<meta charset="UTF-8">必须位于<head>最开头且前面不能有任何字符(包括BOM、空格、换行、注释),否则浏览器仅扫描前1024字节,遇非ASCII字符即中断识别,回退至系统默认编码(如Windows的GBK)导致乱码。

meta charset 必须出现在 <head> 开头,且前面不能有任何字符(包括 BOM、空格、换行、注释),否则浏览器可能忽略它。
为什么 meta charset="UTF-8" 放在 <head> 开头还失效?
浏览器只扫描 HTML 文件前 1024 字节来查找 meta charset;一旦遇到非空白字符(如 <script>、<style>、<!-- 注释 --> 或 Unicode 零宽空格 U+200B),解析就会中断,fallback 到系统默认编码(Windows 是 GBK,Linux/macOS 常为 ISO-8859-1)。
- VS Code 默认保存为
UTF-8 with BOM,开头三个字节EF BB BF就是 BOM,会导致meta失效 - 用
xxd -l 4 index.html(Linux/macOS)或Get-Content index.html -Encoding Byte | Select -First 3(PowerShell)检查开头三字节是否为239, 187, 191 - 正确做法:Ctrl+Shift+P → “Save with Encoding” → 选
UTF-8(不含 BOM) -
meta charset必须是<head>内第一个子节点,不要在它前面加任何东西,哪怕是一行空行或 HTML 注释
HTTP 响应头和 meta charset 冲突时谁生效?
HTTP Content-Type 响应头优先级高于 meta charset。如果服务器返回 Content-Type: text/html; charset=GBK,即使 HTML 里写了 UTF-8,浏览器也会按 GBK 解析,结果必然乱码。
- Chrome DevTools → Network → 点开 HTML 请求 → Headers → Response Headers → 查看
Content-Type - Nginx 配置需写
charset utf-8;(小写,不能写UTF-8) - Apache 的
.htaccess要写AddDefaultCharset UTF-8 - Express.js 中必须显式设置:
res.set('Content-Type', 'text/html; charset=utf-8')(小写 utf-8) - 本地双击打开(
file://协议)时 HTTP 头完全无效,此时只依赖meta charset和文件实际编码
Live Server 为什么能绕过很多乱码问题?
VS Code 的 Live Server 插件启动的是一个本地 HTTP 服务(如 http://127.0.0.1:5500/),它会自动发送正确的 Content-Type: text/html; charset=utf-8 响应头,并确保文件以真实 UTF-8(无 BOM)读取和传输——这相当于同时补上了响应头和文件编码两个关键环节。
立即学习“前端免费学习笔记(深入)”;
- 不用 Live Server 时,双击 HTML 文件走
file://协议,HTTP 头全失效,纯靠文件编码 +meta,容错率极低 - Live Server 不会修复已损坏的文件:如果 HTML 文件本身是 GBK 编码却写了
UTF-8,照样乱码 - 它不解决后端输出乱码(比如 PHP
echo "中文"前没设 header)或数据库连接乱码 - Thymeleaf、Jinja 等模板引擎需单独配置
templateResolver.setCharacterEncoding("UTF-8"),Live Server 无法代劳
真正容易被忽略的是:文件实际编码、meta 声明、HTTP 响应头、数据源(如数据库连接参数)、模板引擎配置,这五者必须全部对齐为 UTF-8(且不含 BOM)。少一个,就可能在某个环境或某次请求中突然崩掉。



















