外部样式表和<style>标签必须放在<head>中,<script>默认应置于</body>前;必须放<head>的脚本需加defer属性。

外部样式表必须放在 <head> 里
浏览器在解析 HTML 时,遇到 <link rel="stylesheet"> 会立即开始下载并阻塞渲染,直到样式表加载、解析完成。如果把它错放到 <body> 或文档末尾,页面内容会先以无样式状态闪现(FOUC),再突然重绘,体验很差。
常见错误包括:
- 把
<link>放在</body>之后 —— 浏览器可能忽略或延迟加载 - 误以为“顶部”就是
<html>上方 —— 实际上那不属于合法 DOM 范围,会导致解析失败 - 为“避免阻塞”而故意挪到
<body>开头 —— 这不解决阻塞,只推迟阻塞点,且破坏语义
正确写法只有一个:<head><link rel="stylesheet" href="main.css"></head>。即使使用 preload 或 media="print" 等优化手段,也仍需保留在 <head> 内。
<style> 标签也要在 <head> 中
内部样式表不是可选的“补充”,而是与外部样式表同等地位的渲染阻塞资源。放在 <body> 里看似能生效,但存在两个硬伤:
立即学习“前端免费学习笔记(深入)”;
- 浏览器仍需回溯已解析的
<body>元素并重新计算样式,性能更差 - HTML 验证器报错,
<style>在<body>中属于非标准用法,某些严格模式下可能被忽略
特别注意:不要因为“这段样式只用于某个组件”就把它塞进对应 <div> 里 —— 那是内联样式(style 属性)的事,<style> 是全局作用域声明,理应在 <head> 统一管理。
使用 Puppeteer + Chrome 将 HTML 渲染为中文 PDF,自动处理图表等待、Tab 展开、动画、测高、白边消除、防分页,适用于看板、报表、网页和交互图表转 PDF。
<script> 默认应放在 </body> 前
脚本默认是“解析阻塞”的:浏览器一旦遇到 <script>,就会暂停 HTML 解析,下载、执行完才继续。如果它在 <head> 里且没加 async 或 defer,整个页面渲染会被卡住。
最稳妥的位置是紧贴 </body> 标签上方:
<body> <div id="app"></div> <script src="app.js"></script> </body>
这样能保证 DOM 已构建完毕,脚本可直接操作元素,无需监听 DOMContentLoaded。但要注意:
- 这个位置对内联脚本和外部脚本都适用
- 若脚本有
document.write(极不推荐),放这里会出错 —— 它只能在解析阶段用 - 现代构建工具打包的入口脚本,通常已处理好依赖顺序,不必手动调整位置
必须放 <head> 的脚本要加 defer
有些脚本无法挪到 </body> 前,比如第三方统计、Polyfill、字体加载器等。它们需要尽早下载,但又不能阻塞渲染 —— 这时唯一合规解法是加 defer 属性,并保留在 <head>:
<head> <script defer src="polyfill.io/v3/polyfill.min.js"></script> <script defer src="analytics.js"></script> </head>
关键约束:
-
defer只对外部脚本有效,内联脚本加了无效 -
defer脚本按出现顺序执行,且总在 DOM 解析完成后、DOMContentLoaded之前运行 - 别混用
async和defer——async不保证顺序,适合完全独立的脚本(如广告、埋点)
真正容易被忽略的是:哪怕你把 <script> 放在 </body> 和 </html> 之间,HTML 解析器也会自动把它“收编”进 <body> 内部 —— 这看似没区别,但不符合规范,审查工具可能警告,团队协作时也容易引发歧义。


















