HTML根元素的lang属性必须设为小写短横线格式(如zh-CN)且仅出现在标签中,否则屏幕阅读器将错误朗读;多语言混排需显式嵌套lang,动态切换须服务端预置并同步更新相关属性。

lang 属性设错或不设,屏幕阅读器大概率把中文读成日文、英文甚至乱码——这不是“听起来别扭”,而是用户根本听不懂。
html 根标签的 lang 必须写对且只写一次
浏览器和辅助技术(如 NVDA、VoiceOver)只认 这一个位置的值。它决定整页断词、声调、标点停顿和翻译触发逻辑。
-
无效,纯属浪费 DOM 节点 -
<meta http-equiv="Content-Language" content="zh-CN">已被 HTML5 废弃,现代浏览器直接忽略 -
或→ 视为“未知语言”,TTS 引擎 fallback 到英文朗读中文 - 必须用小写字母 + 短横线 + 地区码:✅
zh-CN、en-GB、ja-JP;❌zh_cn、ZH-CN、zh、Chinese
多语言混排时,局部 lang 怎么嵌套才安全
一段英文引文、一个外文人名、代码块里的注释——这些内容不会被自动识别语言,必须显式加 lang,否则屏幕阅读器会强行用中文规则切分英文单词,读成“特-阿-特-欧夫-科-姆-普-特-尔”。
- 语义合理优先:
<blockquote lang="fr">Je suis français.</blockquote>合法;<div lang="en">... 不推荐,<code><div> 无语义,读屏不认 <li>嵌套必须闭合:<code><p lang="zh-CN">参考 <code lang="en">useStateAPI ✅;开lang不关 ❌ - 避免过度嵌套:连续三层
lang切换(如 zh-CN → en-US → ja-JP)会让部分 AT 缓存混乱,优先合并同类语种块 - 非文本内容也得管:
<input placeholder="Search">的父容器是lang="zh-CN"?那 placeholder 会被读成中文发音;SVG 中的<title>编辑</title>没加lang="zh-CN"?照样读错 - 服务端必须输出正确初始 HTML:Next.js/Nuxt 等框架需确保 SSR 阶段就渲染出带正确
lang的 - 若真要运行时切换(如 demo 页),至少同步三处:
document.documentElement.lang、所有已渲染子元素的lang属性、当前SpeechSynthesisUtterance.lang - 别指望改了
lang就自动触发日期格式或翻译弹窗——业务逻辑和可访问性语义是两回事 - 用
innerText动态插入文案时,记得同步设置父元素lang或用aria-label覆盖,否则读屏照旧按旧语种读 -
<canvas></canvas>的 fallback 文本只要出现在 DOM 中且未被aria-hidden="true"或display: none掩盖,就会被读屏捕获并按当前上下文语言朗读 - 后端返回的
lang值可能是zh_ch或ZH-CN,前端必须清洗:转小写、下划线换短横线、校验 BCP 47 合法性,再赋给document.documentElement.lang -
:lang(zh)CSS 伪类能匹配zh-CN,但前提是合法存在;若不生效,先看控制台是否报错,再确认拼写有无空格或下划线 -
hreflang和lang完全无关:前者告诉搜索引擎“还有哪些语言版本”,后者决定屏幕阅读器怎么读这一段文字;hreflang写错会导致整组失效,但不影响当前页面朗读
SPA 动态切换语言时,JS 改 lang 基本没用
屏幕阅读器在 DOM 解析初期就读取了 的 lang,后续 JS 修改(比如 document.documentElement.lang = "en-US")不会触发语音引擎重载或重新分析文本。
立即学习“前端免费学习笔记(深入)”;
容易被忽略的边界场景
最麻烦的不是写错,而是写了但没测——不同 AT 对嵌套 lang 的处理差异极大,尤其在表单、SVG、Canvas fallback 和 JS 动态弹窗里。
真正难的不是语法,而是把 lang 当成和 id 或 class 一样需要严格管理的 DOM 属性——它出现在哪、谁继承谁、谁覆盖谁,都得在组件生命周期里显式维护。



















