R3.05.4render-blocking first paint设计
阻塞渲染的资源决定首次可见的时刻
别名: 渲染阻塞 · render-blocking CSS · 首绘等待 · CSSOM 阻塞
概念解释
浏览器在关键 CSS、同步脚本、以及仍处于阻塞期的字体就绪之前,可以不绘制第一帧。这些资源叫渲染阻塞资源(render-blocking resources)。它们决定的是首次可见的时刻:屏幕何时从空白变成有内容,而不是控件何时能点、主线程何时空闲。看得见和能操作是两件事;这里只管前一件——第一帧被谁拦住。
机制
HTML 解析遇到外部样式表时会构建 CSSOM;没有 CSSOM,引擎不愿画出无样式内容闪烁,于是首绘等待样式。文档中的同步脚本打断解析,脚本跑完之前后续 HTML 进不了 DOM,首绘同样推迟。字体若走阻塞策略,文本节点可以占着布局却不画字形,首屏看起来像缺了字。链路是:阻塞资源 → 推迟第一帧 → 用户仍对着空白或残缺首屏。
这与“内容后到推动已绘节点”不是同一条时间线。阻塞发生在第一帧之前,用户还没有已呈现元素可被推动;偏移发生在第一帧之后。把首绘推迟,有时反而减少偏移,因为更多盒子在第一次绘制时已经齐套——代价是空白更久。优化首绘是缩短阻塞链,不是把阻塞改成绘制后插入。
边界
media 不匹配的样式表、异步/延迟脚本、非阻塞的字体策略,默认不挡住第一帧。HTTP/2 多路复用能缩短传输,但不改变“CSSOM 未完成就不首绘”的规则。服务端渲染出的 HTML 若仍链接一份巨大的阻塞 CSS,首绘照样等这份 CSS。原生应用的视图树没有这套 CSSOM 阻塞模型;它们的首帧受启动和主线程初始化约束,机制不同。离线已缓存的阻塞资源可以把首绘推得很早,现场冷启动则不能用这个时间。
怎么落地
- 把首屏真正用到的 CSS 内联或拆成首屏专用文件,其余样式异步加载;同步脚本移出首屏关键路径。
- 字体用预加载缩短阻塞窗口,但不要用“整包字体下载完再绘”换取所谓的整齐首屏。
- 在瀑布图里标出第一帧之前仍未结束的 CSS、同步 JS 和阻塞字体,逐项改成非阻塞或拆小。
- 验证:节流网络下量第一次有内容的绘制时间;去掉或推迟可疑资源后,首绘应前移,且不要把原阻塞工作改成首绘之后往已绘流里插块。