【问题标题】:Less CSS: Mixins with Variable Number of Arguments更少的 CSS:具有可变数量参数的 Mixins
【发布时间】:2012-07-10 07:24:47
【问题描述】:

LESS 允许参数混合,例如:

.transition(@property, @duration){
    transition:         @property @duration;
    -moz-transition:    @property @duration; /* Firefox 4 */
    -webkit-transition: @property @duration; /* Safari and Chrome */
    -o-transition:      @property @duration; /* Opera */
}

但是,这并不总是适用于转换等属性。如果您尝试进行多个转换并尝试多次调用 mixin,则最后一个 mixin 会覆盖所有先前定义的转换。这是因为定义多个过渡的正确 CSS3 语法是:

... {
    transition: @property1 @duration1, @property2 @duration2, ...;
}

我能想到的将多个转换定义为 mixin 的唯一方法是重载 mixin:

.transition(@property, @duration){...}
.transition(@property, @duration, @prop2, @dur2){...}
.transition(@property, @duration, @prop2, @dur2, @prop3, @dur3){...}

是否有更健壮和简洁的方式来定义过渡混合以接受可变数量的参数并构造适当的过渡 CSS?

上下文: 有时我想在多个属性上进行过渡;例如,:hover 可能会触发背景颜色、框阴影、文本颜色等的转换...

【问题讨论】:

    标签: css less css-transitions less-mixins


    【解决方案1】:

    我认为这应该可行:

    .transition(...) {
        transition:         @arguments;
        -moz-transition:    @arguments; /* Firefox 4 */
        -webkit-transition: @arguments; /* Safari and Chrome */
        -o-transition:      @arguments; /* Opera */
    }
    

    ... - 是一种有效的 less 语法,而不是要替换的东西。

    【讨论】:

    • 对我不起作用,至少在我的 *box-shadow 案例中。在生成的 CSS 中缺少逗号。 @Warappa 的回答对我有用。
    • 确实如此。这看起来很整洁,但最终结果是无效的。 “@arguments”占位符扩展为空格连接的参数列表,而不是逗号分隔。
    【解决方案2】:

    注意:添加此答案并不是为了说明现有答案不正确或已过时。所有答案都是有效的,并且仍然有效。这只是提供了一种不同的方法,在我看来,它更复杂一些,但在如何将每个参数称为键值对方面也更灵活。

    使用此方法的优点:当需要对值执行任何额外操作时(例如将unit 添加为degpx或执行任何额外的数学运算等)或动态添加 @property 的供应商前缀。例如,有时您可能只想将transform 作为输入属性传递给mixin,但想为-webkit-transition 添加-webkit-transform,为-moz-transform 添加-moz-transform 等。

    在这个方法中,我们利用了... 特性,它允许我们将可变数量的参数传递给mixin,循环遍历传递的每个参数,extract 属性的名称以及附加参数(如持续时间、旋转度数等),然后使用 Less 提供的 merge feature 连接为属性指定的值。

    • +: 用逗号连接属性值,并在 Less v1.5.0 中引入
    • +_: 将属性值与空格连接起来,并在 Less v1.7.0 中引入。
    .transition(@args...){
        .loop-args(@argCount) when (@argCount > 0) {
            .loop-args(@argCount - 1);
            @arg: extract(@args, @argCount);
            @property: extract(@arg,1);
            @duration: extract(@arg,2);
            -webkit-transition+: @property @duration;
            -moz-transition+: @property @duration;
            -o-transition+: @property @duration;
            transition+: @property @duration;
        }
        .loop-args(length(@args));    
    }
    
    div{
        .transition(background, 1s; border-color, 2s; color, 2s);
    }
    
    .transform(@args...){
        .loop-args(@argCount) when (@argCount > 0) {
            .loop-args(@argCount - 1);
            @arg: extract(@args, @argCount);
            @property: extract(@arg,1);
            @param: extract(@arg,2);
            -webkit-transform+_: ~"@{property}(@{param})";
            -moz-transform+_: ~"@{property}(@{param})";
            -o-transform+_: ~"@{property}(@{param})";
            transform+_: ~"@{property}(@{param})";
        }
        .loop-args(length(@args));    
    }
    
    div#div2{
        .transform(rotate, 20deg; scale, 1.5; translateX, 10px);
    }
    

    上面的代码编译后会产生以下输出:

    div {
        -webkit-transition: background 1s, border-color 2s, color 2s;
        -moz-transition: background 1s, border-color 2s, color 2s;
        -o-transition: background 1s, border-color 2s, color 2s;
        transition: background 1s, border-color 2s, color 2s;
    }
    div#div2 {
        -webkit-transform: rotate(20deg) scale(1.5) translateX(10px);
        -moz-transform: rotate(20deg) scale(1.5) translateX(10px);
        -o-transform: rotate(20deg) scale(1.5) translateX(10px);
        transform: rotate(20deg) scale(1.5) translateX(10px);
    }
    

    相关答案:

    • Here 是来自 seven-phases-max 的答案,它详细解释了如何使用此方法自动添加供应商前缀,就像我在优势段落中提到的那样。

    【讨论】:

      【解决方案3】:

      从 LESS 1.4 开始,文档 (http://lesscss.org/features/#mixins-parametric-feature-mixins-with-multiple-parameters) 提出了处理此问题的正确方法:

      使用逗号作为 mixin 分隔符使得无法创建逗号 分隔列表作为参数。另一方面,如果编译器 在 mixin 调用或声明中看到至少一个分号,它 假定参数由分号和所有逗号分隔 属于 css 列表:

      具体来说,mixin

      .transition(@prop-or-props) {
          -webkit-transition: @prop-or-props;
             -moz-transition: @prop-or-props;
               -o-transition: @prop-or-props;
                  transition: @prop-or-props;
      }
      

      用法

      .transition(opacity .2s, transform .3s, -webkit-transform .3s;);
      

      请注意,多个属性用逗号分隔,结尾的分号导致逗号分隔的列表在 mixin 中被视为单个参数。

      使用rest... 参数定义mixin 并能够提取任意长度参数的每个元素以进行单独处理会更好,但我正在考虑的用例是添加供应商前缀来转换转换(所以我可以简单地用.transition(opacity .2s, transform .3s) 调用它并自动添加-webkit-transform 位),也许这最好由不同的实用程序来处理(例如gulp-autoprefixer)。

      【讨论】:

      • >用 rest... 参数定义 mixin 并能够提取每个元素会更好 - 请参阅 stackoverflow.com/q/21061361/2712740 (但正如我最近所说的那样,它更像是浪费时间,自动前缀工具现在是我们最好的朋友)。
      • @seven-phases-max:对不起,伙计,我看到了这个答案和最后一段,但没有注意到您的评论和其中的链接答案。希望你不介意我的回答。
      【解决方案4】:

      更新 LESS 1.3.3+

      输出是相同的,但请注意在新版本的 LESS 中通过使用分号而不是转义字符串来传递属性的方式有所不同:

      @prop1: color;
      @prop2: opacity;
      @dur1: 3s;
      @dur2: 4s;
      
      .transition(@transString: 0) when not (@transString = 0) {
          transition:         @transString;
          -moz-transition:    @transString; /* Firefox 4 */
          -webkit-transition: @transString; /* Safari and Chrome */
          -o-transition:      @transString; /* Opera */
      }
      
      .class1 {.transition();}
      .class2 {.transition(width 2s, height 2s;);}
                                              ^
                                         semicolon here
      .class3 {.transition(@prop1 @dur1, @prop2 @dur2;);}
                                                     ^
                                               semicolon here
      

      分号强制将逗号作为列表分隔符而不是参数分隔符进行计算。

      LESS pre 1.3.3 的一种解决方案

      我们将正确的属性参数构建为 transition 的字符串,然后使用转义值 (~) 运算符将其转换为所需的专有语法。通过使用字符串插值(@{variableName}),我们甚至可以将变量嵌入到进程中,但实际输入需要采用转义字符串的形式。

      LESS 代码

      @prop1: color;
      @prop2: opacity;
      @dur1: 3s;
      @dur2: 4s;
      
      .transition(@transString: 0) when not (@transString = 0) {
          transition:         @transString;
          -moz-transition:    @transString; /* Firefox 4 */
          -webkit-transition: @transString; /* Safari and Chrome */
          -o-transition:      @transString; /* Opera */
      }
      
      .class1 {.transition();}
      .class2 {.transition(~" width 2s, height 2s");}
      .class3 {.transition(~" @{prop1} @{dur1}, @{prop2} @{dur2}");}
      

      CSS 输出

      注意:没有.class1 被输出,因为保护表达式确保输入了某些内容(尽管它不能防止不正确的输入)。

      .class2 {
        transition: width 2s, height 2s;
        -moz-transition: width 2s, height 2s;
        -webkit-transition: width 2s, height 2s;
        -o-transition: width 2s, height 2s;
      }
      .class3 {
        transition: color 3s, opacity 4s;
        -moz-transition: color 3s, opacity 4s;
        -webkit-transition: color 3s, opacity 4s;
        -o-transition: color 3s, opacity 4s;
      }
      

      【讨论】:

        【解决方案5】:

        在 LESS 中,您可以使用逗号或分号分隔参数。对于包含逗号的单个值,您可以用分号终止该单个值,以便将列表作为单个值发送,如下所示:

        .class {
          .background-size(100%, auto;);
        }
        

        对于多个值,只需使用以下语法:

        /* Example mixin */
        .set-font-properties(@font-family, @size) {  
          font-family: @font-family;
          font-size: @size;
        }
        /* Usage with comma-separated values */
        .class {
          .set-font-properties(Arial, sans-serif; 16px);
        }
        
        /* Output */
        .class {
          font-family: Arial, sans-serif;
          font-size: 16px;
        }
        

        简单易懂!

        【讨论】:

          【解决方案6】:

          在这里查看我的答案:Multiple properties are getting treated as separate arguments in mixins

          总结:将此 mixin 用于可变数量的参数:

          .transition (@value1,@value2:X,...)
          {
              @value: ~`"@{arguments}".replace(/[\[\]]|\,\sX/g, '')`;
          
              -webkit-transition: @value;
              -moz-transition: @value;
              -ms-transition: @value;
              -o-transition: @value;
              transition: @value;
          }
          

          【讨论】:

          • 这真的很棒。但是,应该注意的是,在转换转换时(特别是),此 mixin 将不起作用。这是由于所需的供应商前缀。
          • 这种方案很好,但如果使用 LessPHP - 它可以t evalute regexp js. So, there is simple solution if we dont 需要为每个转换(只需 ise prop+:) 分配参数:.transition(...){ -webkit-过渡+:@arguments; -moz-transition+: @arguments; -o-transition+: @arguments;过渡+:@arguments; }
          猜你喜欢
          • 1970-01-01
          • 2018-03-24
          • 1970-01-01
          • 2018-07-20
          • 2014-06-02
          • 1970-01-01
          • 2011-12-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多