必须为每个语言片段显式声明 lang 属性,仅设置 html 根标签 lang="zh-cn" 不足;需严格遵循 bcp 47 规范(如 zh-cn、en-us),配合 :lang() 选择器与 spa 全节点同步更新,否则翻译、朗读、排版等功能静默失效。

不设 lang 属性,多语言网页的屏幕阅读器朗读、浏览器翻译、CSS 排版、拼写检查全都会“认错人”——这不是体验降级,而是功能失效。
为什么只写 还远远不够
根标签的 lang 是起点,不是终点。浏览器和辅助技术不会自动推断段落里夹的英文术语、日文引文或 Bash 命令是“外语”,它们只认显式声明的 lang 值。
- 没给
<pre class="brush:php;toolbar:false;" lang="bash">curl -X POST</pre>加lang,Chrome 翻译菜单会跳过整块代码,语法高亮工具也可能 fallback 到错误的词法解析规则 -
<blockquote lang="fr">C’est la vie.</blockquote>不加lang,VoiceOver 会用中文语调读法语重音,标点停顿完全错乱 - 只改
document.documentElement.lang = "en",已渲染的 DOM 节点(如富文本、第三方组件插入的<p></p>)仍按旧语言解析,屏幕阅读器卡在旧语音引擎里
lang 值必须严格符合 BCP 47,错一个字符就等于没写
写错 lang 不报错,但所有依赖它的功能都静默失效:SEO 抓取当无语言处理、:lang(zh) 样式不匹配、字体回退链断裂、iOS VoiceOver 直接降级为英语发音。
- ✅ 正确:
zh-CN、en-US、ja-JP、zh-Hans(注意是短横线-,不是下划线_) - ❌ 无效:
zh_CN、Chinese、zh-ch、cn、zh-hans-cn(IANA 不收录三段式,Chrome 静默降级) - 选
zh-CN还是zh-Hans?多数 CMS、SEO 工具、翻译插件只认zh-CN;zh-Hans仅当你需强调“简体字”且明确排除港澳台繁体场景时才用
:lang() 和 [lang] 在 CSS 中行为完全不同
想用 CSS 控制不同语言的排版(比如日文标点间距、阿拉伯文右对齐),选错选择器样式就完全不生效。
-
[lang="ja"]只匹配显式写了lang="ja"的元素,不继承父级值 -
:lang(ja)能匹配该元素或其任意祖先有lang="ja",适合嵌套混排(如<div lang="ja"><p>こんにちは</p></div>) - 注意:
:lang(zh)不匹配lang="zh-CN",:lang(zh-CN)也不匹配lang="zh-Hans"—— 必须枚举所有可能变体,或统一用更宽泛但兼容性更好的值(如:lang(zh)+:lang(zh-CN)并列)
单页应用(SPA)切换语言时,lang 更新必须同步到所有节点
SSR 页面靠服务端吐出正确 ;纯前端 SPA 切换语言,不能只改根节点。
- 必须遍历并更新所有含语言信息的节点:
<blockquote lang="fr"></blockquote>、<code lang="python">、<p lang="en"></p> - 如果用了
data-i18n+ JSON 翻译方案,记得重刷这些节点的textContent,否则lang值虽对,内容还是中文 - localStorage 存的是用户偏好,但首次加载得靠
navigator.language或 URL 参数(如/zh)兜底,否则首屏无障碍功能从一开始就是错的
最常被忽略的一点:lang 属性本身不触发重绘或重流,但它决定了浏览器是否启用某套底层渲染逻辑——字体链、连字符断行、Unicode 渲染行为、甚至表单光标走向。一旦漏标或错标,修复成本远高于初始设置。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











