Can I define a LESS mixin to generate a transition-property with a variable number of parameters?

前端 未结 4 1069
自闭症患者
自闭症患者 2020-12-14 19:40

I\'m introducing LESS to a large web app project to simplify my CSS. I\'ve got a few CSS rules which apply transitions to a varying number of properties, for example:

相关标签:
4条回答
  • 2020-12-14 20:06

    I've managed to figure it out thanks to Luke Page pointing me towards the ... syntax.

    The solution was to use the following:

    • ... to allow variable parameters
    • Backticks for JavaScript evaluation
    • Variable string interpolation
    • A ~ prefix to escape the resulting expression (i.e. stop LESS from enclosing it in a string)
    • Good old regular expressions

    Phew. Here's the resulting mixin:

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

    And here's the full version with a complete set of browser extensions:

    .transition-properties(...) {
        @props: ~`"@{arguments}".replace(/[\[\]]/g, '')`;
        -webkit-transition-property: @props;
        -moz-transition-property: @props;
        -o-transition-property: @props;
        transition-property: @props;
    }
    
    0 讨论(0)
  • 2020-12-14 20:17

    From less.js 1.3 onwards you have to specify ... in the argument list to signify that more arguments can be added. e.g.

    .transition-property(...) {
     foo: @arguments;
    }
    
    0 讨论(0)
  • 2020-12-14 20:25

    Perhaps I am misunderstanding your needs. Why can you not use an escaped string?

    Like so:

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

    This is exactly what we use for multi-property transitions. Never had a problem with it.

    0 讨论(0)
  • 2020-12-14 20:30

    Flexible (LESS 1.5.1+)

    This solution does not use any inline javascript and it allows for:

    1. Defaults to be set
    2. Any number of properties, durations, delays, etc., to be passed
    3. Output either in long form or compact form
    4. A raw list input instead of groups of parameters being input if desired

    If the number of properties are greater than the number of durations, delays, or timings, then if the compact output is set, the final value for duration/delay/timing becomes the value for that parameter for all additional properties beyond the number passed, but if compact is not set, then the long form is output and 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 Use Examples

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

    In the above examples, note two things in particular: (1) how the multiple values need to be passed using commas to separate the lists, but semicolons to separate the parameter groups. So to visualize, it is this:

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

    (2) how the raw-input example needs an ending semicolon to have it consider the commas as list items:

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

    CSS Output of Examples

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

    If long form is never desired then the mixin code can reduce to this:

    .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();
    }
    
    0 讨论(0)
提交回复
热议问题