lang属性必须显式写在语义化元素上,如<p>、<blockquote>、<span>等,而<div>无语言语义,无法触发屏幕阅读器正确发音;语言码须符合BCP 47标准,CSS :lang()为精确匹配,动态插入内容需同步设置lang。
很多开发者以为给一个 <div lang="en"> 包住几段英文就能让屏幕阅读器正确切换发音,其实不行。<div> 没有语言语义,读屏软件不会把它当作“一段外语内容”处理,仍按 <html lang="zh-CN"> 的规则朗读英文单词,比如把 “API” 读成“阿皮”。
真正起作用的是带明确语义的标签 + lang:引文用 <blockquote lang="en">,术语用 <span lang="ja">,代码注释用 <pre lang="en">。这些标签本身代表“这是独立的语言单元”,再配合 lang 才能被辅助技术识别。
<p lang="en">This is English.</p> ✅ 有效,<p> 是文本容器,语义清晰<span lang="fr">bonjour</span> ✅ 适合单个词或短语<div lang="en"><p>...</p></div> ❌ 无效,<div> 不传递语言意图<h2 lang="ko">제목</h2> ✅ 标题也是语义化元素,可单独声明如果你写了 <html lang="zh-CN">,又在某段里加了 <p lang="en">,那 CSS 里 :lang(zh-CN) { quotes: "「" "」"; } 只会匹配到没设 lang 的元素;而 :lang(en) { quotes: "“" "”"; } 才能生效于那段英文。但要注意::lang(zh) 不会匹配 lang="zh-CN",:lang(zh-CN) 也不会匹配 lang="zh-Hans" —— 它们是精确字符串匹配。
:lang(zh) 覆盖所有中文变体,得分别写 :lang(zh-CN), :lang(zh-TW), :lang(zh-HK)
[lang^="zh"](属性选择器前缀匹配),更实用lang 会覆盖父级,但不会“取消”父级样式,只是触发自己的 :lang() 规则常见错误是给 <pre> 写 lang="bash" 或 lang="javascript" —— 这些不是合法语言码,BCP 47 不认。如果里面是英文注释,应该写 lang="en";如果是日文文档说明,就写 lang="ja"。同理,<q> 引用外文时,lang 必须对应实际内容语言,不是“这个引号看起来像英文”就填 en。
立即学习“前端免费学习笔记(深入)”;
<pre lang="en"># 初始化计数器</pre> ✅ 注释是英文,语言码合法<pre lang="bash">echo "hello"</pre> ❌ bash 不是语言,应去掉或改用 lang="en"
<q lang="de">Guten Tag</q> ✅ 引用德语,语义+语言一致<title lang="en">Home Page</title> ❌ <title> 不支持 lang 属性,浏览器忽略JS 拼接 HTML 字符串后插入 DOM,如果忘了带上 lang,那段内容就继承父级语言,导致英文被中文引擎硬读。React/Vue 中用 JSX 或模板渲染时,也要确保 lang 是静态属性或由 i18n 数据驱动,而不是事后用 element.setAttribute('lang', 'en') 补 —— 那样读屏软件很可能已经完成解析,补了也白补。
<p lang="{{item.lang}}">
{ text: "Hello", lang: "en" }
document.documentElement.lang 推断局部语言,它只定义主语言,不决定子内容实际项目里最容易被忽略的,是那些看似“一眼看懂”的英文术语——比如 <span>HTTP status code</span>,不加 lang="en",读屏就会念成“H T T P 状 态 代 码”。语言声明不是装饰,是告诉机器“这段字该怎么读、怎么断词、怎么翻译”的最小契约。