1

是否有可能在 LESS 中将一个 mixin 嵌套在另一个 mixin 中,以便只有当元素是具有后者 mixin 的元素的子元素时才调用前者?

我知道,令人困惑,这是一个简单的例子(不是工作代码,只是概念):

较少的

.foo(@x) {
    width: @x;

    .foo(@y) {
        width: @y/@x;
    }
}

.a {
    .foo(20px);

    .b { 
        .foo(2);
    }
}

输出 CSS

.a {
    width: 20px;
}

.a .b {
    width: 10px;
}

当我这样做时,调用.foo(2).b编译为width: 2.

这应该是设计使然,还是我的语法有问题?另外,我是否从一个完全错误的角度来解决这个问题,并且可能有一个我没有考虑的更简单的解决方案?

编辑

好的,显然,最新版本的 LESS 已经解决了这个问题,不过,我想要实现的目标比我上面给出的最小示例稍微复杂一些。

基本上我想要发生的是,.foo作为另一个元素的子元素的每一个都.foo将使用它的父变量进行计算,所以,理想情况下

较少的

.foo(@x) {
    width: @x;

    .foo(@y) {
        width: (@x/@y);
    }
}

.a {
    .foo(100px);

    .b { 
        .foo(2px);

        .c {
            .foo(5px);
            /* ...and so on */
        }
    }
}

输出 CSS

.a {
    width: 100px;
}

.a .b {
    width: 50px;
}

.a .b .c {
    width: 10px;
}

我得到的是,相反:

.a .b .c {
    width: 50px;
}

我试图修改LESS如下:

.foo(@x) {
    width: @x;

    .foo(@y) {
        @x:    (@x/@y)
        width: (@x);
    }
}

但是我得到递归变量定义的语法错误。显然 LESS 不允许定义如下:

@a: 1;
@a: (@a+1);
4

1 回答 1

5

我认为这里的主要问题是@y/@x. 尝试一下@x/@y,它应该会给人更多的期望;-)

由于嵌套的 mixin 在不同的 less 实现中得到不同的解释,我现在将答案分为两部分:

1. 使用 LESS >1.3.1 在less2css.org 上工作的解决方案(使用您的嵌套混合)

否则,我认为上面的代码实际上在 less2css.org 上做了你想要的。正如 LESS 1.4 中的一个概念,您需要小心数学,因为默认情况下它需要放在括号中。

如果你现在只是在非嵌套规则上调用这样的 mixin,比如

.b { .foo(@y); }

你需要在输入变量中使用单位,或者unit()在你的 mixin 中使用广告,否则你只会得到你输入的数字,例如 2:

.foo(@x) {
    width: unit(@x,px);
    .foo(@y) {
        width: (@x/@y);
    }
}

.a {
    .foo(20px);
    .b{
        .foo(2);
     }
}
.c {
    .foo(2);
}

将输出CSS:

.a {
  width: 20px;
}
.a .b {
  width: 10px;
}
.c {
  width: 2px;
}

如果子类中的属性以像素为单位,您可以变得更加花哨,并检查守卫,以便您还可以嵌套不传递因子的类:

.foo(@x) {
    width: @x;
    .foo(@y) when (ispixel(@y)) {
        width: @y;
    }
    .foo(@y) when not (ispixel(@y)) {
        width: (@x/@y);
    }
}

然而,测试这个嵌套的 mixin 解决方案似乎只在 less2css.org 上工作,而不是在 jsbin.com、lesstester.com 和其他一些服务[你需要调用嵌套(第二)级别的 mixin.foo .too以应用第二级来自 mixin 的样式]。

所以我提出了一种替代方法,我测试过它似乎可以在所有提到的页面上使用 less-css 编译器,小于 >1.2。

2. 使用防护装置的解决方案ispixel应该适用于大多数 LESS >1.2 安装

您可以构建两个 mixin,而不是嵌套的 mixin,它们基于以检查像素为单位的警卫。

  • 如果属性@x以像素为单位 => 返回width:@x;并分配@x给变量@width
  • 如果属性@x不是像素=>返回width:@width/@x;注意: @width需要先通过调用mixin来@x分配px

示例更少:

.foo(@x) when (ispixel(@x)) {
        width:@x;
        @width:@x;
}
.foo(@x) when not (ispixel(@x)) {
        width: (@width/@x);
}


.a, .b {
  background-color: #ddd;
  height: 100px;
}
.a {
  .foo(100px);
  .b {
    background-color: red;
    .foo(2);
  }
}

输出CSS

.a, .b {
  background-color: #ddd;
  height: 100px;
}
.a {
  width: 100px;
}
.a .b {
  background-color: red;
  width: 50px;
}

与您的方法不同,但可能更直接一些,并且似乎效果很好。

编辑:

因此,由于您不想区分带单位的输入和不带单位的输入,我只能考虑调用两个参数 mixin,其中一个参数用于基础(width在您的情况下),第二个参数用作默认值到 1. 你现在可以递归调用任意多次。

较少的:

.foo(@x,@y:1){
    width:unit(@parent,px);
    @parent:(@x/@y);
}


.a {
    .foo(100px);
    .b{
        .foo(@parent,2px);
        .c{
            .foo(@parent,5px);
            .d{
                .foo(@parent,0.05);
            }
        }
    }
}

输出CSS:

.a {
  width: 100px;
}
.a .b {
  width: 50px;
}
.a .b .c {
  width: 10px;
}
.a .b .c .d {
  width: 200px;
}

因此,现在输入具有什么单位并不重要,因为您可以在 mixin 中为输出分配所需的单位。当您调用 mixin 时,它会覆盖@parent当前范围的变量,然后将其继承到嵌套规则,您可以@x在再次调用 mixin 时将其用作宽度参数。这应该会给你想要的结果。

于 2013-04-14T05:57:22.237 回答