lang属性必须写在<html>标签上,写错位置、值不合规或用JS动态修改均无效;推荐使用zh-CN,避免下划线或非标准码;多语言混排需为子元素显式标注lang,动态页面须服务端输出或整页刷新确保生效。

lang 属性必须写在 <html> 标签上,其他位置无效——这是所有问题的根源。写错位置、值不合规、用 JS 动态改,都会让屏幕阅读器“听不懂”,Chrome 翻译按钮“不出来”,Google Search Console 报“未指定语言”。
为什么<html lang="zh-CN">不能写在<body>里
浏览器和 NVDA/VoiceOver 只在初始 HTML 解析阶段读取 <html> 的 lang 值,之后任何修改都晚了。写在 <body lang="zh-CN"> 或 <div lang="zh-CN"> 仅影响该元素内局部行为(如极弱的断词),对整页语言识别毫无作用。
-
<body lang="zh-CN">→ 页面仍被识别为“无语言”,翻译按钮不出现,SEO 降权 -
<meta http-equiv="Content-Language" content="zh-CN">→ HTML5 已弃用,Chrome/Firefox/Safari 全部忽略 -
<html lang="">或<html lang="zh">→ 空值或宽泛值会被视为未知语言,iOS VoiceOver 可能跳过中文 TTS 引擎
zh-CN、zh-Hans、zh 到底怎么选
三者语义不同,兼容性差异直接体现在语音朗读、字体 fallback 和 CSS :lang() 匹配上。
-
zh-CN:事实标准。明确“简体中文 + 中国大陆规范”,NVDA/JAWS/VoiceOver/Chrome/Google 全链路稳定支持 -
zh-Hans:只声明“简体字”,不绑定地域。适合港澳台用户也用简体的场景,但旧版 Safari 的:lang(zh)可能匹配不准 -
zh:BCP 47 合法但不推荐。未区分简繁、无区域信息,部分辅助技术会 fallback 到英文 TTS,把“长”读成 /tʃæŋ/ 而非 /cháng/ - 绝对避免:
zh_china、zh_CN(下划线非法)、Chinese(非标准码)——全部静默失效
多语言混排时,lang 怎么局部生效
根节点 <html lang="zh-CN"> 设好只是起点。嵌入的英文术语、日文引用、代码注释等,必须显式标注子元素 lang,否则读屏仍用中文规则硬读。
立即学习“前端免费学习笔记(深入)”;
- 单个外文词:
<code lang="en">useState</code>—— 触发 IDE 英文高亮,且读作 /ˈeɪ.piː.ˈaɪ/ - 整段英文:
<p lang="en">This is a code example.</p> - 代码块注释:
<pre lang="en"># Initialize counter</pre>(注意不是lang="bash") - 避免滥用:
<div lang="en">包裹多个段落 ——<div>无语义,读屏软件不认它为“语言单元”,且干扰父级:lang(zh)CSS 匹配
动态页面中改 lang 为什么经常白忙活
关键点在于:辅助技术只读取初始 HTML 中的 lang,DOM 加载后 JS 修改 document.documentElement.lang 对已激活的朗读会话基本无效。
- SSR 页面:服务端必须根据
Accept-Language头或路由路径(如/en/about)直接输出带对应lang的 HTML - SPA 页面:语言切换钩子中执行
document.documentElement.lang = "ja-JP"是必要但不充分的;必须配合整页刷新,或至少强制重载 ARIA-live 区域 - Next.js/Nuxt:确保
<html lang={locale}>在首屏 HTML 响应中就输出,不能等 JS 执行后再 patch - 纯前端切换时,若必须用 JS 更新,可加兜底操作:
document.title = document.title(空赋值)触发部分读屏器重新读取根节点
真正难的不是写对一个 lang="zh-CN",而是让每个动态插入、跨框架渲染、第三方脚本注入的文本节点,都带着准确的语言上下文被解析——这需要从构建到运行时全程控制,而不是靠某一行代码一劳永逸。



















