必须在<html>上设dir="rtl",否则光标、Tab流、Flex轴向、滚动条位置等关键行为不翻转;混排内容须用<bdi>隔离,CSS需用逻辑属性替代物理值,且lang必须同步设置。

只在 <html> 上加 dir="rtl" 不够,多数 RTL 布局 bug 都出在这里——光标错位、表单按钮顺序没翻、阿拉伯语里的英文链接被拆成两行还反向换行,根本原因是方向控制没分层,语义、隔离、样式三者没对齐。
必须从 <html> 设置 dir,否则底层行为全乱
浏览器只在根元素有 dir 时才触发完整的 Unicode 双向算法(UBA),影响光标起始位置、Tab 焦点流、<input> 默认插入点、flex-direction: row 的主轴起点、滚动条默认位置。局部加 dir="rtl" 到 <body> 或某个 <div>,会导致:
-
<textarea>光标仍从左入,退格键行为异常 - 第三方 UI 库(如 MUI、Bootstrap)的间距类名(
ms-2→me-2)不生效,图标跑到文字右边甚至溢出 - 服务端渲染(SSR)初始 HTML 没带
dir,hydration 后方向不一致,React/Vue 组件状态错位
正确写法:<html dir="rtl" lang="ar-SA">,且服务端必须初始输出该结构;客户端动态切换时,只改 document.documentElement.dir,不要碰 body 或子节点。
混排内容必须用 <bdi> 隔离,dir="auto" 在生产环境几乎不可靠
dir="auto" 依赖首字符强方向性(如阿拉伯字母 U+0600–U+06FF),但遇到数字、ASCII 符号、中文、空格、变音符号时,Chrome/Safari 行为不一致,JS 动态插入后也不重算。它只适合低风险评论框,绝不能用于关键文案或 URL。
立即学习“前端免费学习笔记(深入)”;
- ❌ 错误:
<p dir="rtl">خطأ: file.txt</p>→ 点号.被卷入 RTL 流,显示为file.txt的.跑到左边 - ✅ 正确:
<p dir="rtl">خطأ: <bdi>file.txt</bdi></p>→file.txt强制独立跑 UBA,保持 LTR 逻辑 -
<bdi>不接受dir属性,加了会关闭自动探测;旧版 Safari(13.0 及更早)对dir="auto"支持差,但<bdi>从 13.1+ 起稳定
动态插入文本时,优先用 textContent 创建 <bdi> 节点,而非 innerHTML 直接拼字符串——后者绕过 DOM 构建阶段的 UBA 触发。
CSS 必须用逻辑属性替代物理值,dir="rtl" 不会自动翻转 margin-left
dir="rtl" 只翻转文本流、text-align: start 含义、Flex/Grid 主轴起点、表单控件图标位置,但以下物理属性完全不翻转:
-
margin-left→ 改用margin-inline-start -
padding-right→ 改用padding-inline-end -
left: 10px(绝对定位)→ 改用inset-inline-start: 10px,或兼容写法::dir(rtl) { right: 10px; } -
float: left→ 改用float: inline-start(Safari 15.4+ 才可靠,旧版需降级) -
text-align: right→ 改用text-align: end,并淘汰所有left/right值
切忌手动加 flex-direction: row-reverse——若容器已设 dir="rtl",再加该声明会造成双重反转。PostCSS 插件(如 postcss-logical)可为旧浏览器生成 fallback。
lang 和 dir 必须共存,缺一不可
只写 dir="rtl" 但漏掉 lang,会导致:
- Safari 对
text-align: start解析不一致 - 屏幕阅读器朗读顺序错乱(
lang决定语音引擎选词规则) -
:dir(rtl)伪类匹配失败(Safari ≤17.3 不支持,需回退用[dir="rtl"])
dir 和 lang 各司其职:dir 告诉浏览器“怎么排”,lang 告诉辅助技术“读什么”。正确写法:<html dir="rtl" lang="ar-SA"> 或 <html dir="ltr" lang="zh-CN">。嵌入 LTR 片段(如代码块、URL)时,直接用 <pre dir="ltr"> 或 <div dir="ltr">,别依赖 CSS。
真正难的不是加 dir,而是判断哪一层该继承、哪一层该隔离、哪一层该用 <bdi> —— 大多数方向 bug 都出在“以为设了 dir="rtl" 就结束了”,结果输入框光标还在左边,或者阿拉伯语里的英文 URL 被拆成两行还反向换行。



















