我可以定义一个LESS mixin来生成具有可变数量参数的transition属性吗?

时间:2012-05-02 11:16:07

标签: css less mixins less-mixins

我将LESS引入大型Web应用程序项目以简化我的CSS。我有一些CSS规则将转换应用于不同数量的属性,例如:

.movable {
    transition-property: top, left;
    transition-duration: 0.2s;
    transition-timing-function: ease;
}

.fadeAndStretchable {
    transition-property: opacity, width, height, margin;
    transition-duration: 1.5s;
    transition-timing-function: ease-out;
}

(注意:为简洁起见,我在此处省略了-webkit-moz-o属性:实际上,这些规则中的每一条都是12行而不是3行。)

请注意transition-property的值以逗号分隔。这在CSS中很常见:多个值通常以空格分隔(如border: 1px solid #f00中所示)。较少的mixins可以使用特殊@arguments值来produce a space-separated list of all the mixin arguments - 但是可以定义一个LESS mixin,它接受可变数量的参数并将它们转换为逗号分隔值列表,适合{{ 1}}?

如果有必要,我很满意需要两个mixin的解决方案:一个用于transition-property,另一个用于transition-propertytransition-duration。这是我到目前为止所尝试的内容:

尝试1:使用带有未命名参数的
transition-timing-function

结果:LESS错误(“找不到'.transition-property(顶部,左侧)'的匹配定义”)

尝试2:将@arguments与命名参数一起使用

.transition-property() {
    -webkit-transition-property: @arguments;
    -moz-transition-property: @arguments;
    -o-transition-property: @arguments;
    transition-property: @arguments;
}

.movable {
    .transition-property(top, left);
}

结果:LESS错误(“找不到'.transition-property(顶部,左侧)'的匹配定义”)

尝试3:使用具有虚拟默认值的命名参数

.transition-property(@p1, @p2, @p3, @p4, @p5) {
    -webkit-transition-property: @arguments;
    -moz-transition-property: @arguments;
    -o-transition-property: @arguments;
    transition-property: @arguments;
}

.movable {
    .transition-property(top, left);
}

结果:没有LESS错误,但它会生成一个CSS规则.transition-property(@p1:p1, @p2:p2, @p3:p3, @p4:p4, @p5:p5) { -webkit-transition-property: @p1, @p2, @p3, @p4, @p5; -moz-transition-property: @p1, @p2, @p3, @p4, @p5; -o-transition-property: @p1, @p2, @p3, @p4, @p5; transition-property: @p1, @p2, @p3, @p4, @p5; } .movable { .transition-property(top, left); } ,由于无法识别的属性,浏览器会忽略该规则。

我尝试过各种其他方法(例如将属性作为字符串-webkit-transition-property: top, left, p3, p4, p5传递)但所有结果都是相同的:LESS错误或CSS无效。

有什么方法围绕这个吗?或者我必须咬紧牙关并定义一组在arity上重载的mixin,例如

'top,left'

4 个答案:

答案 0 :(得分:29)

由于Luke Page指向了...语法,我设法弄明白了。

解决方案是使用以下内容:

呼。这是得到的mixin:

.transition-properties(...) {
    -webkit-transition-property: ~`"@{arguments}".replace(/[\[\]]/g, '')`;
}

这是完整版,其中包含一整套浏览器扩展程序:

.transition-properties(...) {
    @props: ~`"@{arguments}".replace(/[\[\]]/g, '')`;
    -webkit-transition-property: @props;
    -moz-transition-property: @props;
    -o-transition-property: @props;
    transition-property: @props;
}

答案 1 :(得分:20)

也许我误解了你的需求。为什么不能使用转义字符串?

像这样:

.transition ( @property, @duration, @style: ease-in-out ) {
  -webkit-transition-property: @property;  
  -webkit-transition-duration: @duration;
  -webkit-transition-timing-function: @style;

  -moz-transition-property: @property;  
  -moz-transition-duration: @duration;
  -moz-transition-timing-function: @style;

  -ms-transition-property: @property;  
  -ms-transition-duration: @duration;
  -ms-transition-timing-function: @style;

  -o-transition-property: @property;  
  -o-transition-duration: @duration;
  -o-transition-timing-function: @style;

  transition-property: @property;  
  transition-duration: @duration;
  transition-timing-function: @style;
}

#my-id {
  .transition( ~"background, border-color, color", 2s );
}

这正是我们用于多属性转换的内容。没问题。

答案 2 :(得分:6)

灵活(低于1.5.1 +)

此解决方案不使用任何内联JavaScript,它允许:

  1. 默认设置
  2. 要传递的任意数量的属性,持续时间,延迟等
  3. 以长格式或紧凑格式输出
  4. 原始列表输入,而不是根据需要输入的参数组
  5. 如果属性的数量大于持续时间,延迟或时间的数量,那么如果设置了compact输出,则持续时间/延迟/时间的最终值将成为所有参数的值超出传递数量的其他属性,但如果compact 设置,则输出长格式并values are duplicated per browsers interpret ion of the css standards

    LESS Mixin

    .transition (@props: all; 
                 @duration:1s; 
                 @delay: 0s; 
                 @timing: ease; 
                 @compact: true;
                 @raw-input: false) {
      .output() when (@raw-input = false) and not (@compact = true) {
      -webkit-transition-property:@props; 
         -moz-transition-property:@props;
          -ms-transition-property:@props;
           -o-transition-property:@props; 
              transition-property:@props;
      -webkit-transition-duration:@duration; 
         -moz-transition-duration:@duration;
          -ms-transition-duration:@duration;
           -o-transition-duration:@duration; 
              transition-duration:@duration;
      -webkit-transition-delay:   @delay; 
         -moz-transition-delay:   @delay;
          -ms-transition-delay:   @delay;
           -o-transition-delay:   @delay; 
              transition-delay:   @delay;
      -webkit-transition-timing-function:@timing; 
         -moz-transition-timing-function:@timing;
          -ms-transition-timing-function:@timing;
           -o-transition-timing-function:@timing; 
              transition-timing-function:@timing;
      }
      .output() when (@raw-input = false) and (@compact = true) {
        @propsLength: length(@props);
        @durationLength: length(@duration);
        @delayLength: length(@delay);
        @timingLength: length(@timing);
        .buildString(@i, @s: ~'') when (@i <= @propsLength) {
          @prop: extract(@props, @i);
          .setDuration() when (@i <= @durationLength) {
            @dur: extract(@duration, @i);
          }
          .setDuration() when (@i > @durationLength) {
            @dur: extract(@duration, @durationLength);
          }
          .setDuration();
          .setDelay() when (@i <= @delayLength) {
            @del: extract(@delay, @i);
          }
          .setDelay() when (@i > @delayLength) {
            @del: extract(@delay, @delayLength);
          }
          .setDelay();
          .setTiming() when (@i <= @timingLength) {
            @time: extract(@timing, @i);
          }
          .setTiming() when (@i > @timingLength) {
            @time: extract(@timing, @timingLength);
          }
          .setTiming();
          .setDivider() when (@i > 1) {
            @divider: ~'@{s},';
          }
          .setDivider() when (@i = 1) {
            @divider: ~'';
          }
          .setDivider();
          @string: @divider @prop @dur @del @time;
          .buildString((@i + 1), @string);  
        }
        .buildString(1);
        .buildString(@i, @s: ~'') when (@i > @propsLength) {
          .compact(@s);
        }
      }
      .output() when not (@raw-input = false) {
        .compact(@raw-input);
      }
      .compact(@string) {
        -webkit-transition:@string; 
           -moz-transition:@string;
            -ms-transition:@string;
             -o-transition:@string; 
                transition:@string;    
      }
      .output();
    } 
    

    少用例

    .test {
      .transition();
    }
    .test-props {
      .transition(width);
    }
    .test-duration {
      .transition(@duration: 3s);
    }
    .test-delay {
      .transition(@delay: 10s);
    }
    .test-timing {
      .transition(@timing: linear);
    }
    .test-all {
      .transition(height, 4s, 12s, ease-out);
    }
    .test-multitransitions {
      .transition(width, height, top; 1s, 2s; 0s, 1s, 3s; ease-in, ease-out, ease);
    }
    .test-not-compact {
      .transition(width, height, top; 1s, 2s; 0s, 1s, 3s; ease-in, ease-out, ease; false);
    }
    .test-raw-input {
      .transition(@raw-input: top 1s, bottom 1s, color 3s 1s linear;);
    }
    

    在上面的示例中,特别注意两件事:(1)如何使用逗号分隔列表来传递多个值,而使用分号来分隔参数组。所以要想象,就是这样:

      .transition(width, height, top; 1s, 2s; 0s, 1s, 3s; ease-in, ease-out, ease);
                  |---Properties----|-Dur.--|---Delay---|---------Timing--------|
                                    |       |           |
                              semicolons divide groups of parameters
    

    (2)raw-input示例如何需要一个结尾分号才能将逗号视为列表项:

      .transition(@raw-input: top 1s, bottom 1s, color 3s 1s linear;);
                                                                   |
                                                        semicolon here needed
    

    示例的CSS输出

    .test {
      -webkit-transition:  all 1s 0s ease;
      -moz-transition:  all 1s 0s ease;
      -ms-transition:  all 1s 0s ease;
      -o-transition:  all 1s 0s ease;
      transition:  all 1s 0s ease;
    }
    .test-props {
      -webkit-transition:  width 1s 0s ease;
      -moz-transition:  width 1s 0s ease;
      -ms-transition:  width 1s 0s ease;
      -o-transition:  width 1s 0s ease;
      transition:  width 1s 0s ease;
    }
    .test-duration {
      -webkit-transition:  all 3s 0s ease;
      -moz-transition:  all 3s 0s ease;
      -ms-transition:  all 3s 0s ease;
      -o-transition:  all 3s 0s ease;
      transition:  all 3s 0s ease;
    }
    .test-delay {
      -webkit-transition:  all 1s 10s ease;
      -moz-transition:  all 1s 10s ease;
      -ms-transition:  all 1s 10s ease;
      -o-transition:  all 1s 10s ease;
      transition:  all 1s 10s ease;
    }
    .test-timing {
      -webkit-transition:  all 1s 0s linear;
      -moz-transition:  all 1s 0s linear;
      -ms-transition:  all 1s 0s linear;
      -o-transition:  all 1s 0s linear;
      transition:  all 1s 0s linear;
    }
    .test-all {
      -webkit-transition:  height 4s 12s ease-out;
      -moz-transition:  height 4s 12s ease-out;
      -ms-transition:  height 4s 12s ease-out;
      -o-transition:  height 4s 12s ease-out;
      transition:  height 4s 12s ease-out;
    }
    .test-multitransitions {
      -webkit-transition:  width 1s 0s ease-in, height 2s 1s ease-out, top 2s 3s ease;
      -moz-transition:  width 1s 0s ease-in, height 2s 1s ease-out, top 2s 3s ease;
      -ms-transition:  width 1s 0s ease-in, height 2s 1s ease-out, top 2s 3s ease;
      -o-transition:  width 1s 0s ease-in, height 2s 1s ease-out, top 2s 3s ease;
      transition:  width 1s 0s ease-in, height 2s 1s ease-out, top 2s 3s ease;
    }
    .test-not-compact {
      -webkit-transition-property: width, height, top;
      -moz-transition-property: width, height, top;
      -ms-transition-property: width, height, top;
      -o-transition-property: width, height, top;
      transition-property: width, height, top;
      -webkit-transition-duration: 1s, 2s;
      -moz-transition-duration: 1s, 2s;
      -ms-transition-duration: 1s, 2s;
      -o-transition-duration: 1s, 2s;
      transition-duration: 1s, 2s;
      -webkit-transition-delay: 0s, 1s, 3s;
      -moz-transition-delay: 0s, 1s, 3s;
      -ms-transition-delay: 0s, 1s, 3s;
      -o-transition-delay: 0s, 1s, 3s;
      transition-delay: 0s, 1s, 3s;
      -webkit-transition-timing-function: ease-in, ease-out, ease;
      -moz-transition-timing-function: ease-in, ease-out, ease;
      -ms-transition-timing-function: ease-in, ease-out, ease;
      -o-transition-timing-function: ease-in, ease-out, ease;
      transition-timing-function: ease-in, ease-out, ease;
    }    
    .test-raw-input {
      -webkit-transition: top 1s, bottom 1s, color 3s 1s linear;
      -moz-transition: top 1s, bottom 1s, color 3s 1s linear;
      -ms-transition: top 1s, bottom 1s, color 3s 1s linear;
      -o-transition: top 1s, bottom 1s, color 3s 1s linear;
      transition: top 1s, bottom 1s, color 3s 1s linear;
    }
    

    如果永远不需要长篇那么mixin代码可以减少到:

    .transition (@props: all; 
                 @duration:1s; 
                 @delay: 0s; 
                 @timing: ease; 
                 @raw-input: false) {
      .output() when (@raw-input = false) {
        @propsLength: length(@props);
        @durationLength: length(@duration);
        @delayLength: length(@delay);
        @timingLength: length(@timing);
        .buildString(@i, @s: ~'') when (@i <= @propsLength) {
          @prop: extract(@props, @i);
          .setDuration() when (@i <= @durationLength) {
            @dur: extract(@duration, @i);
          }
          .setDuration() when (@i > @durationLength) {
            @dur: extract(@duration, @durationLength);
          }
          .setDuration();
          .setDelay() when (@i <= @delayLength) {
            @del: extract(@delay, @i);
          }
          .setDelay() when (@i > @delayLength) {
            @del: extract(@delay, @delayLength);
          }
          .setDelay();
          .setTiming() when (@i <= @timingLength) {
            @time: extract(@timing, @i);
          }
          .setTiming() when (@i > @timingLength) {
            @time: extract(@timing, @timingLength);
          }
          .setTiming();
          .setDivider() when (@i > 1) {
            @divider: ~'@{s},';
          }
          .setDivider() when (@i = 1) {
            @divider: ~'';
          }
          .setDivider();
          @string: @divider @prop @dur @del @time;
          .buildString((@i + 1), @string);  
        }
        .buildString(1);
        .buildString(@i, @s: ~'') when (@i > @propsLength) {
          .compact(@s);
        }
      }
      .output() when not (@raw-input = false) {
        .compact(@raw-input);
      }
      .compact(@string) {
        -webkit-transition:@string; 
           -moz-transition:@string;
            -ms-transition:@string;
             -o-transition:@string; 
                transition:@string;    
      }
      .output();
    }
    

答案 3 :(得分:5)

从less.js 1.3开始,您必须在参数列表中指定...以表示可以添加更多参数。 e.g。

.transition-property(...) {
 foo: @arguments;
}