CSS应放在<head>中以尽早构建CSSOM并支持渐进式渲染;避免@import,优先用<link rel="stylesheet">;非关键CSS需条件加载或延迟引入。

因为浏览器必须等 CSSOM 构建完成,才能生成 Render Tree 并开始首次绘制——CSS 放在 <head> 是让这个过程尽可能早启动的最直接方式。
浏览器渲染树构建依赖 CSSOM 完整性
DOM 树可以边解析 HTML 边构建,但 Render Tree 不行。它需要 DOM 节点 + 对应的样式计算结果(即 CSSOM)才能合成。而 CSSOM 的构建是阻塞式的:遇到 <link rel="stylesheet">,浏览器会暂停 DOM 解析(除非加 media="print" 等非关键属性),去下载、解析、计算样式规则。
如果 CSS 放在 <body> 底部:
- DOM 树几乎构建完毕才开始加载 CSS,CSSOM 构建严重滞后
- 浏览器无法生成 Render Tree,也就不会触发首次绘制(
first paint) - 用户看到的是长时间白屏,或先闪出无样式的 DOM 内容(FOUC),再重绘
<link> 在 <head> 能触发并行加载与渐进式渲染
现代浏览器对 <head> 中的 <link rel="stylesheet"> 有特殊优化:它不阻塞 HTML 解析本身(注意:不是不阻塞渲染),而是启动 CSS 下载的同时继续解析后续 HTML。一旦 CSSOM 就绪,已解析的 DOM 片段就能立刻参与渲染。
立即学习“前端免费学习笔记(深入)”;
这种机制支持渐进式渲染:
- 导航栏、logo 等头部内容可先带样式呈现
- 用户感知到“页面正在加载”,而非卡死在白屏
- 实测中,
<head>引入比<body>末尾引入平均减少 300–800ms 首屏时间(视网络与 CSS 体积)
别用 @import 替代 <link>,它会串行阻塞
@import 在 CSS 文件内使用时,会强制串行加载:必须等前一个 CSS 文件下载解析完,才发起下一个请求。放在 <head> 里的 <style>@import url("a.css");</style> 比直接 <link href="a.css"> 多出一个 RTT 延迟,且无法被预加载器识别。
更糟的是,某些旧版浏览器(如 IE9 及更早)对 @import 的处理会让整个 CSSOM 构建推迟到 HTML 解析结束之后。
所以:
- 永远优先用
<link rel="stylesheet">,不要在<style>块里写@import - 如果必须条件加载,用 JS 动态创建
<link>并设media="print"后切换,避免阻塞
真正要注意的不是“放哪”,而是“哪些该放”
把所有 CSS 都塞进 <head> 并不总是最优。关键路径上的 CSS(决定首屏布局和文字样式的部分)必须前置;而用于模态框、折叠菜单、暗色主题切换等非首屏样式,应该延迟加载。
容易被忽略的一点是:<link> 标签本身不区分“关键”与“非关键”,浏览器一律当作渲染阻塞资源处理。所以:
- 用
media属性做条件加载(如media="(min-width: 768px)")可让对应 CSS 不阻塞初始渲染 - 用
rel="preload"+as="style"预加载关键 CSS,再通过 JS 注入,能绕过默认阻塞逻辑 - 服务端渲染场景下,内联关键 CSS(
<style>...)+ 外链剩余部分,是最小化阻塞的组合方案



















