meta charset="UTF-8"必须位于<head>开头、任何非ASCII字符(如<title>、注释、<script>、BOM)之前,否则浏览器扫描前1024字节时会跳过该标签,退回到系统默认编码(Windows为GBK,Linux/macOS为ISO-8859-1)导致乱码。

meta charset 必须写在 <head> 开头、任何非 ASCII 字符(包括 <title>、注释、<script>、BOM)之前,否则大概率失效。仅靠这行标签本身不能保证 UTF-8 正常工作,它只是三要素之一。
为什么 meta charset="UTF-8" 写错位置就失效
浏览器解析 HTML 时,只扫描前 1024 字节来查找 meta charset。一旦遇到以下任意一种情况,就会跳过该标签,退回到系统默认编码(Windows 是 GBK,Linux/macOS 是 ISO-8859-1):
-
<title>标签出现在<meta charset>前面 - 开头有 HTML 注释
<!-- -->或空行 - 文件带 BOM(
EF BB BF),且 BOM 后紧跟非 ASCII 内容(如中文<title>我的页面</title>) -
<script>标签出现在<meta charset>前
典型失效写法:<head><title>我的页面</title><meta charset="UTF-8"></head> —— <title> 里的中文已超出 ASCII 范围,浏览器在扫描到它时就停止了 charset 查找。
怎么验证 meta charset 是否真正生效
不能只看源码里有没有那行。需同时检查三项是否一致:
立即学习“前端免费学习笔记(深入)”;
- 浏览器 DevTools → Network → HTML 请求 → Response Headers 中
Content-Type的charset值(如text/html; charset=UTF-8) - 文件实际编码:VS Code 右下角状态栏显示的编码格式;或用命令行确认:
file -i index.html(macOS/Linux)、Get-Content index.html -Encoding Byte | Select -First 3(PowerShell,输出239, 187, 191表示有 BOM) - 运行时 JS 检查:
document.characterSet和document.inputEncoding返回值是否都为"UTF-8"
注意:file:// 协议下 HTTP 响应头为空,此时完全依赖 meta charset 和文件编码,但 BOM + 非 ASCII 开头极易导致 fallback,务必避免。
HTTP 响应头比 meta charset 优先级更高
RFC 7231 明确规定:如果 HTTP Content-Type 响应头中指定了 charset,浏览器会无视 HTML 中所有 meta charset 设置。例如:
Content-Type: text/html; charset=GBK
即使 HTML 里写了 <meta charset="UTF-8">,Chrome/Firefox 仍按 GBK 解析,必然乱码。
常见配置方式:
- Nginx:
charset utf-8;(写在server或location块内,注意是小写utf-8,不是UTF-8) - Apache:
AddDefaultCharset UTF-8(写在.htaccess或虚拟主机配置中) - Express:
res.set('Content-Type', 'text/html; charset=UTF-8')(必须在res.send()前调用)
若服务端未配置,又无法控制响应头(如静态文件托管),则必须确保文件编码、meta 位置、无干扰字符三者严格一致。
编辑器保存时的 BOM 陷阱
VS Code 默认保存为 “UTF-8”,但这个“UTF-8”不含 BOM;而 Sublime Text / Notepad++ 的 “UTF-8” 选项默认含 BOM。BOM 本身是合法的 UTF-8 前缀(EF BB BF),但它占用了前 3 字节,压缩了浏览器用于查找 meta charset 的 1024 字节空间。
更麻烦的是:VS Code 的 “UTF-8 with BOM” 选项,保存后文件开头是 EF BB BF,紧接着如果跟的是中文 <title>,浏览器在解析到第一个中文字符时就判定超出了纯 ASCII 范围,直接放弃后续扫描 —— meta charset 彻底失效。
建议操作:
- 统一用 “UTF-8 without BOM” 保存 HTML 文件(VS Code 选 “Save with Encoding” → “UTF-8”)
- 若已有 BOM,可用命令清除:
sed -i '1s/^\xef\xbb\xbf//' index.html(Linux/macOS) - 绝对不要手动写
charset=utf8或charset=UTF8—— IANA 注册名是UTF-8,少横线或大小写错误会导致部分 WebView 忽略
真正起作用的永远是三者对齐:文件磁盘编码 = HTTP 响应头 charset = <meta charset> 值,且 meta 出现在可被扫描到的位置。缺一不可,顺序和细节决定成败。



















