【问题标题】:Can I define a LESS mixin to generate a transition-property with a variable number of parameters?我可以定义一个 LESS 混合来生成具有可变数量参数的转换属性吗?
【发布时间】:2012-05-11 20:41:27
【问题描述】:

我将 LESS 引入一个大型网络应用项目以简化我的 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)。 LESS mixin 可以使用特殊的 @arguments 值到 produce a space-separated list of all the mixin arguments - 但是是否可以定义一个 LESS mixin 接受可变数量的参数并将它们转换为逗号分隔的值列表,适用于transition-property?

如有必要,我对需要两个 mixin 的解决方案感到满意:一个用于 transition-property,另一个用于 transition-duration 和 transition-timing-function。到目前为止,这是我尝试过的:

尝试 1:使用带有未命名参数的 @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(top, left)' 找到匹配的定义”)

尝试 2:使用带有命名参数的 @arguments

.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 错误(“没有为 '.transition-property(top, left)' 找到匹配的定义”)

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

.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);
}

结果:没有 LESS 错误,但它会生成一个 CSS 规则 -webkit-transition-property: top, left, p3, p4, p5,由于无法识别的属性,浏览器会忽略该规则。

我尝试了各种其他方法(例如,将属性作为字符串传递 'top,left'),但结果都是一样的:要么是 LESS 错误,要么是无效的 CSS。

有什么办法可以解决这个问题吗?或者我必须硬着头皮定义一组在 arity 上重载的 mixin,例如

.transition-property(@p1) {...}
.transition-property(@p1, @p2) {...}
.transition-property(@p1, @p2, @p3) {...}
.transition-property(@p1, @p2, @p3, @p4) {...}
etc.

【问题讨论】:

    标签: css less mixins less-mixins


    【解决方案1】:

    感谢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;
    }
    

    【讨论】:

    • 出于兴趣,您需要 JavaScript 做什么?什么是插入方括号?
    • @arguments 是一个数组。如果你只是在 LESS 中使用它,你会得到所有用空格分隔的元素。但是对于这个属性(通常),它们需要用逗号分隔。如果您在 @arguments 上使用变量插值,您会得到一个字符串,其中包含方括号中的逗号分隔列表(如 JavaScript 数组文字):"[a,b,c]"
    • 有时我们希望每个浏览器都有一个不同的@props,如果你需要动画转换就是这种情况。你必须做-webkit-transition-property: -webkit-transform、-moz-transition-property: -moz-transform等等。这可以通过-webkit-transition-property: replace(@props, 'XX', '-webkit-', 'g');、-moz-transition-property: replace(@props, 'XX', '-moz-', 'g'); 等来完成。然后只需拨打.transition-properties('XXtransform', 'color')
    • 我是想打电话给.transition-properties(XXtransform, color)
    • 奇怪的是,当你传递一个参数时,它会导致一个逗号分隔的字符串(不透明度0.5s)会产生(不透明度,0.5s),为什么?
    【解决方案2】:

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

    像这样:

    .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 );
    }
    

    这正是我们用于多属性转换的方法。从来没有遇到过问题。

    【讨论】:

    • 如果可以的话,我会为这个答案投票 10 次。简单而且非常有用。我以前对 Less 中的转义字符串一无所知。谢谢。
    • @spikyjt 我也花了一点时间才找到它。很高兴它有帮助。
    • 波浪号是什么意思? ~"<list here>"
    • @Redsandro 它告诉 LESS 解析器不要转义以下内容。因此它按原样通过它。欲了解更多信息,请转到link 并在页面上搜索Escaping。你会立即看到它。
    • 这种方法的缺点是因为它被转义了,你不能在字符串中使用 LESS 变量。我使用变量作为过渡持续时间,这个函数不能处理多个过渡持续时间。另外,转义的新文档现在是here。
    【解决方案3】:

    灵活(LESS 1.5.1+)

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

    1. 要设置的默认值
    2. 要传递的任意数量的属性、持续时间、延迟等
    3. 以长格式或紧凑格式输出
    4. 如果需要,可以输入原始列表而不是输入参数组

    如果属性的数量大于持续时间、延迟或计时的数量,则如果设置了 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();
    } 
    

    LESS 使用示例

    .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();
    }
    

    【讨论】:

    • 这是一个简洁的解决方案...(请不​​要将其视为批评,只是一个小评论)但我个人更喜欢使用一些基于“property merge”的小型混合而不是一个巨大的“我可以做任何事”的例行公事。 (不包括现代的“无前缀”方法(因为 autoprefixer 之类的东西),这可以完全不用 mixins 来完成。即仅使用 transition+: ...;,并且 mixins 仅对某些动画“模板”有用左右)。
    • @seven-phases-max:当我遇到this bug 时,我实际上正在研究另一个属性合并解决方案,它有apparently been fixed (by you I believe),但在less2css.org 中仍然不适合我1.5.1 版本(所以也许是 1.5.2?)。
    • 对了,我差点忘了这个bug。是的,即将到来(我希望很快)1.6.0 已修复。
    【解决方案4】:

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

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

    【讨论】:

    • 谢谢卢克,这是一个很大的帮助。 ... 语法在 lesscss.org 中根本没有提到!
    • 是的,我觉得less.js的作者——cloudhead,太忙了。他在 github 上创建了一个要点,但对网站没有任何更改。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 1970-01-01
    相关资源
    最近更新 更多