render blocking 实测:26 个首页 285 张样式表,没有一张写了 media=print
render blocking 是样式表的默认行为,而 26 个被优化得最狠的首页没有一个绕开它:285 张外链样式表要么不写 media 要么写 all,几乎每份性能指南都推荐的 media=print 写法出现 0 次。

实测 · 2026-08-27 · 26 个首页 · 285 张样式表 · 一次抓取 · 只看原始 HTML
样本 / 口径:2026-08-15 起一直在用的那 30 个站,2026-08-27 各抓一次,浏览器 UA,不渲染。逐条读出 rel 含 stylesheet 的 <link>,加上所有 rel="preload" as="style" 与内联 <style> 块,记下 media 属性、相对 </head> 的位置、以及内联块的字节数。
render blocking 是样式表的默认行为,而在 26 个被优化得最狠的首页上,没有一个站选择绕开它。285 张外链样式表要么不写 media,要么写 media="all",两者等价。media="print" ——几乎每份性能指南都会推荐的那个延迟加载写法——出现 0 次。倒是有五个站干脆不用外链样式表,把 CSS 全部内联进文档。
怎么测的
每站一次 HTTP 请求,不渲染,不重试。纳入规则跑数前写死:最终状态 200、解压后正文至少 10,000 字节、正文里有 <body。30 个里挂了 4 个 —— www.canva.com 返回 429,stackoverflow.com 与 medium.com 返回 403,www.reddit.com 返回一个 8,393 字节的空壳,剩下 26 个。
在 head 还是在 body,是按解析器自己的状态判的,不是按字节偏移猜的:只有解析器还没遇到 </head> 时读到的那些才算在 head 里。这个区分撑起了整篇,因为 MDN 的 link 参考页 2026-08-27 读到的原文是:「Only link elements in the document's <head> can possibly block rendering. By default, a link element with rel="stylesheet" in the <head> blocks rendering when the browser discovers it during parsing.」
# 数一下自己页面上真正阻塞的那几张
curl -sL --compressed -A 'Mozilla/5.0' https://example.com/ \
| sed -n '1,/<\/head>/p' \
| grep -o '<link[^>]*stylesheet[^>]*>' \
| grep -cv 'media="print"'
这次没测任何一项耗时。没有 timing,没有瀑布图,不渲染。一张走热缓存 CDN 的阻塞样式表几乎不花钱,而这次抓取分不出它和昂贵的那种。
render blocking 的那 228 张:全在 head,没有一个 media 属性给它们放行
285 张外链样式表里,228 张在 head。而这 285 张写的要么什么都没有,要么是 all。
| 数的是什么 | 总数 | 站数 |
|---|---|---|
| 外链样式表 | 285 | 26 里 21 |
— 在 <head> | 228 | 21 |
— 在 <body> | 57 | 4 |
没写 media | 226 | — |
media="all" | 59 | — |
media="print" | 0 | 0 |
blocking="render" | 0 | 0 |
preload as=style | 40 | 5 |
分布很散。中位数是每站四张;纽约时报 69 张,Linear 54 张,GitHub 41 张。另一头,Figma 和 Hacker News 各一张。阻塞这件事上最极端的是 Linear:54 张全在 head,另外还内联了 250,218 个字符的 CSS。
人人推荐的那个写法,26 个站里 0 个在用
对首屏用不到的样式表,标准做法是写 media="print" 加一个 onload,等文件到了再把 media 改回 all。浏览器照样下载,但用低优先级,而且不会为它等。
我们第一遍查出 8 张带 onload 的样式表,全在 slack.com,本篇初稿因此写的是「26 个站里有 1 个延迟加载 CSS」。然后我们回落盘的字节里看了一眼。Slack 那个 handler 是 window._cdn ? _cdn.ok(this, arguments) : null,旁边还有一个 onerror 双胞胎——CDN 的成功回调,从头到尾没碰 media。那 8 张和其他张一样阻塞,真实数字是 0。
这批站要么等 CSS,要么把 CSS 塞进文档。没有一个站走中间那条路。
走第二条路的有五个。它们一张外链样式表都不发,规则全写在 <style> 块里——没有请求,自然谈不上为请求等待。
| 站点 | 内联字符 | 块数 |
|---|---|---|
www.framer.com | 511,770 | 7 |
www.wired.com | 398,543 | 5 |
www.shopify.com | 245,133 | 2 |
www.bbc.com | 88,350 | 3 |
www.wikipedia.org | 60,382 | 3 |
这是一笔交易,不是白赚:那些字节每一次页面加载都跟着 HTML 走一遍,而且没法单独缓存。全样本 155 个内联块共 2,075,948 个字符,每站中位数 13,517。反方向也有五个站一个字符都不内联:nextjs.org、stripe.com、slack.com、supabase.com、news.ycombinator.com。
57 张样式表在 body 里,43 张属于同一个视频播放器
样式表写在 body 里是合法的。MDN 原文:「the stylesheet link type is body-ok, and therefore <link rel="stylesheet"> is permitted in the body.」按同一份文档,它也不在能阻塞渲染的那一类里——只有 head 里的 link 能。
四个站把样式表放在了那儿。纽约时报有 43 张,而且不是散落的:我们从落盘字节里抽查的每一张都属于同一个视频播放器包 betamax,文件名形如 player-0.3.28-gTxBzUvg.css。GitHub 11 张,Webflow 2 张,Railway 1 张。纽约时报的 body 从文档第 202,375 个字符才开始,所以那 43 个请求按定义就是被晚发现的。
那个位置是性能决策还是组件恰好渲染在那里,我们说不清。两种情况产生的标记一模一样,而我们没问过任何人。
这对你意味着什么
值得动手的数字不是 285,是你自己 head 里那几张——每一张都是首屏出现之前的一次网络往返。
- 先数一遍。上面那条命令,结果通常比你担心的少,或者比你以为的多得多
- 确实首屏用不到的那张,写
media="print"加 onload 改回all。这批站 0 个这么做,说明它要么比看起来难,要么比听起来没用 - 别因为五个大站这么干就把整份样式表内联。Framer 那 511,770 个字符每次加载都跟着走,永远进不了浏览器缓存
- 别以为
rel="preload" as="style"能解掉阻塞。它改的是抓取优先级,样式表那条 link 该等还是等
这件事到底值不值得你花一个下午,取决于搜索引擎公开说过什么,我们把它整理成了 core web vitals 值不值得做。同一个 head 里脚本那一半的统计在 async defer 实测 27 个首页,连接层的提示在 27 个首页 650 条资源提示。想看引擎在任何样式生效之前从你的页面拿到了什么,可以 看看 QueryWin 怎么运转。
常见问题
你们是怎么测的?
2026-08-27 每个首页发一次请求,浏览器 UA,正文落盘,link 与 style 元素用 HTML 解析器读一遍并记录 head/body 位置,所有发出来的数字都是从落盘文件重算的。
什么样的样式表才算 render blocking?
在 head 里、解析时被发现、media 与当前设备匹配的 <link rel="stylesheet">。MDN 把它写成默认行为,并补了一句:脚本后来插进去的 link 得显式写 blocking="render" 才会阻塞。
media="print" 真能解掉阻塞吗?
它解掉的是等待,不是下载。浏览器会用较低优先级把文件取回来,中间不为它停,onload 再把 media 值改过来让规则生效。本样本没有一个站在用,所以我们有 26 个数据点和 0 个可参照的实例。
内联 CSS 比外链好吗?
首次访问的首屏,好,因为少一次请求。之后的每一次访问,不好,因为那些字节没法单独缓存,每次都跟着 HTML 再来一遍。这批站里五个选了前一种取舍,另外五个选了完全相反的。
body 里的样式表会拖慢什么吗?
按 MDN 给的定义不会,因为只有 head 里的 link 能阻塞渲染。它们仍然是 57 个在文档很靠后才被发现的请求,而本样本里 43 个属于同一个视频播放器。


