首屏白屏时间长主因是HTML解析被同步<link rel="stylesheet">或<script>阻塞;用Chrome DevTools Performance面板看Parse HTML后是否紧接Recalculate Style/Layout,Network面板中Initiator为parser的css/js即关键阻塞源。

首屏白屏时间长,八成是 HTML 解析被某个 <link rel="stylesheet"> 或同步 <script> 卡死了——不是资源没传完,而是浏览器在等它“放行”才敢继续画。
怎么一眼识别哪个资源在阻塞首屏渲染
打开 Chrome DevTools → Performance 面板 → 录制一次完整加载,重点看 Parse HTML 后是否立刻接上长时间的 Recalculate Style 或 Layout;再切到 Network 面板,筛选 css 和 js,检查 Initiator 列:
- 显示为
parser:该资源是在 HTML 解析中途被同步拉取的,属于关键阻塞点 - 显示为
script或other:大概率是异步加载,不拖首屏 - 哪怕 CSS 已下载完成,只要没解析出 CSSOM,
FCP就不会触发
内联关键 CSS 为什么必须做,又为什么不能乱内联
浏览器遇到 <link rel="stylesheet"> 就会暂停 DOM 构建,等 CSS 下载 + 解析完才继续。内联进 <style> 能跳过网络请求,让 DOM 和 CSSOM 并行构建——但前提是只塞「首屏像素生成所需最小集合」:
- 登录页只需
.logo、.login-form、.submit-btn的基础尺寸与颜色,响应式断点、动画、主题色全扔外部文件 - 体积控制在 ~1KB 内:超了会显著拖慢 TTFB(尤其弱网),还可能因 TCP 初始拥塞窗口限制多一个 RTT
- 服务端无法缓存内联样式,每次 HTML 更新都得重传全部内容
- 别手写提取——用
critters或purgecss + html-webpack-plugin自动分析真实首屏用到的选择器
<link rel="preload"> 加了却没加速?可能是用错了地方
<link rel="preload"> 不改变阻塞行为,只提前拉取资源。它生效的前提是「精准命中首屏必用」且「后续真用了」:
立即学习“前端免费学习笔记(深入)”;
- 对首屏 Hero 图或关键字体用:
<link rel="preload" href="hero.jpg" as="image">,注意as属性必须准确,否则浏览器无法设置正确请求头 - 非关键 CSS 可这样异步加载:
<link rel="preload" as="style" href="non-critical.css" onload="this.onload=null;this.rel='stylesheet'"> - 别对
main.js或整个vendor.jspreload——它已被defer覆盖,再 preload 属于冗余调度,反而抢带宽 - 没实际使用预加载资源时,Chrome 会报警告:
"The resource … was preloaded using link preload but not used within a few seconds"
为什么把 <script> 放 </body> 前还不够
放到底部只是兜底方案,治标不治本。同步脚本会暂停 HTML 解析、等待 CSSOM 就绪(因为 JS 可能调用 getComputedStyle),相当于同时拖住 DOM、CSSOM、渲染树三者:
- 业务逻辑 JS 优先用
defer:下载异步,执行时机在 DOM 解析完成后、DOMContentLoaded前,且按顺序执行 - 统计类脚本(如 analytics.js)可用
async:下载完立刻执行,无序,适合无依赖场景 - 绝对禁用
document.write():现代浏览器已废弃,执行即清空文档流,必然阻塞且不可恢复 - 避免在同步脚本里访问
document.styleSheets或getComputedStyle,这会强制触发 CSSOM 构建,放大阻塞
真正卡住首屏的,往往不是体积大,而是位置错——一个没加 defer 的 SDK 脚本,或一段没条件加载的媒体查询 CSS,就能让 FCP 推迟几百毫秒。优化 CRP 的本质,是让浏览器在收到第一个字节后,立刻知道「哪些东西现在就得画,哪些可以往后放」。



















