乱码不是CSS没加载,而是浏览器用错编码读取字节流;核心是确保CSS为UTF-8 without BOM,并通过@charset "UTF-8"(首行无BOM/空格/注释)或HTTP响应头Content-Type: text/css; charset=utf-8明确声明编码。

乱码不是 CSS 没加载,而是浏览器用错了编码读取字节流;核心只需两步:确保 CSS 文件是 UTF-8 without BOM,且通过 @charset "UTF-8" 或 HTTP 响应头 Content-Type: text/css; charset=utf-8 明确声明解析编码。
@charset "UTF-8" 必须严格位于第一行且无干扰
@charset 是 CSS 规范中唯一能覆盖浏览器默认编码的声明,但它极其敏感:
- 前面哪怕有一个空格、换行、
/* 注释 */或 BOM 字节(EF BB BF),整个声明就失效 - 失效后浏览器退回到系统 locale(Windows 下常为 GBK),把 UTF-8 中文双字节当两个单字节拆开,结果是错位、方块或整段样式被跳过
- VS Code 右下角点击编码 → “Save with Encoding” → 必须选
UTF-8(不是UTF-8 with BOM) - 用
xxd style.css | head -1检查开头三字节:不能出现ef bb bf;有则说明带 BOM,@charset白写 - 不要复制粘贴
@charset行——某些编辑器会悄悄插入零宽空格(\u200b),导致声明失效
HTTP 响应头比 @charset 优先级更高
当 CSS 通过 <link> 引入时,浏览器以 HTTP 响应头中的 Content-Type 的 charset 为最高优先级:
- 如果服务器返回
Content-Type: text/css; charset=gbk,哪怕 CSS 文件里写了@charset "UTF-8",浏览器仍用 GBK 解码,中文照样乱码甚至 404(路径含中文时尤其明显) - 用 Chrome DevTools 的 Network 标签页,找到对应 CSS 请求 → Headers → Response Headers → 查看
Content-Type是否含charset=utf-8 - Vite / Webpack Dev Server 默认发
charset=utf-8,一般无需干预;Nginx 需显式配置charset utf-8;(不能写成charset gbk;) - CDN 或旧 Apache 服务器可能强制覆盖响应头,用
curl -I https://example.com/style.css实测响应头
CSS 文件里写中文 content 还是乱码?别用裸中文
这不是编码问题,而是 CSS 规范对裸中文支持不稳定。W3C 明确定义的只有 Unicode 转义语法(去掉 u 前缀,每个码点单独写):
立即学习“前端免费学习笔记(深入)”;
-
content: '\u5e74'是 JS 写法,在 CSS 里会被当普通字符串解析,不转义 - 正确写法是
content: '\5e74'(注意没有u,斜杠后直接四位十六进制) - 可用
escape('年')得到%u5E74,再手动改成\5e74;或用在线工具转完删掉u - 字体名、注释里的中文同理——注释乱码可能吃掉后续
*/,导致整段样式被注释掉
本地 file:// 协议下 @charset 彻底失效
没有 HTTP 协议,就没有响应头,@charset 在 file:// 下被绝大多数浏览器忽略:
- 此时浏览器全靠“猜”:HTML 的
<meta charset="UTF-8">对 CSS 完全无效,系统 locale 和文件 BOM 都不可靠 - 开发阶段务必用本地服务(
vite dev、python -m http.server、live-server),别双击打开 HTML - 如果必须用
file://,CSS 文件只能存为UTF-8 with BOM(虽违反规范,但 IE/Edge 会认),且 HTML 必须有<meta charset="UTF-8">
最容易被忽略的是:路径里的中文(比如 url("图标.css") 或 @import "按钮.css")和 @charset 无关。它只影响 CSS 文件自身文本解析,不干预 URL 编码逻辑——这类问题得靠服务器配 charset utf-8 或干脆避开中文路径。


















