尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

从LCP到代码分割:前端首屏加载优化实战指南

发布时间:2026/9/28 22:41:36

资讯中心
01
ARTICLE

从LCP到代码分割:前端首屏加载优化实战指南

从LCP到代码分割:前端首屏加载优化实战指南
有人反馈过“你们首页看起来挺高级但每次进来都要转好几圈是不是服务器不行”。我没查服务器先打开控制台看了看网络瀑布图一个首屏就有十几个请求其中光JS文件就好几个MB首屏图片还没有尺寸约束。这种问题其实跟服务器关系不大更像是前端资源策略没做好。首屏提速这件事本质上不是把网站做得“快”那么玄而是让用户第一眼看到的关键内容以最短的时间出现在屏幕上。这篇文章我会从性能指标、资源加载、渲染链路、移动端工程化和真实排查手段这几个方向把首屏提速这件事拆开讲透希望不管是做后端的同学、刚转前端的新人还是已经在写业务但没系统优化过的朋友都能有可参考的思路。1. 先弄清楚首屏到底卡在哪核心指标与优化思路1.1 别再拍脑袋LCP和FCP才是首屏的尺子首屏提速之前得先回答一个问题什么样的状态算“首屏完成”如果只是打开页面能看到背景色那其实没有任何意义。业界常用两个指标来度量首屏体验FCPFirst Contentful Paint首次内容绘制和LCPLargest Contentful Paint最大内容绘制。FCP 表示页面第一次绘制出文本、图片或画布等内容的时间LCP 表示页面视口内最大元素通常是首屏大图、标题、视频封面渲染完成的时间。用生活类比的话FCP像是门刚开了一条缝你能看到屋里有点光LCP才是客厅沙发、电视这些关键家具都摆到你面前了。很多团队只盯着“页面加载耗时”或者“DOMContentLoaded”这两个数字一个偏差太大、一个与实际渲染感知脱节。真正决定用户觉得快不快的是 LCP尤其是移动端页面影响LCP的通常是首屏图片、标题文本、Hero 区域。如果首屏是一张3MB的轮播图那就算你的JS全部压缩到极致LCP也不会好看。所以优化的第一步就是跑一次 Lighthouse 或 PageSpeed Insights把 FCP、LCP、TTITime to Interactive、TBTTotal Blocking Time这几项记下来再结合浏览器 Performance 面板看瓶颈。没有这些数据后面所有优化动作都像是在黑屋子里修灯泡。1.2 首屏提速的三条主线网络、渲染、调度首屏耗时主要由三部分构成资源传输时间、浏览器解析执行时间、关键资源被阻塞的时间。对应到优化动作也就有三条主线。第一条是缩短网络传输包括资源体积压缩、HTTP缓存、CDN分发、减少请求次数。第二条是减少渲染工作量包括降低 DOM 复杂度、精简主线程任务、减少不必要的组件渲染。第三条是调度优先级让首屏关键资源更快到达让非关键资源往后排比如 preload 关键字体、延迟加载首屏以外的图片、把第三方脚本放到最后。这三条线不是互相独立它们往往会相互影响。举个例子你压缩了JS体积但如果没有调整加载顺序主线程照样被一个巨型脚本占住你做了图片懒加载却把首屏图片也懒加载了反而拖慢LCP。所以做优化前先把这个优先级框架放在脑子里先解决传输再解决渲染最后做精细调度。2. 资源加载层的提速压缩、拆包与调度2.1 把1MB的JS砍到100KB压缩与代码分割首屏最常见的问题就是“一个JS包打天下”。很多老项目用 Webpack 打包后所有业务代码、第三方依赖全部塞进一个 bundle体积动辄 1MB 甚至更高。浏览器要先把这个文件下载完、解析完、执行完才能开始渲染页面首屏自然被拖住。压缩的第一步其实是启用产物压缩工具Webpack 的 TerserWebpackPlugin、Vite 内置的 esbuild 都会做 JS 压缩这一步能去掉注释、空格和未使用代码。但压缩比率毕竟有限真正的关键还是要做代码分割。现代构建工具默认支持按路由拆包比如 Vite 里直接使用动态import()构建后会自动给每个路由生成单独的 chunk。实际项目中我见过很多组件库被整体引入比如只用了 Table 组件却把整套 Ant Design 或者 Element Plus 全部打进去光这一项就能多出几百 KB。组件库现在基本都有unplugin-vue-components或者 babel-plugin-import 这类按需引入方案可以按组件粒度载入。还有一个需要注意的点是千万不要把 lodash、moment 这类强占体积的依赖直接挂在全局 bundle 里优先用 lodash-es、dayjs 这类支持 tree shaking 的生态替代品。我在一个实际项目里做过一次改造原先首屏 JS 资源体积约 1.2MB代码分割后按路由拆成多个 chunk同时把所有第三方 UI 库改为按需引入体积下降到 320KB。首屏加载时间直接少了将近 1 秒。这件事投入不大就是把构建配置和入口代码重新理一遍性价比很高。2.2 HTTP缓存与CDN让老用户秒开让新用户首屏快是本事让老用户回访秒开更是基础。HTTP 缓存是大多数团队都做了但经常做错的一个环节。常见的错误有三种第一种是给 HTML 设置了长时间强缓存结果上线后用户刷新也看不到新版第二种是所有静态资源都设置no-cache导致每次访问都重新下载第三种是资源引入没有带版本指纹缓存形同虚设。正确的做法是HTML 文件始终Cache-Control: no-cache意思是允许缓存但必须回源校验这样后端发布新版本后用户能尽快拿到最新 HTML。而带 hash 指纹的静态资源JS/CSS/图片可以设置Cache-Control: max-age31536000, immutable因为文件名一变就是新文件完全不需要重新验证。Nginx 里常见配置是这样的location /dist/ { add_header Cache-Control public, max-age31536000, immutable; } location / { add_header Cache-Control no-cache; }CDN 也是首屏提速的重要一环。国内访问境外源站时握手和时间延迟都很高把静态资源放到 CDN 节点后用户可以从最近的边缘节点拉取文件。这里有个细节CDN 缓存模式最好也遵循 HTML 不缓存、带指纹资源长缓存的原则否则会出现发布后用户拿到旧 HTML 却引用新 hash JS导致资源 404 的情况。配置 CDN 回源时同时开启 Gzip/Brotli 压缩。Brotli 的压缩率通常比 Gzip 再高 15% 到 25%现代浏览器都支持如果 CDN 支持就优先开启。2.3 preload、prefetch、dns-prefetch 的调度策略传输层优化做到位之后还可以通过资源调度让浏览器提前知道哪些资源“重要”。很多前端同学对这三个标签的关系一直拎不清我简单总结一下preload是告诉浏览器这个资源当前页面马上要用请尽快下载prefetch是告诉浏览器这个资源未来可能要用闲的时候再下载dns-prefetch是提前做域名解析省下 DNS 查询时间。preconnect比 dns-prefetch 更进一步还会提前建立 TCP 连接和 TLS 握手。实际使用中最实用的是给首屏字体加preload。字体文件通常隐藏在 CSS 深处浏览器要等渲染到对应 DOM 时才发请求这样就会出现文字先不可见、字体加载完突然闪变的情况。用下面的标签可以让字体下载尽早开始link relpreload href/fonts/Inter.woff2 asfont typefont/woff2 crossorigin对首屏大图也可以 preload前提是你确认这个图是 LCP 元素。相比之下prefetch更适合用在用户大概率会点击的“下一个页面”上但要注意别过度使用如果首屏还没加载完就去 prefetch 一堆无用资源反而会占用带宽和网络队列。dns-prefetch和preconnect则用在第三方域名的资源上比如 CDN、字体服务、图表服务等直接写在 HTML head 里就行。3. 渲染链路与关键资源优化让浏览器更早画出来3.1 阻塞渲染的CSS和JSCritical CSS与async/defer网络层的资源变小变快了但如果浏览器渲染流水线被阻塞同样白搭。先说 CSSCSS 默认是渲染阻塞资源因为浏览器需要完整的 CSSOM 才能构建渲染树。一个首屏页面如果外链了三四个大样式文件全部下载解析完之前浏览器什么都画不出来。对于首屏必须用到的样式业内建议是内联成“关键CSS”Critical CSS也就是把首屏节点最需要的几十到几百字节样式直接写到style里剩下的非关键样式再异步加载。现在有很多工具能自动提取关键 CSS比如critical、purgecss也可以用构建插件处理。关于 JS浏览器遇到普通script标签会阻塞后续 DOM 解析直到脚本下载并执行完毕。这也就是为什么大家反复强调把非关键脚本改成async或defer。defer让脚本在 HTML 解析完成后、DOMContentLoaded事件之前按顺序执行适合业务脚本async适合独立的第三方脚本下载完成后立即执行不保证顺序。首屏场景下默认做法是自己的应用入口 JS 用defer所有广告、埋点、客服组件脚本用async同时尽量让它们从 HTML 中后置或者动态加载。我遇到过一种很隐蔽的阻塞字体加载。font-display: swap没设置时浏览器会等待字体下载完成才显示文字最长能达到 3 秒。白屏期间用户甚至看不到任何标题LCP 直接被拉爆。后来统一加了font-display: swap并且在font-face里声明好 woff2 子集格式文字渲染速度提升很明显。这个点值得写进你的 CSS 规范里。3.2 图片是首屏大头响应式图片与懒加载很多首屏“重”其实是图片造成的。图片体积占比大又直接影响 LCP。优化图片有几条硬规则第一按需输出尺寸不要在 750px 宽的容器里放一张原始 5000px 的美术图第二使用新格式WebP 和 AVIF 在同等视觉质量下比 JPEG 小很多第三首屏图不要懒加载非首屏图才需要懒加载。响应式图片可以用srcset和sizes实现让浏览器根据当前视口宽度选择合适的图片。示例img srcsetimage-480.jpg 480w, image-800.jpg 800w, image-1200.jpg 1200w sizes(max-width: 600px) 480px, 800px srcimage-800.jpg alt首屏主图 fetchpriorityhigh 上面还用了fetchpriorityhigh这是现代浏览器提升图片加载优先级的手段对 LCP 很有帮助。对应地非首屏图片直接加loadinglazy即可浏览器会自动延后加载完全不依赖 JS 库。很多项目还在用 IntersectionObserver 手写懒加载现在其实没必要了原生属性更简单、性能更好。背景图和img要区分处理背景图无法继承原生懒加载需要通过image-set或者动态判断视口再加背景。首屏图千万不要懒加载这是我一直强调的把首屏图 lazy 化等于告诉所有浏览器“这张最关键的图晚点再给我”LCP 必然被拖垮。3.3 组件渲染粒度和虚拟列表减少首屏绘制的Overhead资源加载速度上去了还要看页面结构复杂度。首屏如果一次性渲染了几百个组件主线程会被压得喘不过气即使资源体积很小交互时间也会很晚。React 项目里常见的问题是父组件每次状态更新子组件全部跟着重渲染Vue 项目里常见的问题是computed被滥用、模板里写大量方法调用导致缓存失效。组件层优化不是为了优化“点击按钮后的响应”而是减少渲染任务挤占首屏关键帧的时间。React 里可以用React.memo、useMemo、useCallback控制渲染粒度Vue 里可以用computed缓存派生数据用v-once标记完全静态的区块。我见过一个比较极致的页面首屏是一个表格加一堆图表图表用的是重量级库首屏所有图表同时渲染FCP 很久不出现。后来把非首屏位置的图表改成懒加载等用户滚动到该区域再初始化图表实例首屏渲染任务瞬间轻了一半。长列表也是一个重灾区。如果你的首屏内容是几千行的信息流直接用虚拟滚动列表替代一次性渲染比如react-window或 Vue 生态的virtual-list。虽然大部分业务首屏不是长列表但列表如果出现在首屏底部也值得做。记住一个原则首屏只渲染用户最终看到的那个区域其余内容等滚动或交互后再渲染这是“渲染调度”的核心。4. 移动端与工程化场景下的首屏提速实践4.1 弱网下的策略Service Worker、离线包与预连接移动端首屏提速的环境比桌面复杂核心差异是网络不稳定、带宽更低、内存和CPU受限。同样的资源在 Wi-Fi 下 1 秒加载完在 4G/弱网下可能要 5 到 8 秒。所以移动端首先要做的是降低资源的绝对体积在图片质量允许的范围内尽量选择更小的格式比如用 AVIF 替代 PNG 大图。其次要利用 Service Worker 做首屏资源预缓存用户第一次访问后把 JS/CSS 和首屏图片放进缓存后续再访问可以从本地直接读取。这里给出一个简单的 Workbox 配置思路import { precacheAndRoute } from workbox-precaching; // 构建时自动生成的预缓存列表 precacheAndRoute(self.__WB_MANIFEST);Service Worker 虽然不能让你第一次访问变快但能让第二次回访几乎秒开。实战中要注意缓存版本控制每次发布资源路径变了就替换预缓存列表避免旧 SW 继续支配页面。移动端另外要做的是preconnect到核心的 API 域名因为 DNS 查询和 TLS 握手在弱网环境下占比更高。还有超时策略移动端首屏资源请求最好设置一个合理优先级如果统计图中某个请求堵塞了后续资源可以考虑内联小体积关键 CSS而不是继续外链。4.2 架构选型SSR/SSG、Vue3Vite、微前端如何影响首屏很多团队在技术选型时没有考虑首屏性能到了优化阶段才发现架构方向选偏了。传统的纯客户端渲染CSR流程是加载 HTML - 加载 JS - 执行 JS - 渲染页面。这意味着首屏内容必须等 JS 执行完才能出现在网络差的设备上尤其吃亏。如果业务对首屏要求极高可以考虑 SSR服务端渲染或者 SSG静态站点生成。SSR 让服务端直接输出完整 HTML首屏内容随第一次响应到达SSG 更进一步在构建时生成静态页面配合 CDN 可以做到极快的首屏响应。Vue3 Vite 组合在首屏性能上比老 Webpack 项目天然有优势Vite 开发环境用原生 ESM生产环境用 Rollup 做更精准的 tree shaking。但注意Vite 生产构建默认仍然会输出一个较大的入口 chunk还是需要配合路由懒加载和手动拆包配置。微前端是另一个经常被误解的点。微前端能带来团队自治和独立部署但如果设计成“所有子应用资源在主应用加载时全部预拉取”首屏性能一定崩。合理的做法是按需加载子应用入口主应用只保留框架资源和通用依赖子应用在用户访问对应路由时才去拉取自己的 JS 和 CSS。另外多个子应用共享的依赖比如 React、Vue 运行时尽量抽成公共模块并设置长缓存避免重复下载。4.3 骨架屏与首屏进度体验感知提速也是提速首屏提速除了真实性能还要考虑用户的“等待体感”。一个 2 秒内白屏的网页和一个 1.9 秒内显示骨架屏的网页用户会觉得后者更快。骨架屏的思路是在真实内容到达前先用灰色块模拟页面的大致布局让用户知道页面正在加载且结构已经“搭好”。实现方式有几种最简单的是直接用静态 HTML/CSS 在入口页面画骨架复杂一点是根据路由自定义骨架组件或者在构建阶段自动生成。但骨架屏有个边界它不能替代 LCP 优化。如果骨架屏占位元素成了视口内最大元素LCP 会绑定到骨架上真实内容出现时反而可能被判定为 LCP 元素却已经太晚。所以我通常建议骨架屏用在数据请求比较慢中后台页面而不是电商首屏这种以图片和标题为主的内容页。移动端还可以用页面转场动画、局部内容渐进式加载来提升感知。核心思路是让用户始终看到“有内容在变化”而不是静止白屏或转菊花。5. 用Performance面板和数据说话排查实录与避坑5.1 从瀑布图里找异常TTFB、阻塞期、大请求首屏提速到最后必须靠数据验证。打开 Chrome DevTools 的 Performance 面板点击录制后刷新页面会得到一条时间线。我一般先看三个区域网络请求的瀑布图、主线程的脚本执行长任务Long Tasks、以及总耗时占比。网络瀑布图里如果某个请求 TTFB首字节时间特别长说明后端接口或静态服务器响应慢这不是前端压缩能解决的如果某个 JS 下载后紧接着一段很长的黄色任务说明脚本执行时间过长需要拆包或减少 polyfill。如果网络请求本身已经很快但 FCP 仍然晚那大概率是有阻塞渲染的 CSS 或者内联脚本放在 head 里。还有一个很容易被忽略的点多个第三方脚本互相竞争网络优先级。比如埋点脚本用 async 加载但因为先出现在 HTML 里反而把首屏图片的下载排到后面。解决方法是把第三方脚本移到组件内动态加载或者统一放到 body 末尾并且给关键首屏资源设置fetchpriorityhigh。有时候一个小小的加载顺序调整能让 LCP 前进 0.5 秒。5.2 优化前后数据对比参考预算与验收没有预算的性能优化很难坚持下去。我建议团队在项目初期就定一个性能预算比如桌面端 LCP 小于 2.0s移动端 FCP 小于 1.8s首屏总资源体积小于 500KB。每次跑完 Lighthouse 或者 WebPageTest 就把数据记下来用表格对比优化效果。指标优化前优化后主要动作FCP2.8s1.4s内联关键CSS、JS deferLCP3.6s2.0s首屏图preload、图片换WebPTBT620ms180ms代码分割、降低主线程任务首屏JS体积1.2MB320KB按需组件库、按路由拆包这种表格既是给老板看的交付成果也是给下一任开发者的优化基线。页面大屏类场景还要单独关注渲染帧率避免图表和大图影响 FPS。这里提一个和优化相关的细节如果使用了大屏组件库或图表库建议在初始渲染时只显示一个简化的骨架等数据加载完成后再初始化重任务组件否则一打开就是七八个图表同时渲染主线程会直接长时间阻塞。5.3 容易踩的坑清单我踩过的那些“优化”陷阱做首屏优化这几年踩过的坑可以整理成一张避坑清单。第一给带 hash 的资源加 preload。带 hash 的文件在构建后文件名会变如果你在 HTML 里写死了 preload 旧文件名下次发布就会失效或者加载错误文件反而浪费流量。第二全部图片都懒加载。首屏图片懒加载会让 LCP 指标变成一个笑话必须保证 LCP 图在首次渲染时就能被高优先级拉取。第三CDN 把 HTML 也缓存了。这个问题非常隐蔽发布后用户刷新还是旧版排查半天发现是 CDN 配了 10 分钟缓存后来改为 HTML 不过缓存静态资源长缓存。第四关键 CSS 内联得太多。有人为了极致首屏把整个页面的 CSS 都内联了导致 HTML 体积暴增到 200KB解析本身又变成了瓶颈。内联范围应该是首屏真正用到的样式而不是整站全部样式。还有一个容易忽视的点字体文件没做子集化。一个中文字体文件几个 MB 是很常见的事如果直接挂到首屏无论怎么压缩 JS 都没用。用unicode-range加上子集化字体只加载当前页面用到的文字子集是每个中文站点都该做的固定动作。做优化时切记别被某一个指标带偏比如 FCP 做得很好看但 LCP 一直不动说明主要瓶颈在首屏最大图片或标题渲染上这时候应该回头看看图片尺寸和字体加载策略而不是继续压缩 JS。优化的过程有点像削苹果皮要一层一层找最厚的那一层下手而不是拿着菜刀把整个苹果都切掉一半。最后再分享一个我自己的习惯每个优化方案落地后我都会用同样的网络模拟条件比如 DevTools 里的 Slow 4G跑三遍取中位数再对比优化前数据。不要用一次结果来判断因为网络波动会影响判断。首屏提速是个持续迭代的过程只要形成“度量-分析-优化-再度量”的循环就能稳定提升。希望这些从项目和踩坑里沉淀下来的经验能让你在下次被吐槽页面慢的时候知道先看哪里、动哪里。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。