同步脚本一放就卡首屏,因浏览器解析html时遇无defer/async的script会立即暂停dom构建,下载执行js,导致body内容无法生成而白屏;内联脚本同样阻塞,且若置于link rel="stylesheet"前还会拖住cssom构建;验证看network面板initiator是否为parser。

同步<script>为什么一放<head>就卡住首屏</script>
因为浏览器解析HTML时,遇到没加defer或async的<script src="xxx"></script>,会立刻暂停DOM构建,去下载、解析、执行JS——此时哪怕只是个1KB的统计脚本,body里的标题、导航栏、轮播图都还没生成节点,用户只能看白屏。
- 内联脚本(如
<script>window.data = {...}</script>)同样阻塞,除非它不操作DOM或CSSOM -
里放<link rel="stylesheet">再前面放同步<script></script>,会导致CSSOM构建被拖住:JS执行完前,浏览器连CSS文件都不敢开始下载 - 验证方法:打开Chrome DevTools → Network → 切到“Waterfall”,找
parser在Initiator列,如果JS或CSS的Initiator是它,说明正被HTML解析器同步拉取
如何让<script>真正不阻塞HTML解析</script>
不是“挪到前”就万事大吉,关键看执行时机是否与DOM就绪对齐。用错属性,JS仍可能查不到元素或样式未生效。
-
defer:下载异步,执行排队——等DOM解析完、DOMContentLoaded前按顺序执行;适合初始化Vue/React根实例、操作DOM的逻辑 -
async:下载异步,下载完立刻执行——不保证顺序,也不等DOM;只适合完全独立的脚本,比如analytics.js、chat-widget.js - 绝对避免:
<script src="app.js"></script>裸写在,尤其别放在<link rel="stylesheet">之前 - 小技巧:内联配置脚本可保留在
,但必须用document.currentScript或包装成IIFE,且不调用document.querySelector('body')这类依赖完整DOM的API
关键CSS内联与非关键CSS异步加载的实操边界
“把CSS全内联”是常见误解。内联体积过大反而拖慢TTFB和HTML解析;而“用preload + onload”若漏掉<noscript></noscript>回退,无JS环境直接丢失样式。
- 关键CSS范围:仅限首屏viewport内渲染必需的规则,比如
.header、.hero、.card-title的字体、颜色、间距;不含分页、评论、侧边栏 - 体积控制:gzip后建议≤14KB,超过后HTTP/2多路复用优势显现,外链更优
- 非关键CSS加载写法必须带回退:
<link rel="preload" as="style" href="non-critical.css" onload="this.rel='stylesheet'"> <noscript><link rel="stylesheet" href="non-critical.css"></noscript> - 禁用
@import:它在CSS文件内部触发串行请求,比<link>多一层阻塞,DevTools里能看到明显瀑布延迟
DOM结构本身也是渲染瓶颈,怎么简化才有效
嵌套过深的<div class="container"><div class="row"><div class="col">不是语义问题,是解析开销问题——每个标签都是一个Node对象,都要走词法分析、语法树构建、内存分配。
<ul><li>删除纯布局类容器:用CSS Grid/Flex替代<code><div class="row"><div class="col">,直接作用于语义化元素上
<li>避免深层嵌套:DOM深度>20层时,Chrome主线程解析耗时明显上升;可用<code>document.querySelectorAll('*').length粗略估算节点总数
<article></article>
:hover)、媒体查询命中项(如@media (max-width: 768px)),上线前务必在设备模拟器中禁用网络,手动检查标题、按钮、主图是否真能渲染出来。











