dir属性直接参与Unicode双向算法,决定光标起始、Tab焦点流、数字顺序等;设错层级会导致表单光标异常、Flex主轴不翻转;全局RTL必须从<html>设置,混合文本应使用<bdi>隔离。

dir 属性不是对齐开关,也不是 CSS 替代品;它直接参与 Unicode 双向算法(UBA),决定光标起始、Tab 焦点流、数字顺序、括号方向、Flex 主轴起点——设错层级或值,输入框光标就卡左边,阿拉伯语里的 URL 就被拆成两行还倒着换行。
全局 RTL 必须从 <html> 开始设 dir="rtl"
只在 <body> 或某个 <div> 上加 dir="rtl",会导致:
- 表单控件(
<input>、<select>)光标仍从左入,退格行为异常 - Tab 键焦点流不翻转,用户按 Tab 仍往右跳
-
flex-direction: row不自动起点右移,主轴仍默认左起 - 滚动条卡在右侧(而非 RTL 系统预期的左侧)
正确做法是服务端初始渲染时就输出:<html lang="ar" dir="rtl">;客户端动态切换时用:document.documentElement.dir = "rtl"。别碰 <body dir="rtl">——HTML 规范不认它为根方向源。
混合文本中动态内容必须用 <bdi> 隔离
API 返回的用户名、搜索词、路径或邮箱,方向不可预知,且常混排(如 "أحمد123"、"user@مثال.com")。此时:
立即学习“前端免费学习笔记(深入)”;
-
dir="auto"极不可靠:开头是数字、ASCII 字母、中文或空格 → 强制 fallback 到ltr -
<bdo dir="rtl">会把"123"显示成"321",破坏可读性与复制逻辑 - 显式写
<span dir="ltr">Ahmad123</span>也不行——若父容器是dir="rtl",该 span 仍可能被 UBA 拖入错误上下文
唯一可靠方案:<bdi>{{username}}</bdi>。它创建独立 Bidi 隔离环境,让浏览器按首字符强方向(如 م)判断并隔离标点、数字顺序,同时保持 DOM 原始顺序、复制可用、屏幕阅读器朗读正常。
<bdo dir="rtl"> 不是方向修复工具,只用于强制字符重排
<bdo> 的作用是跳过 UBA,逐字符按指定方向绘制,不是“让阿拉伯语看起来对”。它只在两个场景合理:
- 调试 UBA 行为(比如验证某段文本是否被正确识别为 RTL)
- 实现倒序动效(如
<bdo dir="rtl">Hello</bdo>显示为olleH)
常见误用:
- 给
<input>套<bdo>:破坏光标定位、粘贴逻辑、选区行为 - 用它替代
<div dir="rtl">:导致"مرحبا 123"渲染成"321 اجبهرم"(空格也被翻转) - 指望它做镜像翻转:它不改字形,只改顺序;真要视觉镜像得用
transform: scaleX(-1)+dir="ltr"
别混淆 dir 和 CSS 的 direction / text-align
dir 是 HTML 语义属性,影响底层行为;direction 是样式层控制,仅影响盒内文本流和部分布局:
-
dir="rtl"让<input>光标从右入、Tab 流右→左、justify-content: flex-start指向右侧 -
style="direction: rtl"不改变光标位置,不翻转 Tab 流,不触发完整 RTL 逻辑链 -
text-align: right只是视觉右对齐,括号、冒号方向全错,复制到记事本会乱序
真正该用的是逻辑值:text-align: start、margin-inline-start、inset-inline-start——它们随 dir 自动适配,且现代浏览器支持稳定。物理属性(margin-left、float: left)不会因 dir 自动翻转,必须手动替换。
最难的从来不是加 dir,而是判断哪一层该继承、哪一层该隔离、哪一层该用 <bdi> —— 大多数方向 bug 都出在“以为写了 dir="rtl" 就结束了”,结果阿拉伯语里嵌的英文 URL 被拆断、数字倒序、光标还在左边。



















