lang 属性必须设在 标签上才生效,影响整页语言基调;dir 属性控制文本逻辑方向并触发 unicode 双向算法,二者作用域不同、不可替代,动态切换时需同步更新 document.documentelement.lang 和 dir。

lang 属性必须写在 标签上
不设在根元素,等于没设。浏览器、搜索引擎、屏幕阅读器只认 这个位置的 lang 值作为整页语言基调——其他地方的 lang 只影响局部。
常见错误包括:
- 只给
或某个<div> 加 <code>lang="ar",结果自动翻译仍按中文处理,语音朗读用普通话引擎读阿拉伯语 - 后端返回
lang="ZH-CN"或lang="zh_ch",浏览器直接忽略(BCP 47 要求小写+连字符) - SPA 切换语言时只更新 state,没执行
document.documentElement.lang = "he-IL",已挂载的<p></p>元素仍用旧lang值参与拼写检查和字体回退 - SSR 页面:根据
Accept-Language头输出对应 - 静态多语言站:每个语言版本用独立 HTML 文件,
lang硬编码 - 局部内容(如引文、代码块)必须显式加
lang:<blockquote lang="fr">Merci</blockquote>,不能依赖继承 - 阿拉伯语站点必须设
,否则<input type="text">光标默认在左侧,用户输入第一个字符就错位 - 中文页面嵌一段希伯来语:
<p dir="rtl">שלום עולם</p>,不加dir仅靠 CSS,标点会包裹错误、数字顺序颠倒 -
dir="auto"在首字符为 ASCII 字母或数字时一律 fallback 到ltr,哪怕后面全是阿拉伯文——线上项目慎用 -
<p lang="ar" dir="rtl">مرحبا</p>合理:阿拉伯语 + RTL 方向 -
<p lang="en" dir="rtl">Hello</p>不合理但合法:英语内容强制 RTL 排版,光标从右起,但语音仍用英语引擎读——仅用于调试或特殊设计 - 混排内容(如阿拉伯用户名含英文)必须用
<bdi></bdi>隔离:<span><bdi>{{username}}</bdi></span>,否则可能拖垮整个容器的方向上下文 - 不要给
<input type="number">设dir="rtl":数字输入框本身不支持 RTL 逻辑,反而导致光标跳变和退格异常 -
document.documentElement.lang—— 影响语音、拼写、SEO -
document.documentElement.dir—— 影响光标、Tab 流、Flex 主轴、滚动条位置
实操建议:
dir 属性不是 CSS direction 的替代品
dir 是 HTML 原生属性,作用是告诉浏览器「这段文本的逻辑书写方向是什么」,它触发 Unicode 双向算法(UBA),直接影响光标位置、Tab 焦点流、<input> placeholder 渲染、<select></select> 下拉项顺序等底层行为。
direction: rtl 只控制行内对齐,不改 UBA 上下文,也不影响表单控件内部逻辑。
典型场景:
lang 和 dir 混用时的隔离边界
二者作用域不同:lang 影响语音合成、拼写检查、字体 fallback;dir 影响文本流解析与交互行为。它们可以共存,但不能互相替代或推导。
关键规则:
动态切换时最容易漏掉的同步点
用户点击语言切换按钮后,只改了 UI 文案,却忘了同步两个关键 DOM 属性:
漏掉任一,就会出现「文字翻过来了,但输入框光标还在左边」「朗读用日语引擎读中文」这类割裂现象。
注意:element.hidden 是布尔值,element.hasAttribute('hidden') 无法反映 JS 动态设置后的状态;同理,element.dir 返回当前生效值,而 element.getAttribute('dir') 可能为空字符串或旧值——查状态优先用属性访问器,别查 attribute。
真正难的不是加属性,而是判断哪一层该继承、哪一层该隔离、哪一层该用 <bdi></bdi> 或 <bdo></bdo> 显式覆盖。多数线上 bug 都卡在“以为设了 dir 就全好了”,结果双向混排一动就崩。











