【问题标题】:Using variables in property names in LESS (dynamic properties / property name interpolation)在 LESS 中的属性名称中使用变量(动态属性/属性名称插值)
【发布时间】:2013-01-29 20:30:22
【问题描述】:

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

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

有没有办法在 LESS 中使用一些奇怪的功能来复制这个,比如 e() 和 @{ } ?

【问题讨论】:

    标签: css less vendor-prefix


    【解决方案1】:

    更新:LESS >= 1.6

    从 1.6 版开始(参见 changelog)属性名称插值在 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

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

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

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

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

    .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) 让我们定义一个通用的供应商混合(@rest 参数将用于稍后排列多个供应商块)

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

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

    .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*/
    }
    

    输出将全部在一行中。

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

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


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

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

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

    LESS:(使用 Scott 的换行建议):

    @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 测试版中注意到,如果只引入一个变量在 mixin 中,它仍然可以从包含规则集中调用,因此通过一点递归,您可以构造 .vendors 块,并在最后一步将它们分配给一个新变量,然后将其用于注入。我也很兴奋,使用了这个less版本中引入的新的extract()函数。使用变量@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 测试版中运行良好,但让我们看看未来会带来什么。

    【讨论】:

    • +1 以获得创造性的解决方法。我希望they resolve this 很快就不需要这样的解决方法。请注意,如果您将变量定义放入 .test mixin 中,例如 @newline: `"\n"` (注意 \n 字符串是 javascript 处理的),那么您可以将 @{newline} 放入字符串代码中您实际需要换行符的每个位置显示出来,这会将您的代码格式化为不仅仅是一行。
    • 我刚刚注意到 LESS 1.4 不允许这种解决方法(以及我为回答一些问题而做的许多其他事情),因为:variables in mixins no longer 'leak' into their calling scope
    • 好的,我调查了问题并提出了另一种解决方法,适用于 1.4.0 测试版......这个游戏有点有趣,但我认为我的答案已经变成了小说,所以我会退休=)
    • 感谢 1.4 的另一个可行解决方案。如果您向.this-class 添加普通属性,我注意到一个怪癖,它会在第二个.this-class 定义下将其分开。不幸,但并不重要。
    • 看起来是这样,因为我们实际上是通过注入创建了.this-class 的子类。我想如果你不希望它被拆分,你需要将它与其余部分一起注入......通过字符串插值 - 像这样的@p: "@{nl}width:20px; @{nl}height:12px; @{nl}background-color:#fff;" 并将其传递给.muli mixin的@inj参数,或者我猜你可以修改 multi 混合本身,以便它添加任何动态属性,而不仅仅是供应商的。我在上面的最后一个示例中添加了@p,以显示结果。
    【解决方案2】:

    我只是想补充一点,您可以使用“减号”作为属性名称,解析器会忽略它,但会添加字符串的其余部分。这样你就不会得到一个空的 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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-21
      • 1970-01-01
      • 1970-01-01
      • 2011-07-12
      相关资源
      最近更新 更多