必须为每个非主语言内容显式声明lang属性,仅靠无法覆盖子元素;屏幕阅读器、翻译工具和css :lang()均依赖各元素自身lang值,不继承根标签,漏标将导致发音错误、翻译失效及样式不匹配。

必须为每个非主语言的段落、短语或代码块显式添加 lang 属性,仅靠 完全不够——屏幕阅读器会用中文引擎硬读英文术语,浏览器翻译按钮不识别局部外文,CSS :lang() 也匹配不到。
为什么 不能覆盖所有内容
浏览器和 NVDA/VoiceOver 等辅助技术只把 的 lang 当作文档主语言依据,用于字体 fallback、拼写检查默认行为和 SEO。但它不继承给子元素做语音朗读或翻译判定——除非你显式写上 lang,否则一段 <p>API</p> 会被读成“阿皮”,而不是 /ˈeɪ.piː.ˈaɪ/。
-
或<div lang="en"> 全无效:不被读屏软件识别为语言单元,<code>:lang(en)也不匹配 -
document.documentElement.lang = "en-US"(JS 动态改)毫无作用:DOM 已渲染完成,语音引擎不会重载,Chrome 翻译按钮也不会出现 - 局部混排场景(如中文文档里夹英文代码注释、日文引文、法语术语)必须逐个标注,不能“靠继承”蒙混过关
- ✅ 推荐写法:
zh-CN(最稳)、en-US、ja-JP、fr-FR;zh-Hans仅在需明确排除繁体且服务端可控时使用 - ❌ 绝对禁用:
zh_CN(下划线非法)、Chinese(非标准)、zh-ch(大小写错)、zh-hans-cn(三段式 IANA 不收录,Chrome 静默降级为zh) - 注意:
:lang(zh-CN)不匹配lang="zh-Hans",:lang(zh)也不匹配lang="zh-CN"——想宽泛匹配请用[lang|="zh"] - 单个外文词:
<span lang="en">API</span>,避免被中文 TTS 硬读 - 整段英文说明:
<p lang="en">This is a code example.</p> - 代码块中的自然语言注释:
<pre class="brush:php;toolbar:false;" lang="en"># Initialize counter</pre>(别用lang="bash",那不是语言码) - 引文类语义标签更可靠:
<blockquote lang="fr">…</blockquote>、<q lang="ja">こんにちは</q> - 避免滥用:
<div lang="en"> 包裹多个段落——语义不清,干扰父级 <code>:lang(zh)CSS 匹配:lang()样式怎么写才不翻车CSS 的
:lang()是继承感知型伪类,但匹配逻辑比想象中严格。它不看属性值是否“包含”,只看是否精确匹配或符合 BCP 47 继承规则。-
p:lang(en) { quotes: "“" "”"; }→ 只匹配<p lang="en"></p>,不匹配<p lang="en-US"></p> - 想覆盖变体,用属性选择器:
p[lang|="en"] { ... }可匹配en、en-US、en-GB - 字体控制要小心:
:lang(ja) { font-family: "Noto Sans JP", sans-serif; }在 Chrome 中才会触发日文字体回退链;只写[lang="ja"]就可能失效 - 别指望
:lang()替代 JS 切换语言——它只是样式钩子,不改变实际语言行为
最容易被忽略的是:动态生成的内容(比如 Vue/React 渲染的多语言文案)如果没在首屏 HTML 里带正确
lang,后续 JS 注入的节点即使加了lang,部分旧版读屏软件仍可能跳过识别。真要稳妥,SSR 必须注入,SPA 切换语言时得重刷整页或至少重写document.documentElement.outerHTML并手动清理 ARIA 缓存。 -
lang 值怎么写才真正生效
写错不报错,但等于没写。BCP 47 标准是硬门槛,大小写、分隔符、子标签顺序都影响匹配结果和工具链支持。
哪些元素必须加 lang?常见漏标位置
不是只有 <p></p> 才需要。任何语义上属于“另一语言”的内容区块,只要可能被辅助技术处理或参与样式匹配,就得标。











