:lang()伪类仅匹配带合法lang属性的元素,真正生效的是后续font-family等声明;90%失效源于html未设lang或值非法(如zh_CN、空值、xml:lang),必须用zh-CN等标准BCP 47格式且大小写规范。

:lang() 伪类本身不设置样式,它只是匹配语言上下文;真正起作用的是你跟在它后面的 font-family、line-height 等声明——但 90% 的“没生效”,问题出在 HTML 的 lang 属性根本没写对,或压根没写。
HTML 的 lang 属性必须显式、非空、符合 BCP 47
浏览器完全不推断语言,也不读取系统 locale 或 Accept-Language。以下全是无效写法:
-
(缺失lang) -
(空值) -
或(非法标签) -
(xml:lang在 HTML5 中不触发:lang())
正确写法示例:
<html lang="zh-CN"> <html lang="zh-Hans"> <html lang="ja"> <html lang="en-US">
大小写不敏感(zh-cn 和 zh-CN 都行),但下划线格式(如 zh_CN)不被识别。
立即学习“前端免费学习笔记(深入)”;
:lang(zh) 和 :lang(zh-CN) 匹配逻辑完全不同
:lang(zh) 是前缀匹配:能命中 lang="zh"、lang="zh-CN"、lang="zh-Hans",但 Safari 某些版本对子标签解析更严格,:lang(zh) 可能不触发 zh-Hans,而 :lang(zh-CN) 稳定生效。
- 想覆盖所有中文变体 → 同时写多个:
html:lang(zh)、html:lang(zh-CN)、html:lang(zh-TW)、html:lang(zh-HK) - 要精确控制简体中文 → 直接用
:lang(zh-Hans),但前提是你的真这么写了 - 别写
:lang("zh")(引号多余)或:lang(zh-cn)(小写没问题,但括号内值必须和属性值结构一致)
字体声明顺序错了,中英文都会翻车
直接写 font-family: "Noto Sans CJK SC", sans-serif 是典型错误:西文字母会被强制套用中文字体,导致字重发虚、标点错位;更糟的是,若用户系统没装该字体,sans-serif 会回退到 Helvetica(macOS)或 Arial(Windows),而这俩对日文、韩文支持极差,结果就是方块。
- 中日韩必须分开声明:
body:lang(zh) { font-family: "Noto Sans CJK SC", "PingFang SC", sans-serif; } body:lang(ja) { font-family: "Noto Sans CJK JP", "Hiragino Kaku Gothic Pro", sans-serif; }body:lang(ko) { font-family: "Noto Sans CJK KR", "Apple SD Gothic Neo", sans-serif; }- 混合内容(比如一段里夹日文)必须给具体元素加
lang:<p lang="ja">こんにちは</p>,否则:lang(ja)不会命中
Safari 下 :lang(zh) 有时不生效的真正原因
Safari 对 :lang() 的实现更严格:它要求 lang 属性必须出现在目标元素自身或其任意祖先元素上,且不能是通过 JS 动态插入后未触发 CSSOM 重算的“游离”状态。
- React/Vue 中动态渲染文本时,容易漏掉给根节点或文本容器补
lang - 建议在
上设默认值,再局部覆盖(如<span lang="ja">...</span>) - 不要依赖 JS 动态改
document.documentElement.lang后立刻重排样式——CSSOM 更新有延迟,可加getComputedStyle强制触发,或用requestAnimationFrame延迟应用
最常被忽略的一点:字体栈末尾必须保留系统默认字体族(如 sans-serif),否则某语言字体加载失败时会直接回退到英文 fallback,而不是降级到本地等宽字体或系统 UI 字体。


















