lang属性必须写在html标签上且值严格符合BCP 47格式,否则浏览器、屏幕阅读器等完全忽略;动态切换需服务端渲染支持,局部多语言须显式声明。

lang属性写错位置或格式,浏览器根本不会识别页面语言——不是“没效果”,而是“压根没读到”。
lang必须写在标签上,其他地方全无效
浏览器、屏幕阅读器、搜索引擎和翻译功能只认这个位置的值。写在
里,- Chrome 地址栏不出现翻译按钮,或点击后误判为日语
- VoiceOver 把英文术语
API读成 /aɪˈpiː.aɪ/ 还是 /ˈeɪ.piː.ˈaɪ/ 完全混乱 -
:lang(zh-CN)CSS 规则完全不匹配,连引号样式都失效
别信“加在 body 上也差不多”——它对页面级语言声明就是零作用。
值必须严格符合 BCP 47,小写+连字符缺一不可
浏览器对 lang 值校验极严,非法格式会被静默忽略(等同于没写):
立即学习“前端免费学习笔记(深入)”;
- ✅ 正确:
zh-CN、en-US、ja-JP、fr-FR - ❌ 错误:
zh_CN(下划线)、ZH-CN(大写)、zh(粒度太粗)、chinese(非标准标签)
特别注意:iOS VoiceOver 对 ja 支持不稳定,必须用 ja-JP;中文首选 zh-CN,不是 zh-Hans 或 zh——前者在旧版 Edge 中可能加载不到语音库,后者会让部分辅助技术直接 fallback 到英语引擎。
动态页面改 lang 不能只靠 JS 赋值
SPA 切换语言时,仅执行 document.documentElement.lang = "en-US" 是远远不够的:
- 屏幕阅读器已在 HTML 解析初期锁定语言,JS 后期修改对已激活朗读会话基本无效
- 已渲染的 DOM 不会触发浏览器重译,也不会刷新字体回退链
- 更糟的是:如果
<title></title>仍用中文文案但 lang 已切为en-US,VoiceOver 可能用英文音读出中文标题
真正可靠的方案是服务端渲染时就输出正确值,比如 Next.js 在 app/layout.tsx 中用 <html lang={locale}>;纯 CSR 场景下,至少要同步触发 document.title = document.title 强制重读根节点(但仍是妥协方案)。
局部多语言内容必须显式声明,不能靠继承
lang 有继承性,但浏览器不会“猜”哪段是外语。不显式标注,后果直接落在用户身上:
- 一段法语引文
<blockquote>Merci beaucoup.</blockquote>若没加lang="fr",NVDA 会用中文规则读标点,停顿错乱 -
<pre lang="bash">curl -X POST</pre>不写lang,语法高亮工具无法识别上下文,拼写检查也会误报 - 代码中的英文标识符如
useState,建议用<code lang="en">useState</code>,而非包裹整个段落
别为了“省事”给 <div> 加 lang——它破坏语义层级,还干扰父级 :lang(zh) 的 CSS 匹配范围。
最常被忽略的点是:lang 属性不是“设一次就完事”的开关,它是贯穿 HTML 解析、DOM 构建、辅助技术挂载、字体回退触发的底层信号。任何环节断掉,用户看到的可能只是文字,但听到的、搜索到的、渲染出来的,早已偏航。



















