关键渲染路径卡在阻塞资源处,首屏即停;优化核心是减少阻塞资源、缩短依赖链、让首屏样式结构立即参与绘制。

关键渲染路径(CRP)卡在哪儿,首屏就停在哪儿。优化不是堆工具,而是控制浏览器解析 HTML 时「先看到什么、先加载什么、先执行什么」——核心就三点:减少阻塞资源、缩短依赖链、让首屏样式和结构能立刻参与绘制。
怎么识别哪些资源在阻塞首屏渲染
打开 Chrome DevTools → Performance 面板 → 录制一次页面加载,重点看 Parse HTML 后是否被 Recalculate Style 或 Layout 长时间挂起;再切到 Network 面板,筛选 css 和 js,看 Initiated by 列是不是 parser:如果是,说明这个资源是在 HTML 解析中途被同步拉取的,大概率是关键阻塞点。
常见错误现象:
-
FCP > 3s但DOMContentLoaded已在 800ms 触发——说明 DOM 构建快,但 CSSOM 或 JS 执行拖住了渲染树生成 - 首屏文字闪一下才出现,或按钮先无样式再突然变色——典型因外部 CSS 延迟导致的 FOUC(Flash of Unstyled Content)
内联关键 CSS 为什么必须做,且不能超 1KB
浏览器遇到 <link rel="stylesheet"> 就会暂停 HTML 解析,等 CSS 下载+解析完才继续。而内联进 <style> 的 CSS 不触发网络请求,DOM 和 CSSOM 可并行构建,直接缩短 CRP。
立即学习“前端免费学习笔记(深入)”;
但内联体积过大反而有害:
- 超过 ~1KB 会显著增加 HTML 主文档体积,尤其在弱网下,反而拖慢首字节到达(TTFB)和初始解析
- 服务端无法缓存内联样式,每次 HTML 更新都得重新传输全部样式
- 构建时需用工具(如
critters或purgecss+html-webpack-plugin)自动提取首屏用到的选择器,别手写
示例:登录页只需内联 .logo、.login-form、.submit-btn 的基础尺寸与颜色,其他主题、动画、响应式断点全扔外部文件。
script 标签放哪儿、加什么属性才不打断解析
默认 <script src="app.js"></script> 是同步阻塞的:HTML 解析停 → 下载 JS → 执行 JS → 继续解析。用户看到白屏。
按用途选加载策略:
- 业务逻辑脚本(如 Vue/React 初始化、API 请求)→ 必须用
defer:下载异步,执行时机在 DOM 解析完成后、DOMContentLoaded前,且保持顺序 - 统计类脚本(如
analytics.js)→ 可用async:下载完立刻执行,但可能早于 DOM 就绪,需自行加document.readyState判断 - 兜底方案是把
<script>放在</body>前:至少 DOM 已构建完,但不如defer可控,且无法保证执行顺序
绝对禁用 document.write():现代浏览器已废弃,执行即清空当前文档流,不可恢复。
预渲染适合哪些页面,哪些情况反而更慢
预渲染本质是构建时用无头浏览器跑一遍前端逻辑,输出完整 HTML 字符串。它只对静态或低频更新页面有效,比如官网首页、帮助中心、产品介绍页。
但以下场景用了反而更糟:
- 页面依赖实时登录态、用户偏好或地理位置——预渲染产出的是“通用模板”,用户看到的是别人的数据或未登录状态
- 内容每小时更新(如新闻列表、活动倒计时)——预渲染产物很快过期,还得配 CDN 缓存刷新逻辑
- 需要客户端水合(hydration)但 JS 加载失败或执行出错——页面变成纯静态,交互完全失效
Vue CLI 项目可用 prerender-spa-plugin,但注意:404 on /static/js/xxx.js 多因 public 资源路径未映射到 dist 目录;Cannot read property 'mount' of undefined 常因 Vue 实例在 DOM 就绪前就初始化了,需加 document.readyState === 'complete' 判断或改用 app.mount('#app')(Vue 3)。
真正难的不是知道该做什么,而是判断「哪些算首屏」「哪些算关键」——这没法靠工具全自动,得结合 LCP 元素、用户点击热区、转化漏斗起点来人工圈定。一个按钮是否关键,不取决于它多大,而取决于用户进来第一眼会不会点它。



















