LESS CSS 将 mixin 作为参数传递给另一个 mixin



有没有办法将一个 mixin 或 style 的声明作为输入参数传递给另一个 mixin?

让我们看一个带有动画关键帧的示例。以下是我们如何在纯 CSS 中定义关键帧:

@-moz-keyframes some-name
{
    from { color: red; }
    to { color: blue; }
}
@-webkit-keyframes some-name
{
    from { color: red; }
    to { color: blue; }
}
@keyframes some-name
{
    from { color: red; }
    to { color: blue; }
}

想法是使用 mixins 简化这些声明,因此我们可以有如下所示的内容:

.keyframes(name, from, to)
{
    // here we need somehow to reproduce structure
    // that we have in an example above
}
// define one animation
.my-from() { color: red; }
.my-to() { color: blue; }
// the following won't work because you cannot pass mixin as a parameter
// in way I have here, so I am looking for a way to solve this problem
.keyframes('some-name', .my-from, .my-to);
// define another animation
.another-from() { font-size: 1em; }
.another-to() { font-size: 2em; }
.keyframes('another-name', .another-from, .another-to);

系统将具有不同的模块,这些模块可以动态附加到应用程序以及删除。所以,不要建议我使用@import因为事实并非如此。输出 CSS 是动态编译的,使用有关模块及其自己的 LESS 样式的信息以及基本的 LESS 依赖项(如 mixins 库等(。

注意:如果您知道一种传递类定义而不是 mixin 的方法,它将对我有用。在上面的示例中,它将是.my-from而不是.my-from()等。

更新为 LESS 1.7.0+(更简单的方式(

现在,我们可以通过 1.7.0 更新和创建规则集以及在设置中使用变量的功能更直接地执行此操作 @keyframes .

现在我们真的可以通过规则集通过参数传递 mixin,或者我们可以传入属性刺痛本身。所以考虑一下:

更少(使用 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;}

请注意,我同时传递了属性设置和 mixin 调用,我的输出是:

CSS 输出

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

注意规则集是如何通过{...}括号传递的,然后通过@from()@to()调用(看起来很像mixin调用(。我使用这些传递的规则集来设置另一个@frames规则集,然后调用该规则集本身来填充关键帧定义。

更通用

在这里,我将一个私有 mixin 传递给另一个 mixin,然后从另一个 mixin 调用它:

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

CSS 输出

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

保留以下内容以获取旧信息。

已更新(添加了 LESS 1.4.0+ 支持(

哇,这需要做一些工作,但我想我有一些你可以使用的东西。但是,它确实需要对模块中的mixin进行一些特殊的定义,特别是使用模式匹配。所以。。。

首先,定义您的模块组合

请注意,打算在未来特定混音中使用的模块混音是如何使用相同的混音名称定义的,但具有不同的模式名称。这是完成这项工作的关键。

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

如果你还想在模块中出现单独的mixin名称,你应该能够这样做:

// 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() }

这应该允许人们调用直接 mixin .my-from(),或者使其在通过模式匹配访问单数.from() mixin 组的后续混合中可变地访问。

接下来,定义您的混合蛋白

对于你的@keyframes例子,这是非常困难的。事实上,堆栈溢出答案对于帮助我解决应用@name的问题至关重要,该在正常的 LESS 规则下不适用,因为它遵循@keyframes定义。应用@name的解决方案看起来很讨厌,但它有效。也许,它确实具有定义一个选择器字符串来播放动画的不幸必要性(因为它使用该字符串来帮助构建关键帧的最后}(。此命名限制仅适用于以@开头的 css 字符串,例如 @keyframes 和可能@media

此外,由于我们在模块文件中使用了标准的mixin名称,因此我们可以在新的mixin中一致地访问该名称,同时传递一个变量以通过模式匹配选择该mixin的正确变体。所以我们得到:

减去 1.3.3 或以下

// 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,         "");
}

减去 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,         "");
}

现在打电话给你的混音

你可以给它起你自己的名字,只需传递模块 mixins 上的模式匹配的直模式(所有模式都没有点 [.] 和引号(,但不要忘记你还需要一个选择器字符串(带引号(才能让 mixin 正常工作:

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

这为您提供所需的输出

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

简化

我只是简化了一点 ScottS 的方式,将@keframes-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;
}

用:

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

输出:

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

小问题:

所以动画现在与@keyframes分开了,但我们必须付出代价。有一个讨厌的:

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

但这应该不是问题 ->我们所有人都可能通过任何类型的简化器推送CSS文件,从而减少注释。

您还可以使用我的解决方案生成CSS关键帧: https://github.com/thybzi/keyframes

特征:

  • 跨浏览器关键帧生成(Firefox 5+、Chrome 3+、Safari 4+、Opera 12+、IE 10+(
  • 每个keyframes规则中最多 16 个时间点(如果需要,可以轻松增加数量(
  • 混合、变量和函数可用于设置时间点的样式
  • 关键帧是独立于animation规则创建的,因此:
    • 多个animation规则可以使用具有不同值的同一关键帧进行计时、重复等。
    • 可以在同一animation规则中使用多个动画
    • 动画可以在任何父选择器中应用(而不是创建!
  • 轻量级和(几乎(整洁的 LESS 代码

基本用法:

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

这不是你真正使用mixins的方式。

你应该做一些类似的事情:

.mixin-one { ... }
.mixin-two { ... }
.target-style {
    .mixin-one;
    .mixin-two;
    font-family: 'Comic Sans MS';
    color: magenta;
}

最新更新