必须在元素上设置dir属性才真正生效,且需同步设置lang属性;局部内容须用隔离,表单控件需显式声明dir,dir="auto"生产环境不可靠,css direction不能替代dir。

dir 属性不是“加了就能用”的样式开关,它必须出现在能触发 Unicode 双向算法(UBA)的合法位置,否则光标、输入行为、焦点流、屏幕阅读器解析全都会出错。
必须在 上设 dir="rtl" 才算真正生效
浏览器只在 元素带 dir 属性时,才启用完整的 RTL 感知机制。写成 或 <div dir="rtl"> 是常见错误——旧版 Safari 会直接忽略,导致:<code><input> 光标始终停左边、<textarea></textarea> 退格方向反、<select></select> 下拉项不翻转、滚动条仍在右侧。
正确写法只有这一种:
lang 必须同步设置,否则字体连字、数字样式、语音朗读规则全部失效。
动态切换时,JavaScript 必须成对修改:
document.documentElement.setAttribute("dir", "rtl")document.documentElement.setAttribute("lang", "ar")
dir="auto" 在生产环境基本不可用
dir="auto" 依赖首个“强方向字符”判断方向,但真实数据几乎从不满足条件:
- 开头是数字(
"123 عربي")、ASCII 字母("Hello أهلا")、空格或换行符 → 强制 fallback 到ltr - 开头是中文/日文/韩文(无方向性字符)→ 同样 fallback 到
ltr,不会识别为 RTL - Vue/React 中
v-html或innerHTML初始为空,方向被锁定后不再重算 - 服务端渲染(SSR)时首字符尚未到达,HTML 已发出并被浏览器解析完毕
结论:仅限用户昵称、评论等低风险内联文本,且必须配合 <bdi></bdi> 使用;标题、表单标签、导航栏必须显式写死 dir="ltr" 或 dir="rtl"。
表单控件和混排内容必须单独加 dir
dir 属性可继承,但表单控件(<input>、<textarea></textarea>、<button></button>)内部方向由自身 dir 控制,父级设置不穿透:
- 全局
下,英文输入框仍需写<input dir="ltr"> - 阿拉伯语输入框必须写
<input dir="rtl">,否则退格键行为异常 - API 返回的用户名、搜索词等不确定方向的内容,要用
<bdi>{{username}}</bdi>隔离,而不是靠父容器dir继承
<bdo></bdo> 不是替代方案——它强制字符级反转,会把 "v2.4.1" 显示成 "1.4.2v",仅用于调试或动效,不能用于真实文本。
别指望 CSS 的 direction 替代 dir 属性
direction 只控制行内盒对齐和换行,不触发 UBA,因此无法影响:
-
<input>和<textarea></textarea>中光标起始位置与退格逻辑 -
getSelection()返回的文本偏移量 - Tab 键焦点流顺序(LTR 页面左→右跳,RTL 页面右→左跳)
- 屏幕阅读器对文本逻辑顺序的解析
当 dir 和 direction 同时存在时,dir 永远优先——这是 HTML 规范强制要求。真正在意可访问性和输入体验的项目,dir 是必填项,不是可选项。
真正难的从来不是“怎么加”,而是“在哪一层加”:根元素漏了,整个页面方向逻辑就崩了;局部该隔离没隔离,一段阿拉伯用户名能把整段正文拖进错误方向;表单控件该显式声明却依赖继承,用户一输数字就发现光标乱跳——这些都不是样式问题,是语义缺失。











