:dir() 不是自动镜像开关,仅提供方向条件,镜像逻辑需手动实现;它只匹配计算后 dir 为 rtl 的元素,依赖显式 dir="rtl" 或强 rtl 字符推断,lang 属性无效;ssr 未注入 dir 属性会导致样式失效;优先使用逻辑属性(如 margin-inline-start),物理属性需配合 :dir(ltr)/:dir(rtl) 双写;避免与 [dir="rtl"] 混用及第三方库全局 rtl 冲突。

:dir() 不是自动镜像开关,它只提供方向条件,镜像逻辑必须你手动写。直接加 :dir(rtl) { margin-right: 16px; } 不会“自动翻转”,反而可能在 RTL 下把间距加错边——真正起作用的是你是否用对了属性和上下文。
为什么写了 :dir(rtl) 但样式不生效
常见错误是以为浏览器会“猜”方向。它不会。:dir(rtl) 只匹配计算后方向为 rtl 的元素,而计算依据只有两个:HTML 中显式写的 dir="rtl"(如 ),或浏览器根据强 RTL 字符(如阿拉伯字母、希伯来字母)自动推断(Chrome/Firefox 支持,Safari ≤15.3 不可靠)。
-
lang="ar"或lang="he"完全不影响:dir()匹配,别混用 -
SSR页面若服务端没注入dir属性(比如模板默认输出而非),那客户端JS后续加dir也晚了——CSS已解析完毕,:dir(rtl)规则压根没进匹配队列 - 局部设
或<div dir="rtl"> 不够:旧版 <code>Safari和部分表单控件(如<input>光标、选区)要求必须从开始设dir="rtl"才能触发完整 RTL 感知机制:dir(rtl)配合什么 CSS 属性最有效优先用逻辑属性,物理属性仅作兜底。
- 间距/边距类:用
margin-inline-start/margin-inline-end替代margin-left/margin-right,它们天然响应方向,无需:dir() - 图标翻转:
transform: scaleX(-1)没有逻辑等价物,必须靠:dir(rtl)控制:.icon:dir(rtl) { transform: scaleX(-1); } - 浮动/定位:优先用
float: inline-start比float: left更安全;但若必须用物理值,就写两套:.sidebar:dir(ltr) { left: 0; }.sidebar:dir(rtl) { right: 0; } - 慎用
text-align:它本身已响应direction,单独写text-align: right在:dir(rtl)里是冗余的;真要覆盖,优先改direction或用text-align: start
容易踩坑的混用场景
多个方向控制机制叠在一起,优先级和继承关系极易失控。
- 避免同时存在
[dir="rtl"] .btn和.btn:dir(rtl):前者只认硬编码属性,后者认计算方向,两者来源不同、匹配范围不同,CSS优先级又一样,调试时根本分不清谁覆盖了谁 - 别在全局
下直接套用第三方组件库(如Bootstrap、Ant Design):它们多数按ltr假设写死padding-left、margin-right,一开RTL就错位。更稳妥的是只给内容区加dir="rtl",UI组件保持ltr基线 + 用CSS自定义属性隔离方向逻辑 -
:dir(rtl)不能嵌套使用,比如div:dir(rtl) span:dir(ltr)是无效的;子元素若显式设dir="ltr",它自己会匹配:dir(ltr),但父选择器不会“穿透”
真正难的不是加
:dir(),而是判断哪一层该加、哪一层该隔离、哪一层该用逻辑属性替代——多数 bug 都出在“以为加了dir就万事大吉”,结果双向文本卡在中间不动,或者滚动条突然出现在左边却没配好overflow-x。 - 间距/边距类:用











