<meta charset>必须是<head>第一个可执行标签,否则触发重解析拖慢FP/FCP;<link rel="preload">须在对应资源标签前生效;CSS和JS顺序决定渲染阻塞点;fetchpriority与loading="lazy"混用会抵消优先级。

HTML <head> 里标签的顺序不是“写对就行”,而是直接影响 FP、FCP、LCP 的硬性开关——错一个位置,LCP 可能晚 400ms,FCP 可能卡在 CSS 阻塞上不动。
为什么 <meta charset> 必须是 <head> 第一个可执行标签
浏览器解析 HTML 时,如果没在前 1024 字节内确定编码,会触发重解析(reparse):丢弃已建的 DOM 树、清空已下载资源、重新开始解析。这直接拖慢 FP 和 FCP 起点。
-
<meta charset="utf-8">必须出现在<title>之前,且不能被注释或 JS 动态插入 - 若用了
<meta http-equiv="Content-Type">,它不生效——只认charset属性写法 - Next.js / Nuxt 等框架生成的 HTML 若在
<title>后才写charset,DevTools 的 Network → Timing 里能看到明显的 “reparse” 时间断层
<link rel="preload"> 放错位置等于没写
浏览器只在初始 HTML 解析阶段读取 <link rel="preload">,且仅当它出现在对应资源标签之前才生效。放错位置会导致重复请求、优先级错乱或完全忽略。
- 必须放在
<meta charset>和<title>之后、<link rel="stylesheet">或<script>之前 - 比如关键字体要提前加载:
<link rel="preload" href="font.woff2" as="font" crossorigin>,但如果它写在<link rel="stylesheet" href="main.css">后面,浏览器可能已开始下载 CSS,preload 就被跳过 - Chrome DevTools Network 面板中,生效的 preload 显示为
Priority: high;若显示medium或没出现,大概率是位置或as值错了 - 用构建工具自动生成 preload 时,务必检查最终 HTML 输出顺序——Webpack 插件或 Vite 插件常把 preload 插到
<body>开头,完全无效
<link rel="stylesheet"> 和 <script> 的相对顺序决定 FCP 卡点
CSS 是渲染阻塞资源,<link rel="stylesheet"> 的位置决定了浏览器何时能推进到 FCP。而脚本的位置则可能让整个渲染流水线停在 FP 阶段。
立即学习“前端免费学习笔记(深入)”;
- 关键 CSS 必须前置,但不要塞进
<style>内联——超过 15KB 的内联 CSS 会让 HTML 解析变慢,反而延迟FP -
<script src="vendor.js">如果没加defer或async,哪怕只有 2KB,也会同步阻塞 HTML 解析,FCP直接延后到 JS 下载+执行完 - 非关键脚本(如统计、错误监控)必须加
defer:保证执行顺序,又不打断 HTML 流式解析 - 纯交互逻辑(如按钮点击绑定)可用
async,但注意它不保序,且可能在DOMContentLoaded前运行——若此时操作 DOM,报Cannot read property 'addEventListener' of null
fetchpriority 和 loading="lazy" 在头部结构中的冲突风险
fetchpriority="high" 是显式提升资源优先级的信号,但它只对实际参与首屏渲染的资源有效;而 loading="lazy" 是告诉浏览器“这个资源不用急”,两者混用会互相抵消。
-
<img src="hero.jpg" fetchpriority="high">有效,但加上loading="lazy"后,Chrome 会忽略fetchpriority,降级为低优先级 - 预加载图片时,
<link rel="preload" href="hero.jpg" as="image" fetchpriority="high">才是正解;<img>标签本身只需保留fetchpriority="high",去掉loading - Safari 不支持
fetchpriority(截至 2026 年 4 月),所以对关键资源还需配合<link rel="preconnect">和 DNS 预解析兜底 - 服务端渲染(SSR)输出的 HTML 中,若同时存在服务端注入的 preload 和客户端 hydration 时动态插入的同名资源,可能触发双下载——需在构建时统一管控 preload 注入点
真正难的不是记住规则,而是判断哪个资源该高优、哪个该延迟、哪个根本不该出现在首屏 HTML 里。比如一个被 display: none 的 <iframe>,只要它带 src,就会同步阻塞主页面的 FCP,这种细节在 DevTools 的 Main Thread 火焰图里才看得清。



















