在 LESS CSS 中动态定义一个变量

Posted

技术标签:

【中文标题】在 LESS CSS 中动态定义一个变量【英文标题】:Dynamically define a variable in LESS CSS 【发布时间】:2013-08-05 00:48:46 【问题描述】:

我正在尝试通过实际为它们分配一个复合名称来创建一个在 LESS CSS 中动态定义变量的 mixin。

简化的用例(不是真实的):

.define(@var)
    @foovar: 0;

然后人们会这样调用mixin:

.define('Bar')
    @fooBar: 0;

由于在使用选择器名称时可以进行这种字符串插值,我想知道变量名称是否也可以这样做;到目前为止,我尝试过的各种语法都没有运气(除了上述之外,我尝试了转义、引用、使用~ 前缀等等)。

编辑

我又尝试了一件事情,我觉得我可能已经接近了;但我遇到了 LESS 语法的奇怪之处。如果我这样写:

.define(@var)
    #namespace 
         @foo: @var;
    

然后这样称呼它:

.define(0)

然后我可以以通常的命名空间方式使用@foo

.test 
     #namespace;
     property: @foo; /* returns 0 */

但是,这不适用于字符串插值选择器:

.define(@var, @ns)
    #@ns 
         @foo: @var;
    


.define(0, namespace);

.test 
     #namespace;
     property: @foo;

上面的代码给了我以下错误:

名称错误:#namespace 未定义

但是,字符串插值成功且有效。事实上,如果我去掉.test 部分并修改上面的内容以输出一个测试属性,我可以看到CSS 被正确解析。我的意思是:

.define(@var, @ns)
    #@ns 
         @foo: @var;
         prop: @foo;
    


.define(0, namespace);

输出以下 CSS:

#namespace 
    prop: 0;

【问题讨论】:

【参考方案1】:

这是不可能的

您想要做的事情目前在 LESS 中是不可能的。我可以想到两种可能的“解决方法”如果您提前知道要允许使用哪些变量名称(换句话说,不是完全动态的)。然后可以执行以下操作之一:

想法 #1(变量)

.define(@var) 
  @fooBar: 0;
  @fooTwo: 2;
  @fooYep: 4;

  @fooSet: 'foo@var';


.define(Two);
.test 
  .define(Bar);
  prop: @@fooSet;

.test2 
  prop: @@fooSet;

想法 #2(参数混合)

.define(@var) 
  .foo() when (@var = Bar) 
    @fooBar: 0;
  
 .foo() when (@var = Two) 
    @fooTwo: 2;
  
 .foo() when (@var = Yep) 
    @fooYep: 4;
  
  .foo();


.define(Two);
.test 
  .define(Bar);
  prop: @fooBar;

.test2 
  prop: @fooTwo;

CSS 输出(两种想法)

.test 
  prop: 0;

.test2 
  prop: 2;

结论

但我不确定两者到底有多大用处,也不知道它是否可以在您的实际用例中有任何实际应用(因为您提到上述不是真正的用例)。如果你想要一个完全动态的变量在 LESS 中,那么它不能通过 LESS 本身来完成。

【讨论】:

非常感谢您的回答;不幸的是,您的任何想法都不能帮助我解决我的真实案例,尽管使用参数混合会减少我的一些代码。不过,我尝试了另一种解决方案,您可以检查 edit:对此有何想法? 您使用命名空间想法的编辑受到当前LESS does not support using dynamically generated classes as mixins 的影响。命名空间基本上是一个 mixin。 @Sunyatasattva:我也没有看到命名空间给你带来了什么好处,当你可以简单地在任何代码块中调用.define(0); 时,你会放置#namespace。两者都允许您在那时使用 @foo 变量。您可能需要进一步描述您实际尝试做的事情以及为什么要这样做。 感谢您提供该问题的链接。确实,您是对的,使用命名空间只会为我节省一点代码;一开始,当我尝试这种方法时,我希望我可以打电话给prop: #namespace > @fooBar,但事实并非如此。感谢您的帮助。 很棒的答案...需要一点时间来解决这个问题,但非常值得花时间!谢谢【参考方案2】:

我不太确定你想用什么,但我的建议之一是基于@ScottS 的回答。在我的现实世界中,我需要创建一个网络应用程序,它会显示几个品牌,每个品牌都有自己的文字颜色、背景等......所以我开始在 LESS 中寻找一种方法来完成这个,我可以在 SASS 上轻松完成,结果如下:

// Code from Seven Phase Max
// ............................................................
// .for
.for(@i, @n) .-each(@i)
.for(@n)     when (isnumber(@n)) .for(1, @n)
.for(@i, @n) when not (@i = @n)  
    .for((@i + (@n - @i) / abs(@n - @i)), @n);


// ............................................................
// .for-each

.for(@array)   when (default()) .for-impl_(length(@array))
.for-impl_(@i) when (@i > 1)    .for-impl_((@i - 1))
.for-impl_(@i)                  .-each(extract(@array, @i))


// Brands
@dodge : "dodge";
@ford : "ford";
@chev : "chev";

// Colors
@dodge-color : "#fff";
@ford-color : "#000";
@chev-color : "#ff0";

// Setting variables and escaping than
@brands: ~"dodge" ~"ford" ~"chev";

// Define our variable   
.define(@var) 
  @brand-color: '@var-color';


// Starting the mixin
.color() 
    // Generating the loop to each brand
    .for(@brands); .-each(@name) 
        // After loop happens, it checks what brand is being called
        .define(@name);
         // When the brand is found, match the selector and color
        .brand-@name & 
            color: @@brand-color;
        
    


.carColor 
    .color();

结果将是:

CSS

.brand-dodge .carColor 
    color: "#fff";

.brand-ford .carColor 
    color: "#000";

.brand-chev .carColor 
    color: "#ff0";

这非常棘手,我不得不使用几个元素来获得我需要的东西,首先使用了一组由 Seven Phase Max 提供的 mixin,你可以找到它here,然后,@ScottS 的答案就是我的谜题中缺少...希望这可以帮助您和其他需要创建一组变量以成为另一个变量的一部分并创建更具动态性的更少文件的人。

你可以复制我的整个代码并在http://lesstester.com/进行测试

【讨论】:

感谢您的评论。我会看看你的代码。我的问题已经差不多一年了,我不记得我到底想达到什么目标(我一定是以不同的方式实现的)。我会研究一下你发布的内容,并挖掘我的旧代码,看看它是否合适。 以防万一,我唯一的问题是你真的需要这些变量吗? (变量使这一切变得如此复杂)。就我个人而言,我根本看不到那里需要像@dodge-color 这样的东西(即在一个地方写dodge 只是为了让自己不得不在其他地方写dodge?)。对我来说,这些东西看起来完全可以用 this 或 this (+这些方法的任何合适组合)来解决。 @seven-phases-max 我理解你的意思,但是在某些情况下我们确实需要动态生成类......我的例子很简单,在这种情况下并没有什么意义,但在我的现实世界中,变量是必需的,因为我们只需要设置变量,让 LESS 完成其余的工作。另外需要注意的是,在我们的案例中,CMS 将品牌类设置为 body 标签,每个页面都有自己的字体颜色、背景图像等...... 我仍然不明白为什么不能使用@colors: dodge #fff, ford #000; 或类似名称来代替@dodge-color: #fff; @color-ford: #000;。以任何其他编程语言设计模式为例:当我们需要一些可重复的东西时,我们通过结构数组(或数组结构等)来定义这些数据,我们不会将我们需要的每一个值都声明为具有唯一名称的全局变量(又一次,为什么?)。好吧,没关系(它似乎已经跑题了),我只想提一下,对我来说,这整个想法看起来像是根本错误的方法。【参考方案3】:

要跟进已接受的答案,您还可以通过扩展 .define() 混合来定义变量的值,如下所示。这允许您在规则中使用一组临时变量。

.define(@var, @val) 
  .foo() when (@var = temp1) 
    @temp1: @val;
  
 .foo() when (@var = temp2) 
    @temp2: @val;
  
 .foo() when (@var = temp3) 
    @temp3: @val;
  
  .foo();


.define(temp2, 2);
.test 
  .define(temp1, 0);
  prop: @temp1;

.test2 
  prop: @temp2;

CSS 输出

.test 
  prop: 0;

.test2 
  prop: 2;

这里有一个更复杂的gist of how I use this 在一个mixin 中,用于生成具有background-size 的响应式背景图像:cover; (以及 IE8 后备)。

【讨论】:

【参考方案4】:

我没有时间构建示例,但以上都不像定义一个变量然后基于它组装导入那样快速和简单。然后只需要定义相同变量的多个文档。

@whitelabel: 'foo';
@import 'whitelabel/@whitelabel/colors';

【讨论】:

以上是关于在 LESS CSS 中动态定义一个变量的主要内容,如果未能解决你的问题,请参考以下文章

less一些总结

动态样式语言—LESS基础知识

less及编译工具介绍

less及编译工具介绍

less和sass的区别,你知道么?

less 动态样式语言