lang属性必须写在标签上,其他位置无效;中文首选zh-cn,因zh语义过宽导致屏幕阅读器fallback至拼音或英文朗读,且不符合bcp 47区域子标签要求。

lang 属性必须写在 标签上,其他位置基本无效;中文首选 zh-CN,不是 zh、zh-Hans 或 zh_CN —— 后三者要么语义模糊、要么不被主流辅助技术识别、要么直接被浏览器静默忽略。
为什么 lang="zh" 不推荐用
它太宽泛。iOS VoiceOver、NVDA 等读屏软件遇到 lang="zh" 时,可能跳过中文 TTS 引擎,转而用拼音逐字朗读,或 fallback 到系统默认语种(比如英文)。Google Search Console 也会报“语言未明确指定”。BCP 47 标准要求区域子标签(如 CN)显式声明,zh-CN 是事实标准,全链路兼容性最稳。
-
zh:ISO 639-1 基础代码,但 HTML5 实践中缺乏上下文,辅助技术无法区分简繁体 -
zh-Hans:虽符合 BCP 47,但 Safari 和部分旧版 Chrome 对其支持不稳定,:lang(zh-Hans)CSS 选择器易失效 -
zh_CN或zh-china:下划线非法、大小写混用,会被解析器丢弃,等价于没写
lang 值在表格和内联元素中的写法差异
表格单元格语言必须直接写在 <td> 或 <code><th> 上,不能靠父级 <code><table lang="en"> 继承。同理,<code><code>、<pre class="brush:php;toolbar:false;"></pre> 这类语义化容器也应显式标注语言,方便 IDE 高亮或语法工具识别上下文。
-
<td lang="ja">東京</td>✅ 正确,屏幕阅读器可触发日语发音 -
<td><div lang="ja">東京</div></td>❌<div> 无语言语义,不传递意图 <li> <code><code lang="en">useState✅ 触发 IDE 英文关键词高亮 -
<pre class="brush:php;toolbar:false;" lang="bash">curl -X POST</pre>✅ 语法分析器能识别 shell 上下文 - ✅
p[lang^="zh"] { font-family: "Noto Sans CJK SC"; }—— 匹配所有以zh开头的语言值 - ✅
blockquote[lang="fr"] { quotes: "« " " »"; }—— 精确控制法语引号样式
多语言混排时 :lang() CSS 选择器的坑
:lang() 是精确字符串匹配,td:lang(zh-Hans) 不会匹配 <td lang="zh-CN">,反之亦然。实际项目中建议改用属性选择器前缀匹配,更鲁棒。
<ul>
<li>❌ <code>p:lang(zh) { font-family: "Noto Sans CJK SC"; } —— lang="zh-CN" 不命中
动态页面中改 document.documentElement.lang 为什么常失效
屏幕阅读器在 HTML 解析初期就读取 document.documentElement.lang,JS 后期赋值对已激活的朗读会话基本无效。SPA 切换语言时,仅执行 document.documentElement.lang = "ja-JP" 不够。
- 临时补救:执行
document.title = document.title(空赋值),强制重读根节点 - 真正可靠的做法是服务端渲染时就输出正确值,比如 Next.js 在
app/layout.tsx中用 - 第三方脚本插入的内容(如评论框、广告位)若含文本,必须确保它们自身也携带正确的
lang,否则无障碍树会断裂
最难的不是填对一个 lang="zh-CN",而是让每个 DOM 节点——尤其是运行时动态插入、跨框架协作、第三方 SDK 注入的文本——都带着准确的语言上下文被解析和朗读。











