:lang() 选择器更可靠,因它依赖语言继承而非显式 lang 属性,大小写不敏感且支持 bcp 47,兼容性好、不污染 html,适合多语言字体控制与精准样式匹配。

用 [lang] 选择器直接匹配语言代码
HTML 的 lang 属性是标准且可靠的多语言样式控制入口,浏览器原生支持,不需要 JS 干预。关键在于写对选择器——不是用类名模拟,而是真实依赖 或 <div lang="ja"> 这类属性。
<p>常见错误是写成 <code>div[lang=zh] 却忽略属性值大小写敏感性(zh-cn 和 ZH-CN 不等价),或误以为 [lang^="zh"] 能自动覆盖所有中文变体(实际不匹配 zh-Hant,除非显式声明)。
-
[lang="zh-CN"]精确匹配,适合强区域控制(如简体中文特有标点间距) -
[lang^="zh-"]匹配所有带zh-前缀的值(zh-TW、zh-HK都生效) -
:lang(zh)更智能:它不依赖元素是否带lang属性,而是继承父级语言,且对大小写不敏感,还支持 BCP 47 规则(:lang(zh)可匹配zh-Hans、zh-CN、zh)
:lang() 比 [lang] 更可靠的实际原因
很多人用 [lang] 是因为“看着直观”,但线上项目常出问题:翻译组件动态插入内容时忘了补 lang 属性;或者父级 已设,子元素却没显式写 lang,导致 [lang="ja"] 完全不生效。
:lang(ja) 没这问题——只要元素在语言上下文里(哪怕没写 lang),它就生效。CSS 规范明确要求浏览器按语言继承链计算,所以它更接近“真实语言环境”。
立即学习“前端免费学习笔记(深入)”;
- 兼容性足够:Chrome 1+、Firefox 1+、Safari 3.1+、Edge 12+ 都支持
- 不污染 HTML 结构:不用给每个段落加
lang,靠继承就行 - 避免重复设置:比如中英混排的按钮文字,用
button:lang(zh) { font-family: "PingFang SC", sans-serif; }就比在每个按钮上写lang="zh"干净得多
中日韩字体栈必须按 :lang() 分开写
直接写 font-family: "Noto Sans CJK SC", "Hiragino Sans GB", sans-serif; 是典型反模式——中文用户看到日文字体渲染,日文用户看到中文字体 fallback,字重、字宽、标点位置全乱。
正确做法是把字体声明拆进不同语言块,让每种语言只加载自己需要的字体:
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]替代——如果页面设了lang="ja",但某段落是用户输入的中文评论,它没lang属性,[lang="zh"]就抓不到,而:lang(zh)可以通过该段落的父容器或自身属性识别 - 字体名含空格必须加引号,否则解析失败
- 别漏掉
sans-serif终极 fallback,否则某些系统可能渲染成 Times New Roman
遇到 lang 不生效?先查这三件事
不是选择器写错,就是环境没对上。90% 的失效都卡在这几个地方:
- HTML 根节点没设
lang属性:缺失会导致所有继承失效 - 动态内容没同步语言信息:React/Vue 渲染的弹窗、富文本,容易漏传
lang属性或没触发:lang()计算(其实只要 DOM 上有对应属性或继承链完整就没问题) - CSS 优先级被覆盖:比如全局写了
body { font-family: Arial; },后面body:lang(zh) { font-family: ... }就可能被压住,加!important是下策,优先调整选择器权重或顺序
最省事的验证方式:打开 DevTools,选中目标元素,看右侧面板的 “Computed” 里 font-family 是否已变成你写的中日韩字体——没变,说明语言选择器根本没命中;变了但字体显示异常,大概率是字体名拼错或系统没装。










