必须写在标签上且值为zh-cn等bcp 47标准格式,否则nvda、voiceover等屏幕阅读器将fallback至英文引擎,导致中文被逐字拼读;局部lang仅在根lang正确时生效,非法值如zh、zh_cn、chinese均被静默忽略。

必须写在 标签上,且值为 zh-CN 这类完整 BCP 47 标签,否则 NVDA、VoiceOver、JAWS 会直接 fallback 到英文引擎,中文被逐字拼读成 “B-e-i-j-i-n-g”。
为什么只认 这一个位置
屏幕阅读器(NVDA、VoiceOver、JAWS)只在初始解析 HTML 时读取这一个声明,用它初始化整页语音引擎。其他位置全被忽略:
-
:不触发全局语言切换,仅极少数断词场景有微弱影响 -
<meta http-equiv="Content-Language">:HTML5 已废弃,所有现代 AT 完全无视 <div lang="en">:只对内部文本生效,但前提是根 <code>lang已正确设置;否则它连“局部覆盖”的资格都没有-
document.documentElement.lang = "en-US"(JS 动态改):已渲染内容不会重朗读,CSS:lang()不重匹配,翻译按钮不刷新 -
lang="zh":太宽泛,旧版 JAWS 和 iOS VoiceOver 直接 fallback 英文 -
lang="zh_CN":下划线非法,BCP 47 要求用短横线zh-CN -
lang="Chinese":非标准标签,完全不识别 -
lang="zh-CN ":末尾空格导致解析失败,Lighthouse 报invalid language subtag - 单个外文词或代码标识符:
<code lang="en">fetch()(比<span></span>更语义准确,部分读屏对<code>有特殊停顿) - 整段英文:
<p lang="en">The response is a JSON object.</p> - 表格单元格必须单独设:
<td lang="en">iPhone 15 Pro</td>,不能靠<table lang="en"> 继承 <p>避免滥用:<code><div lang="en"> 包裹多段落——语义不清,还可能干扰 CSS <code>:lang(en)匹配和 JS 的语言逻辑判断。最麻烦的不是写错,而是写了但没测
不同 AT 对嵌套
lang的解析深度不一致。截至 2026 年 9 月,NVDA 和 VoiceOver 在同一段嵌套三层的混排文本中表现差异明显:有的跳过中间层,有的缓存混乱,有的干脆按最外层语言硬读。服务端模板里用lang="{{ locale }}"动态插入时,必须过滤非法值(如后端返回"zh")。SSR 首屏 HTML 若没带合法lang,爬虫和 AT 拿到的就是空值,JS 补救为时已晚。
lang 值写错等于没写——常见非法写法
浏览器和 AT 遇到非法值会静默忽略,等效于未声明语言。以下写法全部失效:
推荐值:zh-CN(大陆简体)、zh-TW(台湾繁体)、zh-HK(香港繁体)。zh-Hans 可用但兼容性略窄;zh-Hans-CN 是非法组合。
中英文混排时,根 lang 不够用
根 lang="zh-CN" 只管默认行为。遇到英文单词、代码、引文,屏幕阅读器仍会用中文规则硬读,比如 “API” 变 “阿皮”,“React” 变 “瑞克特”。必须显式标注:











