<meta charset="UTF-8">必须紧贴<head>开头,前面不能有BOM、空格、注释或任何字符,否则浏览器仅扫描前1024字节即失效,fallback至系统默认编码(Windows为GBK,Linux/macOS为ISO-8859-1),导致中文静默乱码;HTTP响应头中Content-Type优先级高于meta,但file://协议下仅依赖meta。

meta charset 必须出现在 <head> 的最开头,且前面不能有任何字符(包括 BOM、空格、注释、<script>),否则浏览器只扫描前 1024 字节就中断,直接 fallback 到系统默认编码(Windows 是 GBK,Linux/macOS 是 ISO-8859-1),根本不会报错,但中文会显示成 “” 或乱码——这不是语法错误,而是静默失效。
为什么 meta charset="UTF-8" 放错位置就不生效
浏览器解析 HTML 时,并不等整个文件加载完才确定编码,而是在前 1024 字节内“盲扫” meta charset 标签。一旦遇到以下情况,就会立即放弃查找:
-
EF BB BF(BOM)在文件最开头,把<meta>推到第 4 字节之后 -
<head>前有<!-- 注释 -->或换行/空格 - AI 生成模板自动在
<head>前插入了不可见 Unicode 字符(如 ZERO WIDTH SPACE) - 后端模板引擎(如 Thymeleaf、EJS)在
<head>前动态注入了内容
怎么验证文件是否真为 UTF-8 且无 BOM
别信编辑器右下角的显示,要查真实字节:
- Linux/macOS:
xxd -l 4 index.html—— 若输出含ef bb bf,说明有 BOM;用sed -i '1s/^\xEF\xBB\xBF//' index.html删除 - PowerShell:
Get-Content index.html -Encoding Byte | Select -First 3—— 输出239 187 191即 BOM - VS Code:右下角点击编码 → “Reopen with Encoding” → 选
UTF-8;再点 “Save with Encoding” → 严格选UTF-8(不勾 “with BOM”) - Notepad++:菜单栏 “编码” → “转为 UTF-8 无 BOM 编码”
HTTP 响应头和 meta 谁优先
当页面通过 http:// 或 https:// 加载时,HTTP 响应头中的 Content-Type: text/html; charset=utf-8 优先级高于 meta charset;但用 file:// 双击打开时,响应头完全无效,meta 是唯一救命稻草。
立即学习“前端免费学习笔记(深入)”;
- Nginx 配置要写:
charset utf-8;(注意小写、无等号、分号结尾) - Apache:
AddDefaultCharset UTF-8(大小写敏感,不能写成utf8) - Express.js:
res.set('Content-Type', 'text/html; charset=utf-8'),必须在res.send()或res.sendFile()之前调用 - PHP:
header('Content-Type: text/html; charset=utf-8');,必须在任何输出(包括空格、换行)之前执行
真正容易被忽略的是:即使 meta 和响应头都写了,只要 HTML 文件本身不是 UTF-8 编码(比如用 Notepad 保存成 ANSI),或外部 JS/CSS 文件用了 GBK 编码,依然会触发 JS 解析错误或样式错乱——编码统一是整条链的事,不是单点配置能兜住的。



















