31

我注意到用 SASS 编写的 inuit.css 有一个 .vendor 混合:

@mixin vendor($property, $value...){
    -webkit-#{$property}:$value;
       -moz-#{$property}:$value;
        -ms-#{$property}:$value;
         -o-#{$property}:$value;
            #{$property}:$value;
}

有没有办法在 LESS 中使用 e() 和 @{ } 等一些奇怪的功能来复制它?

4

2 回答 2

58

更新:少 >= 1.6

从 1.6 版开始(参见变更日志),属性名称插值在 LESS 中实现。所以你不再需要任何魔法了。(对于旧版本,请参阅我的原始答案。)

您的 mixin 基本上可以按原样工作:

较少的:

.vendor(@property; @value){
    -webkit-@{property}: @value;
       -moz-@{property}: @value;
        -ms-@{property}: @value;
         -o-@{property}: @value;
            @{property}: @value;
}

/*example*/
.test {
    .vendor(transform, translateX(20px));
}

CSS:

.test {
  -webkit-transform: translateX(20px);
  -moz-transform: translateX(20px);
  -ms-transform: translateX(20px);
  -o-transform: translateX(20px);
  transform: translateX(20px);
}

原始答案:LESS < 1.6

就我而言,less 没有添加对动态插入属性的支持,这在之前已经讨论过很多次了,请参阅:

所以它通常的做法是使用参数混合和模式匹配......所以它有点硬编码......但是属性和不同的供应商无论如何有时需要一些不同的参数格式,所以多一点控制以这种方式添加。

解决方法 #1:将动态生成的属性注入到属性值中

解决方法的第一个选项有点难看,但我试过了,它在http://less2css.org上运行。因此,我尝试将动态创建的属性注入到您硬编码的另一个属性的值中(我只是在-inj这里给了一个随机的“供应商”名称并为其分配了值ect,但是如果您可能想要使用有用的东西代替已经在所有供应商 mixin 中添加了一个元素)

.vendors(@property, @value, @pre: ect) {
    -inj:~"@{pre}; -webkit-@{property}: @{value}; -moz-@{property}: @{value}; -ms-@{property}: @{value}; -o-@{property}: @{value}; @{property}: @{value}";
}

我们可以在一个例子上试一试——也许值得一试……让我们尝试一下transform short:

较少的:

.test-class{
    .vendors(transform, matrix(1,0,0,1,20,20));
    .vendors(transform-origin,"10px 10px");
}

CSS 输出:

.test-class {
    -inj: ect; -webkit-transform: matrix(1, 0, 0, 1, 20, 20); -moz-transform: matrix(1, 0, 0, 1, 20, 20); -ms-transform: matrix(1, 0, 0, 1, 20, 20); -o-transform: matrix(1, 0, 0, 1, 20, 20); transform: matrix(1, 0, 0, 1, 20, 20);
    -inj: ect; -webkit-transform-origin: 10px 10px; -moz-transform-origin: 10px 10px; -ms-transform-origin: 10px 10px; -o-transform-origin: 10px 10px; transform-origin: 10px 10px;
}

这似乎产生了有效的css,但感觉有点不对=)


解决方法 #2:将动态生成的属性注入到以下类的名称中(最高 v1.3.3)

所以我对这个想法进行了更多尝试......并想到了一种不会产生不必要属性的方法。它将动态创建的属性注入到下一个类的名称中。让我告诉你我是如何让它工作的:

1)让我们定义一个通用的vendor mixin(该@rest参数将用于稍后排列多个vendor块)

.vendors(@property, @value, @rest:"") {
    @inject:~"@{rest} -webkit-@{property}: @{value}; -moz-@{property}: @{value}; -ms-@{property}: @{value}; -o-@{property}: @{value}; @{property}: @{value};";
}

2)构造一个我们希望供应商包含在其中的虚拟类/规则集,但我们将其作为一个 mixin,最后构造下一个类 - 所以我们确实创建了一个将递归构建两个或多个类的 mixin。例如(使用与上面相同的示例)我们可以编写如下内容(注意@inject在第二次.vendor()调用中使用 将两个供应商块绑定在一起):

.test(@nextclass){
    .vendors(transform, "matrix(2,0,0,2,20,20)");
    .vendors(transform-origin,"10px 10px", @inject);
    (~"{@{inject}} .@{nextclass}"){/*next class properties*/};
}

3)现在我们将这个 mixin 包装到另一个类中以在 css 中显示:

.this-class{
    .test(next-class);
}

生成的CSS将包括:

.this-class {
  -webkit-transform: matrix(2, 0, 0, 2, 20, 20);
  -moz-transform: matrix(2, 0, 0, 2, 20, 20);
  -ms-transform: matrix(2, 0, 0, 2, 20, 20);
  -o-transform: matrix(2, 0, 0, 2, 20, 20);
  transform: matrix(2, 0, 0, 2, 20, 20);
  -webkit-transform-origin: 10px 10px;
  -moz-transform-origin: 10px 10px;
  -ms-transform-origin: 10px 10px;
  -o-transform-origin: 10px 10px;
  transform-origin: 10px 10px;
}
.next-class {
  /*next class properties*/
}

输出将全部在一行中。

编辑:要获得更好的格式,您可以包含 and 的 javascript 插值"\n""\t"请参阅下面评论中 Scott 的建议。

这样,您现在可以使用供应商 mixin 链接多个类,而无需任何不必要的属性。


解决方法 #3:使用递归将动态生成的属性注入到以下类 (v1.4.0) 的名称中

我之所以添加这个原因,是因为 Scott 在其中一个评论中指出,1.4 版带来的更改不允许使用解决方法 #2。但如果我们有一点足智多谋,我们可以克服这个问题。让我们看看上述解决方法的问题是什么并修复它们。

1)第一个问题是“(~".@{index}") { ...不推荐使用选择器插值”,因此我们需要在单独的步骤中进行字符串插值。实现这一点就足以.vendors从上面注入一个 mixin。

少:(使用斯科特的换行建议):

@nl: `"\n\t"`;        
.vendors(@property, @value) {
    @inject:~"@{nl}-webkit-@{property}: @{value};@{nl}-moz-@{property}: @{value};@{nl}-ms-@{property}: @{value};@{nl}-o-@{property}: @{value};@{nl}@{property}: @{value};";
}
.test(@nextclass){
    .vendors(transform, "matrix(2,0,0,2,20,20)");
    @inj: ~"{@{inject}`'\n'`} `'\n'`.@{nextclass}";
    @{inj} {/*next class properties*/}
}
.this-class{
    .test(next-class);
}

CSS 输出:

.this-class {
    -webkit-transform: matrix(2,0,0,2,20,20);
    -moz-transform: matrix(2,0,0,2,20,20);
    -ms-transform: matrix(2,0,0,2,20,20);
    -o-transform: matrix(2,0,0,2,20,20);
    transform: matrix(2,0,0,2,20,20);
} 
.next-class {
    /*next class properties*/
}

2)第二个问题是“mixin 中的变量不再‘泄漏’到它们的调用范围内”,但我注意到在 1.4.0 beta 中,如果一个变量只在 mixin 中引入,它仍然可以从包括规则集,因此只需一点递归,您就可以构造.vendors块,并在最后一步将它们分配给一个新变量,然后将其用于注入。我也很兴奋,使用了extract()这个版本的less引入的新功能。使用变量@i,我们分配递归级别(要注入的供应商块的数量)。

较少的:

@nl: `"\n\t"`; 
.multi(@props,@vals,1,@inj) {
    @property: extract(@props, 1);
    @value: extract(@vals, 1);
    @inject:~"@{inj}@{nl}-webkit-@{property}: @{value};@{nl}-moz-@{property}: @{value};@{nl}-ms-@{property}: @{value};@{nl}-o-@{property}: @{value};@{nl}@{property}: @{value};";
}

.multi(@props,@vals,@i,@inj:"") when (@i > 0) {
    @property: extract(@props, @i);
    @value: extract(@vals, @i);
    @injnext:~"@{inj}@{nl}-webkit-@{property}: @{value};@{nl}-moz-@{property}: @{value};@{nl}-ms-@{property}: @{value};@{nl}-o-@{property}: @{value};@{nl}@{property}: @{value};";
    .multi(@props,@vals,(@i - 1),@injnext);
}

@properties: "transform-origin" "transform";
@values: "10px 10px" "matrix(2,0,0,2,20,20)";

// string of other properties you want to include in the same class
@p: ~"@{nl}width:20px; @{nl}height:12px; @{nl}background-color:#000;";

.this-class {
    .multi(@properties,@values,2,@p);
    @inj: ~"{@{inject}`'\n'`} `'\n'`.next-class ";
    @{inj} {/**/}
}

CSS 输出:

.this-class {
  width:20px;
  height:12px;
  background-color:#000;
  -webkit-transform: matrix(2, 0, 0, 2, 20, 20);
  -moz-transform: matrix(2, 0, 0, 2, 20, 20);
  -ms-transform: matrix(2, 0, 0, 2, 20, 20);
  -o-transform: matrix(2, 0, 0, 2, 20, 20);
  transform: matrix(2, 0, 0, 2, 20, 20);
  -webkit-transform-origin: 10px 10px;
  -moz-transform-origin: 10px 10px;
  -ms-transform-origin: 10px 10px;
  -o-transform-origin: 10px 10px;
  transform-origin: 10px 10px;
}
.next-class {
  /*next class properties*/
}

现在这在 1.4.0 测试版中对我来说效果很好,但让我们看看未来会带来什么。

于 2013-03-15T22:20:06.143 回答
3

我只是想补充一点,您可以使用“减号”作为属性名称,解析器会忽略它,但会添加字符串的其余部分。这样你就不会得到一个空的inject:;或 inj 属性。它仍然很老套,但是嘿...... :)

.prefix(@property, @value) {
    -:~";-webkit-@{property}: @{value}; -moz-@{property}: @{value}; -ms-@{property}: @{value}; -o-@{property}: @{value}; @{property}: @{value}";
}

例子:

.prefix(transition, "all .2s, color 0s");

将输出:

-webkit-transition: all .2s, color 0;
-moz-transition: all .2s, color 0;
-ms-transition: all .2s, color 0;
-o-transition: all .2s, color 0;
transition: all .2s, color 0;
于 2013-06-10T03:40:08.487 回答