必须用bcp 47标准写lang值(如zh-cn),否则中文被当英文走西文字体链致排版错乱;font-family中文字体须置前,:lang()匹配依赖初始html值,js动态改lang无效。

lang属性不合法,字体回退链直接跳过中文字体
浏览器不是靠文本内容猜语言,而是严格按 lang 值触发内置的语言感知字体链。写错、漏写或用非标准格式(如 zh_CN、chinese、zh),中文就会被当成英文走西文字体 fallback 链——结果是标点撑开、引号变英文、混排时中文糊成一片,甚至直接显示方块。
必须用 BCP 47 标准写法:zh-CN(简体中文)、zh-TW(繁体中文)、ja-JP(日语)、en-US(美式英语)。iOS VoiceOver 和 Safari 对 ja 这种短格式支持不稳定,ja-JP 才稳妥。
-
zh-Hans在部分旧工具中兼容性差,企业级项目优先用zh-CN -
ZH-CN或zh_ch等大小写/分隔符错误,前端需统一转为小写+连字符再赋值 - 只设
不够:局部英文段落、代码块、引用若没显式加lang,仍会继承并错用中文字体渲染
font-family 字体链顺序错了,专用字体根本不会加载
浏览器对 font-family 是从左到右“尝试即停”:一旦某个字体被识别为“可用”,后续字体全跳过。所以把英文字体(如 "Helvetica")放在中文字体(如 "PingFang SC")前面,会导致中文字体永远不生效。
典型翻车写法:font-family: "Helvetica", "PingFang SC", sans-serif → Chrome 可能直接用 Helvetica 渲染中文,字形错乱、间距爆炸。
- 语言专用字体必须放最前:
"PingFang SC"(简中)、"Hiragino Kaku Gothic Pro"(日)、"Apple SD Gothic Neo"(韩) - 避免跨语言混搭:
:lang(zh)里塞"Meiryo",它对中文支持弱,易出字形错位 -
sans-serif必须放在末尾;绝不能用system-ui开头,它会绕过所有语言专用字体
:lang() 选择器为啥有时不生效
:lang(zh) 能匹配 lang="zh"、lang="zh-CN"、lang="zh-Hans",但匹配逻辑依赖底层解析器,Chrome 和 Safari 行为不完全一致。更关键的是::lang() 是纯 CSS 匹配机制,不监听 DOM 变更,只认 HTML 解析时的 lang 值。
- 写
p:lang(zh-CN) { ... },但元素实际是<p lang="zh-Hans"></p>→ 不命中 - JS 动态改
document.documentElement.lang不会触发重排,已渲染节点的语言上下文已锁定 - 稳妥做法是显式列出常用变体:
html:lang(zh-CN), html:lang(zh-SG), html:lang(zh-Hans),或用属性选择器兜底:html[lang^="zh"](注意会误匹配lang="zhx")
动态切换语言时,只改根节点 lang 是无效的
搜索引擎索引、屏幕阅读器发音、浏览器翻译按钮是否出现,全部取决于首屏 HTML 中 的初始值。JS 后设的 document.documentElement.lang = 'en-US' 看似修改成功,实则:
- 已渲染的
<p>API endpoint</p>仍按初始lang走“微软雅黑”,字母间距挤压 -
:lang(en-US)不会匹配未显式声明lang="en-US"的子元素(哪怕它继承自根节点) - 真正要改的是所有带
lang属性的元素:document.querySelectorAll('[lang]')→ 遍历重设el.lang = 'zh-CN' - 特别注意语义化标签:
<blockquote lang="ja"></blockquote>、<pre class="brush:php;toolbar:false;" lang="bash"></pre>、<q lang="fr"></q>,漏一个就可能错读/错渲
最常被忽略的一点:字体回退不是“样式问题”,而是浏览器在解析 HTML 时就固化了每个节点的语言上下文;后续任何 JS 修改,都无法让已渲染的文本重新走中文字体链。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











