乱码不是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 明确告诉浏览器该用 UTF-8 解析。
@charset 必须严格位于第一行且无干扰字符
@charset 是 CSS 规范里唯一能覆盖浏览器默认编码的声明,但它极其脆弱:前面哪怕有一个空格、换行、/* 注释 */ 或 BOM 字节(EF BB BF),整个声明就失效。浏览器立刻退回到系统 locale(Windows 下常为 GBK),把 UTF-8 的中文双字节当两个单字节处理,结果就是错位、方块或整段样式失效。
- 用 VS Code 打开 CSS 文件,右下角点击编码 → “Save with Encoding” → 选
UTF-8(**不是 UTF-8 with BOM**) - 用命令
xxd style.css | head -1检查开头三字节:必须完全无ef bb bf;有则说明带 BOM,@charset不生效 - 不要复制粘贴
@charset行——某些编辑器会悄悄插入零宽空格(\u200b),导致声明失效 - 在 Chrome DevTools 的 Sources 面板中打开该 CSS,确认顶部是否高亮显示
@charset "UTF-8";,且无解析错误
HTTP 响应头比 @charset 优先级更高
当 CSS 通过 <link> 引入时,浏览器以 HTTP 响应头中的 Content-Type 的 charset 为最高优先级,@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实测响应头 -
<meta charset="UTF-8">只作用于 HTML 文档本身,对 CSS 文件**完全无效**,别指望它能“传染”给引入的 CSS
本地 file:// 协议下 @charset 彻底失效
没有 HTTP 协议,就没有响应头,@charset 在 file:// 下被绝大多数浏览器忽略。此时浏览器靠猜:HTML 的 <meta> 不起作用,全凭系统 locale 或文件 BOM —— 这些都不可靠。
立即学习“前端免费学习笔记(深入)”;
- 开发阶段务必用本地服务:如
vite dev、python -m http.server、live-server,**别双击打开 HTML 文件** - 若真必须用
file://(如离线演示),CSS 文件只能存为UTF-8 with BOM(虽违反规范,但 IE/Edge 会认),且 HTML 也需用相同编码保存 - VS Code 中保存为
UTF-8 with BOM后,@charset仍要放在第一行,但此时它已不关键——BOM 本身成了主要识别依据
Less/Sass 等预处理器编译后中文乱码
根本原因不是预处理器不支持中文,而是编译过程未显式指定 UTF-8 编码写入输出文件。Node.js 的 fs.writeFile 默认依赖系统 locale(如 ISO-8859-1),导致中文被错误编码。
- 确认源文件确实是 UTF-8:
file -i style.less输出应含charset=utf-8 - 避免裸调
lessc style.less > style.css—— 重定向不保证编码;改用 Node 脚本,显式传'utf8'参数:fs.writeFile('style.css', output.css, 'utf8') - Webpack +
less-loader中,即使文档没明说,也要在options里加encoding: 'utf8';同时确保css-loader≥ v6.0,旧版对@charset支持不完整 - 编译前在
.less文件顶部手动加@charset "UTF-8";(必须第一行),可规避部分 loader 的编码猜测逻辑
真正容易被忽略的点是:路径里的中文(比如 url("图标.css"))和 @charset 无关,它只受 URL 编码规则和服务器响应头影响;而 content: "年" 这类值,即使编码全对,在某些环境仍可能显示为方块——这时得换成 content: '\5e74' 这种 CSS 原生 Unicode 转义写法。


















