lang属性必须在首屏HTML根标签中声明且符合BCP 47规范(如zh-Hans、en-US),仅JS修改document.documentElement.lang无效,因浏览器和辅助技术在解析初期即锁定各节点语言值,不响应运行时更新,须同步遍历重设所有含lang元素。

lang 属性必须在 HTML 根标签中声明,且值需符合 BCP 47 规范(如 zh-Hans、en-US),否则屏幕阅读器、浏览器翻译、:lang() 选择器均无法正确识别。
为什么只改 document.documentElement.lang 不够
浏览器和辅助技术在 DOM 解析初期就锁定每个节点的 lang 值,不响应运行时继承更新。只执行 document.documentElement.lang = "ja" 后:
-
<title></title>和<meta name="description">仍按旧语言解析,影响 SEO 和语音播报 -
<img alt="logo">的 alt 文本不会自动切换语音引擎 -
:lang(ja) { font-family: "Noto Sans JP"; }样式完全不生效 - 嵌套的
<pre class="brush:php;toolbar:false;" lang="bash"></pre>或<blockquote lang="fr"></blockquote>会被错误覆盖
哪些节点必须显式设置 lang
不能依赖继承,以下节点需逐个检查并设置(或保留)lang:
- 所有语义化容器:
<h1>、<p>、<section>、<article>—— 值应与当前语言包一致 -
<title>和<meta name="description">—— 必须在服务端渲染时注入,JS 动态改无效(爬虫看不到) -
<img>的alt和title属性 —— 若含可翻译文案,需配合data-i18n-alt单独处理 -
<pre>、<code>、<blockquote>—— 若为技术内容或引用,加data-keep-lang显式跳过 - SVG 内的
<text>元素 —— 不继承父级lang,需单独设属性
服务端 vs 纯前端站点的 lang 注入时机
搜索引擎和辅助技术只认首屏 HTML 中已存在的 lang 值,JS 运行时补写是“事后补救”,仅对用户可见:
立即学习“前端免费学习笔记(深入)”;
- SSR/静态生成(如 Hugo、Next.js):把用户偏好注入到初始
<html lang="zh-HK">,最可靠 - 纯前端 SPA:首屏 HTML 固定用 fallback 值(如
lang="en"),再由 JS 同步更新document.documentElement.lang并遍历重设子节点 - 绝对禁止:
<html lang="{{lang}}">却未被模板引擎替换 —— 导致空字符串或非法值,破坏可访问性 - localStorage 存的是用户偏好(如
"preferredLang"),但不能替代服务端对<html lang>的真实输出
真正起效的 lang 是在 HTML 字节流里就存在的那个,不是 JS 改出来的;动态节点插入后必须立刻补 lang,否则新内容对屏幕阅读器来说就是“无语言”的黑盒。



















