网页语言配置必须从根元素开始唯一声明,符合bcp 47规范(小写、短横线、正确子标签),禁用js后查看源码验证,局部内容需显式标注lang,ssr阶段确保注入。

网页语言配置是否正确,直接决定屏幕阅读器读得准不准、Chrome 翻译按钮出不出、:lang() CSS 选择器管不管用——检测必须从根元素开始,不能靠肉眼扫一遍就下结论。
检查 html 标签是否写了 lang 且位置唯一
浏览器、NVDA、VoiceOver、Google Search Console 全部只认 这一处声明。其他地方写等于白写。
-
:无效,<title></title>和<meta name="description">完全不继承,翻译按钮大概率消失 -
<meta http-equiv="Content-Language" content="zh-CN">:HTML5 已废弃,所有现代浏览器静默忽略 - JS 动态设置
document.documentElement.lang = "en-US":对已加载页面的读屏会话基本无效,CSS:lang()也不会重算 - 空值或非法值如
lang=""、lang="Chinese"、lang="zh_china":会被当“未知语言”,iOS VoiceOver 可能 fallback 到英文 TTS 引擎硬读中文
验证 lang 值是否符合 BCP 47 规范
大小写、连字符、子标签顺序不是风格问题,是解析逻辑的关键。错一个字符,辅助技术就可能跳过整页语言上下文。
- 中文必须用
zh-CN(小写 + 短横线),不是zh(太宽泛)、zh-Hans(不绑定地域,旧版 Safari 匹配不准)、zh_CN(下划线非法) - 英文必须用
en-US或en-GB,english、EN-us、en_US全部被忽略 - 法语、葡萄牙语等对大小写敏感:
fr-FR合法,FR-fr不合法 - 用
document.documentElement.lang在控制台直接读取,确认输出是字符串"zh-CN"而非null或undefined
测试局部 lang 覆盖是否生效
主语言设对只是起点;嵌入的英文术语、代码注释、引文若没显式标注,屏幕阅读器仍会用中文规则硬读,比如把 API 读成“阿皮”。
- 单个词:
<code lang="en">useState—— IDE 高亮和读屏发音都依赖这个 - 整段英文:
<p lang="en">This is a code example.</p>,不是<div lang="en">(语义不清,干扰父级 <code>:lang(zh)匹配) - 代码块注释:
<pre class="brush:php;toolbar:false;" lang="en"># Initialize counter</pre>,注意不是lang="bash"(lang表示语言,不是语法类型) - 避免滥用:
<span lang="en">Hello</span>套在中文句子里没问题,但不要给每个英文单词都加——DOM 体积增大,可访问性树构建变慢 - Next.js:必须在
app/layout.tsx中通过localeprop 输出真实值,确保 SSR 阶段就存在 - Nuxt:用
useLocaleHead(),而不是等挂载后执行document.documentElement.lang = ... - Vue CLI 或纯 CSR 项目:如果服务端返回的是
,客户端切语言后必须强制刷新,否则 VoiceOver 从头到尾按英文读 - 验证方法:禁用 JS 后打开页面,查看源码(右键 → “查看页面源代码”),确认
标签里已有正确的 <code>lang值
动态页面中 lang 是否在首屏 HTML 中正确注入
React/Vue/Next.js/Nuxt 的 CSR 渲染容易在这里翻车:JS 拿到 locale 后再改 document.documentElement.lang,对首屏已解析的 DOM 来说,为时已晚。
最难的不是写对一个 lang="zh-CN",而是让每个服务端模板、每个 SSR 组件、每个第三方脚本插入的文本节点,都在 HTML 解析最早阶段就带着准确的语言上下文被识别——漏掉任意一环,多语言体验就断在看不见的地方。











