Chrome 特殊字符乱码

—— 一个特殊字符乱码引发的故事

image.png
这个是 Vue3 源码里的 example todomvc 在 Chrome 98 里打开的样子

解决过程

  • 一开始以为是 encoding 编码问题,使用插件修改编码后发现不管用
  • 尝试在 Firefox 打开,正常
  • 查看源码,发现是一个特殊字符 ❯ (U+276f)
  • Google 关键词 “chrome u+276f”发现跟字体有关
    • 修改 css font 为 ‘Segoe UI Symbol’,不生效
  • 发现 css 在一个叫 todomvc-app-css 的包里
  • 对比两个 demo,尝试给 html 加上 <meta charset="utf-8">,解决
1
2
3
.toggle-all + label:before {
content: "❯";
}

问题

如何查看 DOM 元素实际渲染的字体?

Chrome:
image.png
Firefox:
image.png

如何查看、修改页面的编码格式?

查看

Document.characterSet - Web APIs | MDN

修改

最新版本的 Chrome 和 Firefox 都不支持修改编码,通常字符编码应该在文档或者 HTTP 头中指定,当没有指定编码时,浏览器会根据文档内容自动选择编码
browser - How do I change the character encoding for a webpage in Chrome? - Super User
Text Encoding no longer available in the Firefox menu panel | Firefox Help

当未指定字符编码时 Firefox 的错误提示:
image.png

一些测试

MarvinXu/charset-test

  • Chrome 会 auto-detect 字符集,当 HTML 中有 ❯ 符号解析为 UTF-8,没有时解析为 windows-1252
    • 当 HTML 不包含特殊符号,css 里包含特殊符号时,就出现乱码
    • css 里加上 @charset "utf-8"后正常
  • live server 下打开正常,因为 server 自动加上了响应头 Content-Type: text/html; charset=UTF-8
  • 解析错误得到的字符是:❯,而如果是字体没有该字符,则会渲染成方块
  • image.png

总结

虽然字符编码的问题遇到过很多,但是缺乏系统性的理解,处于以为明白其实不明白的状态。

乱码原因

源码中的 HTML、CSS、JS 都是以 UTF-8 编码,但是因为没有在文件中指定编码( HTML 中的 meta 标签、CSS 中的 @charset ),而且又是以file://文件协议访问,响应头里也没有指定编码,此时浏览器会根据 HTML 文档的内容去自动匹配合适的解码方式。因为此案例中特殊字符刚好在 CSS 文件中,HTML 中没有特殊字符,所以浏览器自动识别成了windows-1252,CSS 中的特殊字符就被解析成乱码。

Charset vs Encoding vs Font

TODO: What’s the difference between encoding and charset? - Stack Overflow

  • unicode 是字符集,UTF-8 是编码方式。
  • 现在代码一般都是以 UTF-8 编码了,如果解码的时候不以 UTF-8 解码,就会出现乱码。
  • 浏览器会根据响应头的 Content-Type、或者文档中定义的 charset 来解析,如果都不存在,则会自动选择“合适”的编码方式,但是各个浏览器的自动选择行为表现不一致。
  • Chrome、Firefox 的新版本都禁用了用户主动选择编码的功能。

参考

❯ - 粗右指尖引号装饰: U+276F - Unicode 字符百科
html - Chrome doesn’t display special character while other browsers do - Stack Overflow
Web fonts don’t show some characters in Chrome for Windows - Stack Overflow
What’s the difference between encoding and charset? - Stack Overflow
Character encodings: Essential concepts