必须位于内最开头且无任何前置字符,否则浏览器仅扫描前1024字节,遇bom、空格或注释即跳过该声明,退用系统默认编码(如gbk)导致中文乱码。

<meta charset="UTF-8"> 必须存在、必须在 最开头、且文件本身必须是 UTF-8(无 BOM)编码——三者缺一,中文就大概率乱码。
为什么 <meta charset="UTF-8"> 放错位置会失效
浏览器只扫描 HTML 前 1024 字节找 charset 声明,一旦前面有 BOM、空格、换行、HTML 注释或不可见 Unicode 字符,就会跳过它,退回到系统默认编码(Windows 是 GBK,Linux/macOS 默认可能是 ISO-8859-1)去解码,结果就是一堆 或乱码字。
- 检查方式:用 VS Code 打开文件,右下角看编码显示;若为
UTF-8 with BOM或GBK,立刻改 - 正确位置:必须是
内第一个非空白、非注释的标签,紧贴开始后写,前面不能有任何字符 - 禁止写法:
<meta charset="utf8">、<meta charset="UTF8">、<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">(后者在 HTML5 中已不推荐,且易被忽略)
VS Code 保存为真正 UTF-8(无 BOM)的操作细节
VS Code 默认在 Windows 上可能悄悄加 BOM,而 BOM 会卡在 <meta charset> 前面,导致声明直接失效。这不是 bug,是编辑器行为惯性。
- 点击右下角编码标识(如显示
UTF-8 with BOM或GBK)→ 选Save with Encoding→ 严格选UTF-8(不是UTF-8 with BOM) - 保存后重新打开文件,右下角应显示纯
UTF-8,且状态栏无 “with BOM” 提示 - 验证命令(Linux/macOS):
head -c 4 index.html | xxd,输出不含ef bb bf才算干净;Windows 可用 PowerShell:Get-Content index.html -Encoding Byte | Select -First 3
HTTP 响应头里的 Content-Type 优先级高于 <meta>
本地双击打开(file:// 协议)时,没有 HTTP 头,只靠 <meta>;但只要走 Web 服务器(http:// 或 https://),响应头里的 Content-Type 就拥有最高解释权——哪怕你 <meta> 写得再对,头里是 charset=gbk 或压根没 charset,照样乱码。
- 排查方法:F12 → Network → 刷新 → 点主 HTML 请求 → Headers → Response Headers → 查
Content-Type - Nginx 配置示例:
add_header Content-Type "text/html; charset=utf-8";(注意别和已有头冲突) - Node.js/Express 示例:
res.set("Content-Type", "text/html; charset=utf-8");,必须在res.send()前调用 - PHP 示例:
header("Content-Type: text/html; charset=utf-8");,必须在任何输出(包括空格、BOM)之前调用
CSS 和 JS 文件也得是 UTF-8(无 BOM)
HTML 本身没问题,但引用的 <script src="app.js"></script> 或 <link rel="stylesheet" href="style.css"> 如果是 GBK 编码保存,浏览器仍会按 HTML 声明的 UTF-8 去解码它们,结果 JS 报语法错误、CSS 中文注释变乱码、甚至样式崩掉。
- CSS 文件开头可加
@charset "UTF-8";,但仅限第一行、前面不能有任何字符(含 BOM) - JS 文件无需声明,但必须确保文件实际编码是 UTF-8(无 BOM),否则中文字符串、注释都会出问题
- Webpack/Vite 默认读取 UTF-8,但如果源文件是 GBK,loader 不配
encoding就会原样吞进去,最终打包出错
最常被忽略的是:BOM 不可见、HTTP 头看不见、外部资源编码独立于 HTML——这三个点串起来,才是真实乱码现场的完整链条。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











