Less不支持运行时方向切换,必须在编译期确定;可行方案是用CSS逻辑属性或带.when条件的mixin封装方向规则,并依赖HTML的dir属性生效。

Less 本身不支持运行时方向切换,所有方向逻辑必须在编译期确定;靠 @lang 变量 + 多次 @import 的思路在现代 Less(v4+)中已失效,因为变量作用域和导入顺序无法保证覆盖。真正可行的路径是:用 CSS 自定义属性驱动逻辑属性,或用 Less .mixin 封装方向感知规则,且必须配合 HTML 的 dir 属性生效。
Less 中用 @dir 变量 + @if 生成 LTR/RTL 规则
Less 没有 if() 函数(那是 Sass 的),但支持 .when 条件混合(guarded mixins)。你不能靠一个全局 @dir: rtl 然后到处写 margin-@{dir}——CSS 不认这种拼接,margin-rtl 是非法属性名。
正确做法是把方向映射为具体值,再注入到物理属性中:
.pad-start(@size) when (@dir = ltr) {
padding-left: @size;
}
.pad-start(@size) when (@dir = rtl) {
padding-right: @size;
}
<p>.text-align() when (@dir = ltr) {
text-align: left;
}
.text-align() when (@dir = rtl) {
text-align: right;
}
</p>
使用时直接调用:.pad-start(12px); .text-align();。注意两点:
- 每个方向分支必须显式写出完整 CSS 属性,不能省略单位或值
- 若
@dir未定义或值非法(如ltrr),两个.when都不匹配,样式不会输出——这比静默 fallback 更安全 - 不要在
@each循环里套.when,Less 不支持嵌套条件判断
为什么不能用 @import (multiple) 两次导入同一文件
Less 的 @import (multiple) 并不重置变量作用域。即使你先写 @dir: ltr; 再 @import "styles.less",然后又写 @dir: rtl; 再 import 一次,第二次 import 仍会读取第一次定义的 @dir 值(除非用 @import (reference) 或拆成独立 scope 文件)。
更实际的替代方案是:把 LTR/RTL 分成两个入口文件,分别定义 @dir 后导入共用模块:
// ltr.less @dir: ltr; @import "shared.less"; <p>// rtl.less @dir: rtl; @import "shared.less"; </p>
构建时分别编译出两份 CSS,再由前端根据 document.documentElement.dir 加载对应文件。这是目前最稳定、兼容性最好的方式。
用 CSS 逻辑属性替代 Less 方向变量才是长期解法
Less 编译出来的仍是静态 CSS,而现代浏览器已普遍支持 margin-inline-start、padding-inline-end、text-align: start 等逻辑属性(Chrome 69+、Firefox 63+、Safari 15.4+、Edge 79+)。它们天然响应 dir 属性,无需预编译分支。
所以更推荐的做法是:放弃在 Less 里做方向判断,直接写逻辑属性,并用 HTML dir 控制行为:
.card {
margin-inline-start: 16px; /* 自动适配 ltr/rtl */
text-align: start;
}
只需确保根元素有 ,所有逻辑属性就自动翻转。Less 在这里只负责组织结构,不掺和方向逻辑——这样既减少编译产物体积,也避免因语言检测延迟导致的闪动。
真正容易被忽略的是:第三方组件库(比如 Ant Design、Bootstrap)大多硬编码 margin-left,它们不会因为你改了 dir 就自动适配。要么用 CSS 覆盖重置,要么启用库自带的 RTL 模式(如果提供),别指望 Less 变量能“穿透”进这些外部样式。










