lang属性必须写在标签上,其他位置无效;应使用zh-cn而非zh-hans或zh;多语言混排需为外文元素显式标注lang;动态页面须在首屏html中设置,js后期修改无效。

lang 属性必须写在 标签上,其他位置全无效——这是所有问题的起点。 写错位置、写错值、用 JS 动态改,都会导致屏幕阅读器“听不懂”、翻译按钮“不出来”、搜索引擎“认不出”。
为什么 必须写在根标签上
浏览器和读屏软件(NVDA、VoiceOver、JAWS)只在解析初始 HTML 时读取 的 lang 值,作为整页语言依据。后续任何修改都晚了。
-
→ 不被识别为文档语言,仅影响极少数子元素的局部断词,实际无用 <div lang="en"> → 语义缺失,读屏不把它当语言单元,硬读效果差<li> <code><meta http-equiv="Content-Language" content="zh-CN">→ HTML5 已弃用,Chrome/Firefox/Safari 全部忽略-
document.documentElement.lang = "en-US"(JS 执行)→ 已加载页面中,语音引擎不重载,CSS:lang()不重计算,翻译按钮不刷新 -
zh-CN:事实标准,明确“简体中文 + 中国大陆规范”,NVDA/VoiceOver/Chrome/Google 全链路支持最稳;CMS、翻译插件、SEO 工具默认认它 -
zh-Hans:只声明“简体字”,不绑定地域,适合港澳台用户也用简体的场景;但旧版 Safari 的:lang(zh)可能匹配不准,部分语音库加载失败 -
zh:过于宽泛,不区分简繁、不指明区域;iOS VoiceOver 可能跳过中文 TTS 引擎,把“长”读成 /tʃæŋ/;Google Search Console 可能报“未指定语言” - 绝对避免:
zh_china、zh_CN(下划线非法)、Chinese(非 BCP 47 标准)——全部静默忽略 - 单个外文词:
<abbr lang="en">API</abbr>→ 读作 /ˈeɪ.piː.ˈaɪ/,不是“阿皮” - 整段英文:
<p lang="en">This is a code example.</p> - 代码块注释:
<pre class="brush:php;toolbar:false;" lang="en"># Initialize counter</pre>(注意不是lang="bash") - 引文类语义标签更可靠:
<blockquote lang="fr">…</blockquote>、<q lang="ja">…</q> - 避免滥用:
<div lang="en"> 包裹多个段落 —— 语义不清,干扰父级 <code>:lang(zh)CSS 匹配动态页面中设置
lang容易踩的坑服务端渲染或前端路由切换时,
lang值若没同步更新,会导致语音朗读错、翻译逻辑乱、CSS 引号样式异常。- Next.js:必须在
app/layout.tsx中用,locale来自路由参数或 i18n 上下文 - Nuxt:通过
useLocaleHead()注入,确保首屏 HTML 就含正确值 - PHP 模板:用
,防 XSS - 纯前端 SPA:不能只改
document.documentElement.lang;已激活的读屏不会响应;最保险是整页刷新,或至少强制重载 ARIA-live 区域
最容易被忽略的一点:HTML 文档一旦加载完成,再改
lang对已激活的辅助技术基本无效——它只认初始值。别指望 JS patch 能“补救”。 - Next.js:必须在
zh-CN、zh-Hans、zh 到底该选哪个
三者语义不同,兼容性差异明显,选错会影响断词、字体回退、CSS 匹配甚至 SEO。
多语言混排时,怎么让 lang 真正起作用
主语言靠 确立,但嵌入的英文术语、日文引用、代码注释等,必须显式标注子元素的 lang,否则读屏仍用中文规则硬读。











