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

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



















