根元素lang必须在服务端或首屏HTML中写死,仅JS设置document.documentElement.lang="en-US"无效;SSR框架需按请求头注入,静态站点应为每语言生成独立HTML,SPA无SSR时须整页刷新;局部多语言内容必须显式标注lang且符合BCP 47规范。

根元素lang必须在服务端或首屏HTML中写死
只靠 JS 执行 document.documentElement.lang = "en-US" 不会触发屏幕阅读器重载、Chrome 翻译按钮激活,也不会让 SEO 抓取到新语言——浏览器只认初始 HTML 里的 <html lang="zh-CN">。
SSR 框架(如 Next.js、Nuxt)需根据请求头 Accept-Language 或用户登录态,在模板渲染阶段注入正确值;静态站点(Hugo/Jekyll)应为每种语言生成独立 HTML 文件,并在模板中硬编码 lang;纯前端 SPA 若无 SSR 支持,语言切换时必须整页刷新(window.location.href = "/en/"),而非仅改属性。
局部多语言内容必须显式标注lang,不能依赖继承
即使 <html lang="zh-CN"> 已设对,<p>API</p> 仍会被读作“阿皮”,<pre lang="bash">curl -X POST</pre> 的注释可能被翻译成中文。这些节点必须各自声明语言:
-
<p lang="en">API</p>→ 屏幕阅读器用英文引擎读 -
<pre lang="en"># Initialize counter</pre>→ 注释不被误译,变量名保留原样 -
<blockquote lang="ja">ありがとう</blockquote>→ 日语发音引擎生效 -
<td lang="zh-Hans">超视网膜XDR显示屏</td>→ 表格单元格级语言控制有效
别用 lang="bash" 这类非 BCP 47 值——它不是合法语言标签,应改用 lang="en" 或留空。
立即学习“前端免费学习笔记(深入)”;
lang值必须严格符合BCP 47,大小写和分隔符都不能错
写错不报错,但等于没写:搜索引擎忽略、:lang(zh-CN) 样式不匹配、VoiceOver 无法加载对应语音包。
✅ 正确写法(注意短横线 -、小写、两段式为主):zh-CN、en-US、pt-BR、zh-Hans、ja-JP
❌ 典型错误:zh_CN(下划线 → 静默降级为 und)ZH-cn(大小写混用 → iOS VoiceOver 失效)zh-hans-cn(三段式 → IANA 不收录,Chrome 降级为 zh)Chinese(非标准字符串 → 完全无效)
:lang() 伪类匹配要小心精确性与前缀策略
:lang(zh-CN) 不匹配 lang="zh-Hans",:lang(zh) 也不匹配 lang="zh-CN" —— 它是严格字符串匹配,不支持子标签继承。
更稳妥的做法是用属性选择器前缀匹配:
-
td[lang^="zh"]→ 覆盖zh-CN、zh-Hans、zh-TW -
p[lang="en-US"], p[lang="en-GB"]→ 显式枚举常见变体
如果用了 :lang() 写字体链,务必确保每个目标元素真有对应 lang 值,否则规则完全不生效。表格里尤其容易漏——<th> 和 <td> 必须各自带 lang,<table lang="en"> 对单元格无效。
最常被忽略的点:动态插入的 DOM(比如 AJAX 加载的弹窗、懒加载模块)不会自动继承或更新 lang,必须手动遍历并设置;而 <script> 和 <style> 内部写 lang 没意义,它们不参与文本渲染。



















