<body lang="zh-CN">对页面主语言声明完全无效,因浏览器、屏幕阅读器等仅读取<html>标签的lang属性来初始化语音引擎、触发翻译等功能,写在<body>上时机已晚且不参与文档级语言判定。

body 标签不能覆盖 html 的 lang 属性——这不是功能限制,而是规范设计:浏览器、屏幕阅读器、搜索引擎和 Chrome 翻译按钮压根不读 body lang,它对页面主语言声明完全无效。
为什么body lang写上去也白写
浏览器在解析 HTML 最早阶段就锁定 html 元素的 lang 值,用于加载语音库、切分音节、触发翻译入口。写在 body 上,时机已晚;且该值不参与文档级语言判定,<title>、<meta name="description"> 等头部内容也不会继承它,直接“失联”。常见现象包括::lang(zh-CN) CSS 选择器不匹配、VoiceOver 按系统默认语种朗读、Chrome 地址栏不出现翻译按钮。
lang 必须写在 html 标签上,且只能一次
正确写法只有这一种:<html lang="zh-CN">。其他位置全被忽略:<body lang="zh-CN">、<div lang="zh-CN">、<meta http-equiv="Content-Language">(HTML5 已弃用)、甚至 JS 动态改 document.documentElement.lang 都无法补救初始语言声明缺失。
多个要点:
立即学习“前端免费学习笔记(深入)”;
- 值必须符合 BCP 47 标准:小写字母 + 连字符,如
zh-CN,不是ZH-CN、zh_CN或chinese -
zh-CN是首选:兼容性最稳,NVDA/JAWS/VoiceOver 全支持;zh-Hans可用于强调简体字但不绑定地域,需确保所有子元素同步更新 -
<html lang="">等价于未声明,会被当未知语言处理
局部语言切换得靠子元素显式设 lang
如果页面里有英文术语、代码块或引用日文内容,不能依赖 body 统一覆盖,而要逐个元素设置:<p lang="en">API</p>、<pre lang="bash">、<blockquote lang="ja">。这些是合法混排,不是 bug。
动态切换语言时注意:
- 不能只改
document.documentElement.lang,必须遍历并重设所有含文本的语义化标签(<h1>、<p>、<label>等)的lang属性 - 技术类
lang(如<pre lang="bash">)通常应保留原值,可加data-keep-lang标记跳过更新 - 已有
data-i18n的元素,若漏设lang,屏幕阅读器仍会按旧语言播报aria-label或placeholder
最容易被忽略的一点:即使你用 SSR 或构建工具生成了正确的 <html lang="zh-CN">,只要某个 <p> 没显式带 lang,它就继承父级(即 html),看似没问题——但一旦里面嵌了英文术语或代码,又没单独标注,屏幕阅读器就会错乱朗读。语言不是“继承就够”,而是“每个可读文本节点都得自己说清自己是什么语种”。



















