<meta charset="UTF-8">必须置于<head>最开头(首子元素)、仅出现一次,因浏览器仅解析前1024字节查找charset声明,晚于该范围或被注释/BOM/<title>等阻隔即回退系统默认编码(如GBK/ISO-8859-1),导致中文、emoji及表单内容乱码。

<meta charset="UTF-8"> 必须放在 <head> 的最开头,且只能出现一次;否则中文、emoji、表单提交内容大概率乱码,而且这种问题在本地双击打开时可能“看起来正常”,一上线就崩。
为什么 <meta charset="UTF-8"> 要放在 <head> 最前面
浏览器解析 HTML 是流式的,前 1024 字节内没找到有效的 charset 声明,就会按系统默认编码(Windows 是 GBK,macOS/Linux 是 ISO-8859-1)开始解码。一旦开头几个字节被错解,后续所有内容都会偏移错乱,<title> 里的中文变成方块、“提交”按钮显示为 “ύ” 就是典型表现。
常见错误写法:
-
<head><title>我的页面</title><meta charset="UTF-8"></head>——<title>已先触发解码,meta晚了 -
<head><!-- 注释 --><meta charset="UTF-8"></head>—— 注释不算“空白”,仍算作非空内容,导致跳过 -
<head><meta charset="utf8"></head>—— 拼写错误,“utf8” 不是标准值,部分嵌入式 WebView 会直接忽略
HTML 文件本身也得是 UTF-8(无 BOM)
<meta charset="UTF-8"> 只是告诉浏览器“请用 UTF-8 解”,但如果文件实际保存为 GBK 或带 BOM 的 UTF-8,浏览器读到的字节流仍是错的。
验证和修复方法:
- VS Code:右下角点击编码名称 → 选 “Save with Encoding” → 选 “UTF-8”(**不要选 “UTF-8 with BOM”**)
- macOS/Linux 终端:
head -c 4 index.html | xxd,输出含ef bb bf就有 BOM,用sed -i '1s/^\xef\xbb\xbf//' index.html删掉 - Windows PowerShell:
Get-Content index.html -Encoding Byte | Select -First 3,若前三字节是239, 187, 191,说明有 BOM
HTTP 响应头 Content-Type 不能和 meta 冲突
当服务器返回 HTTP 响应头 Content-Type: text/html; charset=GBK 时,浏览器以响应头为准,<meta charset="UTF-8"> 直接失效——RFC 7231 明确规定响应头优先级高于 meta。
检查方式:
- 浏览器 DevTools → Network → 点开 HTML 请求 → Headers → Response Headers → 查
Content-Type - Nginx 配置中加
charset utf-8;(注意小写,不能写UTF-8) - Apache 中加
AddDefaultCharset UTF-8 - Node.js(如 Express):
res.set('Content-Type', 'text/html; charset=utf-8')
别混用 meta http-equiv 和原生 charset
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 是 HTML4 写法,HTML5 中已废弃。它兼容性差,某些浏览器(尤其是旧版 WebView)识别不稳定,且和 <meta charset="UTF-8"> 同时存在时,行为不可预测。
正确做法:
- 只保留一行:
<meta charset="UTF-8"> - 删掉所有
http-equiv="Content-Type"的meta - 构建工具(Vite/Webpack)生成的 HTML 模板里,确认这行没被插件误删或挪到
<title>后面
最容易被忽略的一点:双击本地打开(file:// 协议)时没有 HTTP 响应头,全靠 meta 和文件编码兜底;而上线后服务器头一错,乱码立刻暴露——所以本地测试不能只看“能显示”,得查 DevTools 的 Encoding 显示是否为 UTF-8。


















