<meta charset>必须放在<head>开头,否则浏览器已用默认编码(如ISO-8859-1)错误解析了前面的文本(包括<title>、注释等),后续再声明UTF-8也无法挽回,导致中文乱码或控制台报错。

为什么把 <meta charset> 放在 <body> 里会乱码
浏览器解析 HTML 是从上到下流式进行的,<meta charset="utf-8"> 的作用是告诉浏览器“接下来的文本用 UTF-8 解码”。如果它出现在 <body> 里,前面的 HTML 内容(包括 <title> 文本、注释、甚至 DOCTYPE 后的空白)可能已被默认编码(如 ISO-8859-1)错误解码——再改也救不回来。
- 必须放在 <head> 开头,且越靠前越好(最好紧接 <html> 后)
- 不要依赖浏览器“自动修复”,旧版 Safari、某些 WebView 或 SSR 工具会直接忽略
- 常见错误现象:中文标题显示为 ,或控制台报 “Unable to decode” 类似警告
<script> 放在 <head> 还是 <body> 取决于是否操作 DOM
不是位置决定“能不能放”,而是执行时机决定“会不会出错”。
- 如果脚本只做计算、定义函数、加载模块(如 import),放 <head> 没问题
- 如果调用 document.getElementById、querySelector、addEventListener 等操作真实元素,必须确保 DOM 已就绪:
- 推荐:加 defer 属性并留在 <head>
- 替代:放在 </body> 前(即 <body> 最底部)
- 避免:放在 <body> 开头但没 defer,此时 document.body 可能为空,getElementById 返回 null
<link rel="stylesheet"> 为什么不该塞进 <body>
语法上允许,但语义和体验上不推荐。
- 浏览器发现 <link rel="stylesheet"> 会立即发起 CSS 请求,并阻塞后续 HTML 解析(直到 CSSOM 构建完成)
- 如果它在 <body> 底部,HTML 已基本解析完、内容已渲染,但样式还没加载——用户先看到无样式的“白屏闪动”
- 更糟的是,部分浏览器(尤其移动端)可能延迟应用该样式,导致布局跳变或 FOUC(Flash of Unstyled Content)
- 正确做法:统一放在 <head>,必要时用 media="print" 或 onload 回调做懒加载控制
漏写 <head> 或 <body> 标签会怎样
HTML5 允许省略这两个标签,但不等于“可以随意省略”。
- 浏览器会自动补全(如把孤立的 <meta> 插入隐式 <head>),但补全逻辑因引擎而异
- 旧版 Safari、微信内置 WebView、某些 SSR 模板引擎(如 Hugo 的 safeHTML 渲染器)可能直接报错或输出无效文档
- W3C Validator 会标为 “Error: Element head is missing”,影响合规性检查
- 实际开发中:空的 <head> 和 <body> 也要显式写出,这是结构清晰性和工具链兼容性的底线
真正容易被忽略的,是那些“浏览器看似能修好,但修得不一致”的边界情况——比如把 <title> 放在 <body> 开头,Chrome 可能显示标题,Safari 却始终为空。结构不是装饰,是浏览器行为契约的书面约定。



















