【问题标题】:LESS CSS Pass mixin as a parameter to another mixinLESS CSS 将 mixin 作为参数传递给另一个 mixin
【发布时间】:2012-07-18 01:48:24
【问题描述】:

有没有办法将一个 mixin 或样式的声明作为输入参数传递给另一个 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() 等。

【问题讨论】:

  • 您能否更清楚地说明为什么您觉得不能直接使用mixin,以及您期望通过这个mixin 给您带来什么?您是否尝试使用 mixin 来定义一个 @color 变量和一个 @font-size 变量以供在第二个 mixin 中使用?请更具体一些,因为 Petah 的回答是使用它们的正常方式。
  • ScottS,请查看我对 Petah 帖子的回答。

标签: css arguments less mixins css-animations


【解决方案1】:

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

我们现在可以通过 1.7.0 更新和create rulesets 的功能更直接地做到这一点,并使用variables in setting @keyframes

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

LESS(使用 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 进行一些特殊定义,特别是使用 pattern matching。所以……

首先,定义你的模块 Mixins

请注意,打算在特定的未来 mixin 中使用的模块 mixin 是如何使用 相同的 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() 或使其在以后的 mixin 中可变地访问,这些 mixin 通过模式匹配访问单个 .from() mixin 组。

接下来,定义你的 Mixin

对于您的 @keyframes 示例,这非常困难。事实上,a stack overflow answer 对帮助我解决应用 @name 的问题至关重要,因为它遵循 @keyframes 定义,所以它不适用于正常的 LESS 规则。应用@name 的解决方案看起来很糟糕,但它确实有效。不幸的是,它确实需要定义一个选择器字符串来播放动画(因为它使用该字符串来帮助构建关键帧的最后一个})。此命名限制仅适用于以 @ 开头的 css 字符串,例如 @keyframes 和可能是 @media

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

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

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

现在调用你的 Mixin

你可以给它你自己的名字,然后直接传递模块上的模式匹配(都是 no 点 [.] 和 no 引号) mixin,但不要忘记,您还需要一个选择器字符串(被引用)才能使 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;
}

【讨论】:

  • 如果作为参数传递的mixin应该用参数调用呢?使用@to("SomeParam"); 似乎不起作用
  • @SebastienLorber:重要的是要记住@to()ruleset call,而不是mixin,所以它不带参数。要将参数传递到规则集中,请查看混合调用本身作为规则集的一部分传递的示例(例如.myMix(0)),该混合被定义为.myMix(@value) {opacity: @value;}。我希望这可以帮助你得到你正在寻找的东西。
【解决方案2】:

你也可以使用我的方案生成 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);
}

【讨论】:

    【解决方案3】:

    简化

    我只是简化了一点 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 文件,这些压缩器会切断 cmets。

    【讨论】:

      【解决方案4】:

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

      你应该按照以下方式做一些事情:

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

      【讨论】:

      • 是的,我知道我可以这样做,但我的问题更复杂。我的系统具有通用的 mixins 规则,例如用于 css3 内容的 help-wrappers 库,并且该库由不同的模块使用,并且想法是将这些模块中的信息传递到 mixins 库以构建输出 css。如您所见,mixins 库无法知道在不同外部模块中声明的 mixins。所以,我需要一种方法将这些信息传递到我的 mixins 库中。
      • @JoAsakura--为什么你不能只将@import (see here) 你的模块放到 mixin 库中,然后“其中的所有变量和 mixin 都将可用于主文件。 "导入后,使用上面的 Petah 方法。
      • ScottS,这不是我的情况。我所拥有的如下:该项目包含不同的模块,每个模块都有自己的样式(LESS),所有这些模块样式都使用全局 mixins 库。因此,没有@import 甚至没有可能 mixin 库会知道这些外部模块。一切都是动态发生的,我基于这些模块等构建输出 CSS,它不是像 LESS 文件 + js 那样直接使用 LESS 来编译它。
      • @JoAsakura(顺便说一句——不要忘记在我的名字前使用@,这样它会提醒我你在评论中引用了我)。如果 mixin 库对模块一无所知,那么 mixin 库怎么可能以任何方式使用它们中的 mixin?而且我仍然不清楚你到底想要 mixin 使用的模块信息。
      • @JoAsakura 我同意,我们需要更多信息来帮助您。通过示例为您提供完整的用例。
      猜你喜欢
      • 1970-01-01
      • 2013-06-03
      • 1970-01-01
      • 2014-08-27
      • 1970-01-01
      • 2015-05-07
      • 1970-01-01
      • 2013-01-05
      • 2014-01-30
      相关资源
      最近更新 更多