<meta charset="UTF-8">必须位于<head>开头1024字节内,且HTML文件实际编码、HTTP响应头Content-Type、外部JS/CSS资源三者均须为UTF-8;任一不一致或位置被BOM/注释/空格/<title>占用,浏览器即回退至GBK或ISO-8859-1导致乱码。

<meta charset="UTF-8"> 必须出现在 <head> 开头 1024 字节内,且文件实际编码、HTTP 响应头、外部资源三者必须全部为 UTF-8 —— 缺一不可。任何一处错位或不一致,浏览器就会 fallback 到 GBK 或 ISO-8859-1,中文立刻变方块或问号。
为什么 <meta charset="UTF-8"> 写了还是乱码
浏览器只在解析 HTML 前 1024 字节时查找该标签;一旦被 BOM、空格、注释或 <title> 等提前占用位置,声明就失效。
-
<head>开头存在 UTF-8 BOM(ef bb bf):用xxd -l 3 filename.html检查,有则删掉重存为 “UTF-8(无 BOM)” - 写了
<!-- 注释 -->或换行空格在<meta charset="UTF-8">之前:必须是<head>后第一个非空白字符 - 用了非标准写法如
<meta charset="utf8">或<meta charset="UTF8">:只有"UTF-8"是 HTML5 标准值 - Thymeleaf/EJS 等模板引擎动态注入内容,把
<meta>推到了第 2 个或更后位置:检查渲染后源码,而非原始模板
如何确认 HTML 文件真实编码格式
编辑器右下角显示的“UTF-8”只是当前打开方式,不代表文件磁盘字节真实编码。必须验证二进制内容。
- VS Code:点击右下角编码 → “Reopen with Encoding” 试选 UTF-8 / GBK / ISO-8859-1,看中文是否正常;再点 “Save with Encoding” → 明确选 “UTF-8”(不含 BOM)
- Linux/macOS:
file -i index.html查声明,head -c 3 index.html | xxd查 BOM - Windows PowerShell:
Get-Content index.html -Encoding Byte | Select -First 3,输出239 187 191即含 BOM - Notepad++:菜单栏“编码”→“转为 UTF-8 编码”(不是 “UTF-8-BOM”)
HTTP 响应头 Content-Type 覆盖 <meta>
服务器返回的 Content-Type: text/html; charset=GBK 会直接无视 HTML 里的 <meta charset>,优先级更高。
立即学习“前端免费学习笔记(深入)”;
- 浏览器 F12 → Network → 刷新 → 找 HTML 请求 → Headers → Response Headers → 查
Content-Type - Nginx:配置中加
charset utf-8;(在 http/server/location 块内) - Apache:.htaccess 中加
AddDefaultCharset UTF-8,禁用AddDefaultCharset GBK - Express:在
res.sendFile()或res.send()前加res.set('Content-Type', 'text/html; charset=utf-8') - Tomcat:server.xml 的
<Connector>加URIEncoding="UTF-8" useBodyEncodingForURI="true"
<script> 和 <link> 引入的 JS/CSS 也得是 UTF-8
即使 HTML 正确,外部 JS 或 CSS 文件本身是 GBK 编码,其中的中文注释、字符串、提示文案仍会乱码,且可能破坏脚本执行。
- 用同上方法检查
app.js、style.css文件的真实编码(file -i/ VS Code 重存) - 避免在 JS 中写
console.log("你好")却保存为 GBK —— 浏览器按 UTF-8 解码字节流,必然错 - Webpack/Vite 构建时若读取了非 UTF-8 源文件,也会继承错误编码,需统一输入编码
- PHP 输出 HTML 时若文件开头有 BOM,
header()会失败,导致 Content-Type 缺失,间接引发乱码
最易被忽略的是:BOM 不仅让 <meta charset> 失效,还会让 PHP 的 header()、Node.js 的 res.writeHead() 报错或静默失败,从而丢失 HTTP 响应头 —— 这时候你查 <meta> 和文件编码都对,却始终乱码。



















