LESS CSS Pass mixin as a parameter to another mixin

后端 未结 4 1656
借酒劲吻你
借酒劲吻你 2020-12-08 11:49

Is there any way to pass one mixin or style\'s declaration to another mixin as an input parameter?

Let\'s take a look at an example with animation keyframes. Followi

相关标签:
4条回答
  • 2020-12-08 12:29

    You can also use my solution to generate CSS keyframes: https://github.com/thybzi/keyframes

    Features:

    • Cross-browser keyframes generation (Firefox 5+, Chrome 3+, Safari 4+, Opera 12+, IE 10+)
    • Up to 16 timepoints in each keyframes rule (and the number can be easily augmented, if needed)
    • Mixins, variables and functions can be used for styling timepoints
    • Keyframes are created separately from animation rules, so:
      • multiple animation rules can use the same keyframe with different values for timing, repeating, etc,
      • multiple animations can be used within same animation rule
      • animations can be applied (not created!) inside any parent selector
    • Lightweight and (almost) neat LESS code

    Basic usage:

    // Preparing styles for animation points
    .keyframes-item(fadeIn, 0%) {
        opacity: 0;
    }
    .keyframes-item(fadeIn, 100%) {
        opacity: 1;
    }
    // Generating keyframes
    .keyframes(fadeIn);
    
    // Applying animation to fade-in block in 1.5 seconds
    .myBlock {
        .animation(fadeIn 1.5s);
    }
    
    0 讨论(0)
  • 2020-12-08 12:31

    UPDATED for LESS 1.7.0+ (WAY Simpler)

    We can do this far more directly now with the 1.7.0 update and the ability to create rulesets, and to use variables in setting @keyframes.

    Now we really can pass a mixin through a parameter by a ruleset, or we can pass in the property stings themselves. So consider this:

    LESS (using 1.7)

    .keyframes(@name, @from, @to) {
        @frames: {
            from { @from(); }
            to { @to(); }
        };
        @pre: -moz-keyframes;
        @-moz-keyframes @name
        {
           @frames();
        }
    
        @-webkit-keyframes @name
        {
           @frames();
        }
    
        @keyframes @name
        {
           @frames();
        }
    }
    
    .keyframes(testName, {color: red; .myMix(0);}, {color: blue; .myMix(1);});
    
    .myMix(@value) {opacity: @value;}
    

    Note that I am passing both a property setting and a mixin call, and my output is:

    CSS Output

    @-moz-keyframes testName {
      from {
        color: red;
        opacity: 0;
      }
      to {
        color: blue;
        opacity: 1;
      }
    }
    @-webkit-keyframes testName {
      from {
        color: red;
        opacity: 0;
      }
      to {
        color: blue;
        opacity: 1;
      }
    }
    @keyframes testName {
      from {
        color: red;
        opacity: 0;
      }
      to {
        color: blue;
        opacity: 1;
      }
    }
    

    Note how the rulesets are passed, in brackets {...}, and then called, via @from() and @to() (looking a lot like a mixin call). I'm using these passed rule sets to set another ruleset of @frames which is then itself called to fill the keyframes definitions.

    More Generically

    Here I pass a private mixin to another mixin and then call it from that other mixin:

    LESS

    .someMixin(@class; @expectedMixin) {
        .@{class} {
          @expectedMixin();
          .myPrivateMix(0.6);
          test: 1;
        }
    }
    
    .someMixin(newClass; {.myClass;});
    
    .myClass {
      .myPrivateMix(@value) {opacity: @value;}
    }
    

    CSS Output

    .newClass {
      opacity: 0.6;
      test: 1;
    }
    

    Kept the below for legacy info.

    Updated (added LESS 1.4.0+ support)

    Wow, this took some doing, but I think I have something you can work with. However, it does take some special defining of your mixins in your modules, specifically, using pattern matching. So...

    First, Define Your Module Mixins

    Note how the module mixins intended to be used in a specific future mixin are defined with the same mixin name, but with a different pattern name. This was key to making this work.

    // define one animation in a module
    .from(my-from){ color: red; }
    .to(my-to) { color: blue; }
    
    // define one animation in another module
    .from(another-from){ font-size: 1em; }
    .to(another-to) { font-size: 2em; }
    

    If you also want individual mixin names in the modules, you should be able to do this:

    // define one animation in a module
    .my-from(){ color: red; }
    .my-to() { color: blue; }
    
    .from(my-from){ .my-from() }
    .to(my-to) { .my-to() }   
    
    // define one animation in another module
    .another-from(){ font-size: 1em; }
    .another-to() { font-size: 2em; }
    
    .from(another-from){ .another-from() }
    .to(another-to) { .another-to() }
    

    This should allow one to call either the straight mixin .my-from() or, to make it variably accessible within later mixins that access the singular .from() mixin group through the pattern matching.

    Next, Define Your Mixin

    For your @keyframes example, that was extremely difficult. In fact, a stack overflow answer was vital to helping me solve an issue with applying the @name, which was not applying under normal LESS rules because of it following the @keyframes definition. The solution to apply the @name looks nasty, but it works. It does have the, perhaps, unfortunate necessity of also defining a selector string to play the animation by (because it uses that string to help build the last } of the keyframes). This naming limitation would only be true of css strings that begin with @ like @keyframes and probably @media.

    Further, because we have a standard mixin name used in our module files, we can access that consistently within our new mixin, while at the same time passing a variable in to select the proper variation of that mixin through a pattern match. So we get:

    LESS 1.3.3 or under

    // define mixin in mixin file
    
    .keyframes(@selector, @name, @from, @to) {
        @newline: `"\n"`; // Newline
        .setVendor(@pre, @post, @vendor) {
            (~"@{pre}@@{vendor}keyframes @{name} {@{newline}from") {
                .from(@from); 
            }    
            to  { 
                .to(@to);
            }
           .Local(){}
           .Local() when (@post=1) {
               (~"}@{newline}@{selector}") {
                  -moz-animation: @name;
                  -webkit-animation: @name;
                  -o-animation: @name;
                  -ms-animation: @name;
                  animation: @name;
               } 
           }    
           .Local;
        } 
        .setVendor(""            , 0,    "-moz-");
        .setVendor(~"}@{newline}", 0, "-webkit-");
        .setVendor(~"}@{newline}", 0,      "-o-");
        .setVendor(~"}@{newline}", 0,     "-ms-");
        .setVendor(~"}@{newline}", 1,         "");
    }
    

    LESS 1.4.0+

    .keyframes(@selector, @name, @from, @to) {
        @newline: `"\n"`; // Newline
        .setVendor(@pre, @post, @vendor) {
            @frames: ~"@{pre}@@{vendor}keyframes @{name} {@{newline}from";
            @{frames} {
                .from(@from); 
            }    
            to  { 
                .to(@to);
            }
           .Local(){}
           .Local() when (@post=1) {
               @animationSector: ~"}@{newline}@{selector}";
               @{animationSector} {
                  -moz-animation: @name;
                  -webkit-animation: @name;
                  -o-animation: @name;
                  -ms-animation: @name;
                  animation: @name;
               } 
           }    
           .Local;
        } 
        .setVendor(""            , 0,    "-moz-");
        .setVendor(~"}@{newline}", 0, "-webkit-");
        .setVendor(~"}@{newline}", 0,      "-o-");
        .setVendor(~"}@{newline}", 0,     "-ms-");
        .setVendor(~"}@{newline}", 1,         "");
    }
    

    Now Call Your Mixin

    You can give it your own name, and just pass the straight pattern (all are no dot [.] and no quotes) for the pattern matches on the module mixins, but don't forget that you also need a selector string (which is quoted) to get the mixin to work right:

    .keyframes('.changeColor', some-name, my-from, my-to);
    .keyframes('.changeFontSize', another-name, another-from, another-to);
    

    Which Gives You the Desired Output

    @-moz-keyframes some-name {
    from {
      color: red;
    }
    to {
      color: blue;
    }
    }
    @-webkit-keyframes some-name {
    from {
      color: red;
    }
    to {
      color: blue;
    }
    }
    @-o-keyframes some-name {
    from {
      color: red;
    }
    to {
      color: blue;
    }
    }
    @-ms-keyframes some-name {
    from {
      color: red;
    }
    to {
      color: blue;
    }
    }
    @keyframes some-name {
    from {
      color: red;
    }
    to {
      color: blue;
    }
    }
    .changeColor {
      -moz-animation: some-name;
      -webkit-animation: some-name;
      -o-animation: some-name;
      -ms-animation: some-name;
      animation: some-name;
    }
    @-moz-keyframes another-name {
    from {
      font-size: 1em;
    }
    to {
      font-size: 2em;
    }
    }
    @-webkit-keyframes another-name {
    from {
      font-size: 1em;
    }
    to {
      font-size: 2em;
    }
    }
    @-o-keyframes another-name {
    from {
      font-size: 1em;
    }
    to {
      font-size: 2em;
    }
    }
    @-ms-keyframes another-name {
    from {
      font-size: 1em;
    }
    to {
      font-size: 2em;
    }
    }
    @keyframes another-name {
    from {
      font-size: 1em;
    }
    to {
      font-size: 2em;
    }
    }
    .changeFontSize {
      -moz-animation: another-name
      -webkit-animation: another-name;
      -o-animation: another-name;
      -ms-animation: another-name;
      animation: another-name;
    }
    
    0 讨论(0)
  • 2020-12-08 12:37

    Its not really how you would use mixins.

    You should do something along the lines of:

    .mixin-one { ... }
    .mixin-two { ... }
    .target-style {
        .mixin-one;
        .mixin-two;
        font-family: 'Comic Sans MS';
        color: magenta;
    }
    
    0 讨论(0)
  • 2020-12-08 12:40

    Simplification

    I just simplified a little ScottS' way, separateing @keframes from -animation:

    .keyframes(@name, @from, @to) {
        @newline: `"\n"`;
        .Local(@x){};
        .Local(@x) when (@x="") {(~"}@{newline}/*"){a:a}/**/};
    
        .setVendor(@pre, @vendor) {
            (~"@{pre}@@{vendor}keyframes @{name} {@{newline}from") {
                .from(@from);
            }
            to {
                .to(@to);
            }
            .Local(@vendor);
        }
        .setVendor(""            , "-webkit-");
        .setVendor(~"}@{newline}",    "-moz-");
        .setVendor(~"}@{newline}",      "-o-");
        .setVendor(~"}@{newline}",         "");
    }
    
    .animation(...) {
      -webkit-animation: @arguments;
         -moz-animation: @arguments;
           -o-animation: @arguments;
              animation: @arguments;
    }
    

    use:

    .from(a1-from){ width: 10px; }
    .to(a1-to) { width: 20px; }
    .keyframes(a1-animation, a1-from, a1-to);
    
    
    .selector {
        // some other css
        .animation(a1-animation 1s infinite linear);
    }
    

    output:

    @-webkit-keyframes a1-animation {
    from {
      width: 10px;
    }
    to {
      width: 20px;
    }
    }
    @-moz-keyframes a1-animation {
    from {
      width: 10px;
    }
    to {
      width: 20px;
    }
    }
    @-o-keyframes a1-animation {
    from {
      width: 10px;
    }
    to {
      width: 20px;
    }
    }
    @keyframes a1-animation {
    from {
      width: 10px;
    }
    to {
      width: 20px;
    }
    }
    /* {
      a: a;
    }
    /**/
    
    
    .selector {
      // some other css
      -webkit-animation: a1-animation 1s infinite linear;
      -moz-animation: a1-animation 1s infinite linear;
      -o-animation: a1-animation 1s infinite linear;
      animation: a1-animation 1s infinite linear;
    }
    

    little problem:

    So animation is now separated from @keyframes, but we got to pay the price. There is a nasty:

    /* {
      a: a;
    }
    /**/
    

    but it shouldn't be a problem -> propably all of us push CSS files through any kinds of minifiers which cut comments out.

    0 讨论(0)
提交回复
热议问题