必须在<html>元素上设dir="rtl",因为浏览器仅在根元素带dir属性时才完整启用Unicode双向算法(UBA),否则光标错乱、Tab顺序反、滚动条位置错误、select下拉不翻转等问题无法通过CSS或局部dir修复。

必须在 <html> 元素上显式设置 dir="rtl" 或 dir="ltr",否则表单光标、Tab 焦点流、Flex 主轴起点、滚动条位置等关键行为不会真正适配 RTL —— 仅靠 CSS direction 或局部 dir 是无效的。
为什么 <html dir="rtl"> 不是可选项,而是强制前提
浏览器只在根元素(<html>)带 dir 属性时,才完整启用 Unicode 双向算法(UBA)的 RTL 感知机制。漏掉这一步,后续所有“补救”都会失效:
-
<input>和<textarea>光标默认停在左侧,用户输入第一个阿拉伯字符就错位 - Tab 键焦点仍按 LTR 顺序从左到右跳,不符合 RTL 用户直觉
-
flex-direction: row不会自动将主轴起点设为右侧,导致布局逻辑错乱 - 滚动条卡在右侧(即使系统支持 RTL),
<select>下拉项方向也不翻转 -
lang必须同步设置,例如<html lang="ar" dir="rtl">;否则字体连字、数字样式、屏幕阅读器语音规则均不生效
dir="auto" 在哪些场景一定失效
dir="auto" 依赖首个“强方向字符”判断方向,但真实数据几乎总不满足条件:
- 开头是数字(
"123 عربي")、ASCII 字母("Hello أهلا")、空格或换行符 → 强制 fallback 到ltr - 开头是中文/日文/韩文(无方向性字符)→ 同样 fallback 到
ltr,不会识别为 RTL - Vue/React 中
v-html或innerHTML初始为空或含占位符,方向被锁定后不再重算 - 服务端渲染(SSR)时首字符尚未到达,HTML 已发出并被浏览器解析完毕
-
<textarea dir="auto">的 placeholder 渲染时内容为空,光标默认停在左侧
结论:线上项目中,dir="auto" 应视为不可用;关键文案、表单标签、导航项必须显式指定 dir="ltr" 或 dir="rtl"。
立即学习“前端免费学习笔记(深入)”;
混合文本该用 <bdi>,而不是 dir="auto" 或 <bdo>
当一段内容来自 API(如用户名、搜索词),方向不确定且可能混排(如 "أحمد123"),必须用 <bdi> 隔离:
<p dir="rtl">النص بالعربية <bdi>https://example.com</bdi></p>
<bdi> 创建独立 bidi 环境,避免污染父级方向,也解决标点重排错误。而以下写法是危险的:
-
<span dir="auto">{{username}}</span>—— 首字符不可控,极易误判 -
<span>{{username}}</span>—— 不触发隔离,可能把整个容器拖进错误方向 -
<bdo dir="rtl">{{username}}</bdo>—— 强制覆盖,会把"123"显示成"321",仅适合调试
<bdi> 是 HTML5 原生语义标签,所有现代浏览器支持良好,无需 polyfill。
CSS 方向相关属性不会随 dir 自动翻转
dir="rtl" 会翻转文本对齐、Flex 主轴起始、Grid 的 justify-content 含义,但以下物理属性完全不受影响,必须手动处理:
-
margin-left/padding-right→ 改用margin-inline-start/padding-inline-end -
float: left→ 改用float: inline-start(或降级用:dir(rtl) { float: right; }) -
left: 10px(绝对定位)→ 改用inset-inline-start: 10px,或兼容写法::dir(rtl) { right: 10px; } -
background-position: left top→ 改用background-position: inline-start top -
text-align: right→ 改用text-align: end(推荐始终用start/end,而非left/right)
注意:flex-direction: row-reverse 是常见误操作 —— 若容器已设 dir="rtl",再手动加该声明会造成双重反转。
真正难的不是加 dir,而是判断哪一层该继承、哪一层该隔离、哪一层该用 <bdi> —— 大多数方向 bug 都出在“以为加了 dir="rtl" 就结束了”,结果阿拉伯语里的英文 URL 被拆成两行还反向换行,或者表单光标还在左边。



















