dir 属性声明文本逻辑书写方向而非控制对齐,必须在 根节点设置 dir="rtl" 才真正启用 rtl;局部设置无效,表单控件需单独声明,混排文本应使用 隔离双向算法。

dir 属性不是“让文字右对齐”的 CSS 替代品,而是告诉浏览器「这段文本的逻辑书写方向是什么」。只加 style="direction: rtl",input 光标仍停左边、阿拉伯语数字顺序错乱、Tab 键焦点流不翻转——这些都不是样式问题,是逻辑方向没声明。
必须在 上设 dir="rtl" 才算真正启用 RTL
局部加 dir="rtl" 到某个 <div> 或 <code><p></p>,解决不了根本问题:
-
<input type="text">依然按 LTR 处理光标起始位和退格行为 - Flex 容器的主轴起点不会自动移到右侧,
flex-direction: row不会等效于row-reverse - 屏幕阅读器仍按 LTR 解析语句顺序,可访问性失效
-
是无效写法,规范只认
正确做法:直接修改 HTML 文档根节点:。注意 lang 和 dir 要配套使用,但不可互相替代。
dir="auto" 在生产环境基本不可靠
dir="auto" 的判断逻辑极其简单粗暴:只看第一个「强方向字符」,且只看一次,不重算。现实数据几乎总踩中它的失效条件:
- 首字符是数字(
"123 أهلا")、ASCII 字母("Hello عالم")、空格或换行符 → 强制 fallback 到ltr - 首字符是中文/日文/韩文(如
"你好 أهلا")→ 这些属于中性字符,同样 fallback 到ltr - JS 动态插入内容(
el.innerHTML = data)后,方向锁定,不再重新检测 - Vue/React 中初始值为空或含占位符,
dir="auto"一上来就判成ltr,后续更新也不触发修正
结论:dir="auto" 只适合低风险、纯展示型内联文本(比如用户评论昵称预览),绝不能用于表单字段、标题、导航栏等关键区域。
混排文本(如阿拉伯用户名 + 英文 URL + 数字)必须用 <bdi></bdi>
当内容来自 API、不可控、可能混排时,dir 继承或显式设置都会污染上下文或翻转数字顺序。例如:<p dir="rtl">أحمد https://example.com 123</p> 中的 URL 和数字可能被错误重排。
- ✅ 正确隔离:
<bdi>{{username}}</bdi>—— 创建独立 Bidi 上下文,不影响父级,也不强制翻转数字 - ❌ 错误依赖:
{{username}}—— 首字符是英文或数字时方向错,还可能把整个容器拖进错误流向 - ❌ 强制覆盖:
<bdo dir="rtl">{{username}}</bdo>—— 把"123"显示成"321",仅限调试
<bdi></bdi> 是 HTML5 原生语义标签,所有现代浏览器支持良好,不需要 polyfill。它不改变视觉对齐,只隔离双向算法作用域——这才是处理动态混排文本的真实解法。
表单控件必须单独加 dir,不能只靠继承
哪怕 已设,<input> 和 <textarea></textarea> 仍需显式声明方向,否则输入行为异常:
-
<input type="text" dir="rtl">才能让光标默认停在右侧,退格键从右往左删 -
<textarea dir="rtl"></textarea>才能保证 placeholder 渲染、粘贴英文 URL 后顺序正常 -
<select></select>下拉项文本方向也受其自身dir控制,不继承父容器 - 表格单元格(
<td>)里嵌套 RTL 文本时,若里面还有 <code><input>,必须再给<input>单独加dir="rtl",否则光标仍在左最容易被忽略的是:第三方 UI 组件(如 Bootstrap 表单、Ant Design 输入框)通常不主动适配
dir,需要你手动在组件外层或 slot 内补上dir属性,否则方向逻辑就断在组件边界了。











