内联关键CSS是防闪底线,必须用<style>标签置于<head>最顶部、体积≤10KB(gzip前)、禁用media属性;否则首屏必FOUC。需用critters或critical自动生成,并配合preload+onload加载非关键CSS,同时验证Content-Type与字体预加载。

内联关键CSS是防闪底线,不是可选项
不内联关键CSS,其他所有预加载手段都只是补救。浏览器在首次绘制前必须拿到首屏必需的样式规则(如 .header、.hero、基础字体定义、CSS变量),否则必然FOUC——这不是加载慢,而是根本没参与渲染流程。
内联必须满足三个硬条件:
• 用 <style> 标签写在 <head> 最顶部,早于任何 <script> 或 <link>
• 体积 ≤10KB(gzip 前),否则会反向阻塞 HTML 解析
• 不能带 media 属性(比如 media="(min-width:768px)"),否则浏览器直接跳过阻塞逻辑
别手动维护。用 critters(Vite 插件)或 critical(CLI 工具)自动生成,否则上线后样式一改,内联块就失效。
preload + onload 是非关键CSS的安全加载姿势
内联只管首帧,后续样式还得加载。但直接放 <link rel="stylesheet"> 可能因体积大或 CDN 延迟引发回流重绘。正确做法是让它“下载但不应用”,等就绪再切换:
立即学习“前端免费学习笔记(深入)”;
-
<link rel="preload" as="style" href="non-critical.css" onload="this.rel='stylesheet'">—— 注意onload必须在 DOM 插入前绑定,Safari 对时序敏感 - 更兼容写法:
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">—— 利用media="print"让浏览器预加载但不解析,加载完成再激活 - 必须配
<noscript><link rel="stylesheet" href="non-critical.css"></noscript>,JS 失效时兜底
漏掉 as="style",浏览器当普通资源处理;漏掉 onload,样式永远不会生效。
验证关键CSS是否真起作用,别靠猜
Coverage 面板是唯一可信依据。打开 Chrome DevTools → Coverage → 刷新页面 → 查看哪些 CSS 规则被实际执行(绿色高亮)。重点关注:
- 伪类如
:hover、:focus-visible通常不该内联,它们在交互后才触发 -
@font-face声明:如果字体只用于折叠区域或懒加载模块,就该移出内联块 - CSS 变量(
:root { --color-primary: #333; }):只在非首屏用到的,不进内联 - 带
@import的文件:Coverage 不追踪导入链,需单独分析被导入文件
工具导出的“关键CSS”只是起点,得结合 Coverage 报告人工裁剪,否则容易把非首屏规则也塞进去。
最容易被忽略的两个底层细节
一是服务端返回的 Content-Type。哪怕你把 CSS 内联了,如果外链 CSS 返回的是 text/plain 而非 text/css,浏览器会拒绝解析,降级为异步加载——FOUC照常发生。
二是字体和图片资源没同步 preload。critical CSS 里用了 font-family: 'Custom',但没配 <link rel="preload" as="font" crossorigin href="custom.woff2">,浏览器仍要等字体下载完才敢渲染文字,结果就是 FOIT 或 FOUT。
这些点不验证,优化就停在表面:预加载写了,但浏览器根本没按预期执行。


















