在LESS CSS中动态定义变量

时间:2023-01-15 18:51:56

I am trying to create a mixin that dynamically defines variables in LESS CSS, by actually assigning them a composite name.

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

The simplified use-case (not the real one):

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

.define(@var){
    @foo{var}: 0;
}

Then one would call the mixin as such:

那么就可以这样调用mixin:

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

Since this kind of string interpolation is possible while using selectors names, I was wondering if the same would be possible for variable names; so far, I have had no luck with various syntaxes I tried (other than the above, I tried escaping, quoting, using the ~ prefix and so on).

由于在使用选择器名称时可以进行这种字符串插值,我想知道变量名是否可行;到目前为止,我对我尝试的各种语法没有运气(除了上面的内容,我尝试了转义,引用,使用〜前缀等)。

Edit

I just tried one more thing, and I feel I might be close; but I am experiencing an oddity of the LESS syntax. If I write this:

我只是尝试了一件事,我觉得我可能会接近;但我遇到了LESS语法的奇怪之处。如果我写这个:

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

And then call it like so:

然后像这样调用它:

.define(0)

I can then use @foo in the usual namespaced fashion:

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

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

However, the same doesn't apply in the case of a string-interpolated selector:

但是,在字符串插值选择器的情况下,同样的情况不适用:

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

.define(0, namespace);

.test {
     #namespace;
     property: @foo;
}

The above code gives me the following error:

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

Name error: #namespace is undefined

名称错误:#namespace未定义

However, the string interpolation was successful and valid. As a matter of fact, if I take away the .test part and modify the above to output a test property, I can see that the CSS is parsed correctly. I mean:

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

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

.define(0, namespace);

Outputs the following CSS:

输出以下CSS:

#namespace {
    prop: 0;
}

4 个解决方案

#1


12  

This Cannot Be Done

What you desire to do is not currently possible in LESS. I can think of two possible "workarounds" if you know ahead of time what variable names you want to allow to be used (in other words, not fully dynamic). Then something like one of the following could be done:

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

Idea #1 (Variable Variables)

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

  @fooSet: 'foo@{var}';
}

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

Idea #2 (Parametric Mixins)

LESS

.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 Output (for both ideas)

.test {
  prop: 0;
}
.test2 {
  prop: 2;
}

Conclusion

But I'm not sure how useful either would really be, nor do I know if it could have any real application in your actual use case (since you mention the above is not the real use case). If you want a fully dynamic variable in LESS, then it cannot be done through LESS itself.

但是我不确定它有多么有用,我也不知道它是否可以在你的实际用例中有任何实际的应用程序(因为你提到上面的内容并不是真正的用例)。如果你想在LESS中使用一个完全动态的变量,那么它不能通过LESS本身来完成。

#2


2  

I`m not really sure for what you want to use this, but one of my suggestion is based on @ScottS answer. On my real world, I need to create a web app, where it would show several brands and each brand have their own text color, background and so on... so I started to chase a way to accomplish this in LESS, what I could easily do on SASS and the result is below:

我不太确定你想要使用它,但我的一个建议是基于@ScottS答案。在我的现实世界中,我需要创建一个网络应用程序,它会显示几个品牌,每个品牌都有自己的文字颜色,背景等等...所以我开始追逐一种方法来实现这一点,我是什么很容易在SASS上做,结果如下:

LESS

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

Te result will be:

结果将是:

CSS

.brand-dodge .carColor {
    color: "#fff";
}
.brand-ford .carColor {
    color: "#000";
}
.brand-chev .carColor {
    color: "#ff0";
}

This is very tricky and I had to use several elements to get what I needed, first used a set of mixins provided by Seven Phase Max and you can find it here and than, the @ScottS answer was the piece that was missing fro my puzzle... hope this helps you and others that need to create a set of Variables to be part of another variable and create a more dynamic less file.

这是非常棘手的,我不得不使用几个元素来获得我需要的东西,首先使用Seven Phase Max提供的一组mixins,你可以在这里找到它,而@ScottS答案是我的拼图中遗漏的一块...希望这有助于您和其他需要创建一组变量的人成为另一个变量的一部分,并创建一个更动态更少的文件。

You can copy my entire code and test at http://lesstester.com/

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

#3


1  

To follow up on the accepted answer you can also define a value for the variable by extending the .define() mixin as follows. This allows you to use a temporary set of variables within a rule.

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

.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 Output

.test {
  prop: 0;
}
.test2 {
  prop: 2;
}

Here is a more complicated gist of how I use this in a mixin for generating responsive background images with background-size: cover; (and an IE8 fallback).

这是一个更复杂的要点,我将如何在mixin中使用它来生成具有背景大小的响应式背景图像:cover; (以及IE8后备)。

#4


1  

I don’t have time to build out the examples, but none of the above are as quick and simple as defining a variable and then assembling the import based on it. Then just have multiple documents where the same variables are defined.

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

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

#1


12  

This Cannot Be Done

What you desire to do is not currently possible in LESS. I can think of two possible "workarounds" if you know ahead of time what variable names you want to allow to be used (in other words, not fully dynamic). Then something like one of the following could be done:

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

Idea #1 (Variable Variables)

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

  @fooSet: 'foo@{var}';
}

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

Idea #2 (Parametric Mixins)

LESS

.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 Output (for both ideas)

.test {
  prop: 0;
}
.test2 {
  prop: 2;
}

Conclusion

But I'm not sure how useful either would really be, nor do I know if it could have any real application in your actual use case (since you mention the above is not the real use case). If you want a fully dynamic variable in LESS, then it cannot be done through LESS itself.

但是我不确定它有多么有用,我也不知道它是否可以在你的实际用例中有任何实际的应用程序(因为你提到上面的内容并不是真正的用例)。如果你想在LESS中使用一个完全动态的变量,那么它不能通过LESS本身来完成。

#2


2  

I`m not really sure for what you want to use this, but one of my suggestion is based on @ScottS answer. On my real world, I need to create a web app, where it would show several brands and each brand have their own text color, background and so on... so I started to chase a way to accomplish this in LESS, what I could easily do on SASS and the result is below:

我不太确定你想要使用它,但我的一个建议是基于@ScottS答案。在我的现实世界中,我需要创建一个网络应用程序,它会显示几个品牌,每个品牌都有自己的文字颜色,背景等等...所以我开始追逐一种方法来实现这一点,我是什么很容易在SASS上做,结果如下:

LESS

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

Te result will be:

结果将是:

CSS

.brand-dodge .carColor {
    color: "#fff";
}
.brand-ford .carColor {
    color: "#000";
}
.brand-chev .carColor {
    color: "#ff0";
}

This is very tricky and I had to use several elements to get what I needed, first used a set of mixins provided by Seven Phase Max and you can find it here and than, the @ScottS answer was the piece that was missing fro my puzzle... hope this helps you and others that need to create a set of Variables to be part of another variable and create a more dynamic less file.

这是非常棘手的,我不得不使用几个元素来获得我需要的东西,首先使用Seven Phase Max提供的一组mixins,你可以在这里找到它,而@ScottS答案是我的拼图中遗漏的一块...希望这有助于您和其他需要创建一组变量的人成为另一个变量的一部分,并创建一个更动态更少的文件。

You can copy my entire code and test at http://lesstester.com/

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

#3


1  

To follow up on the accepted answer you can also define a value for the variable by extending the .define() mixin as follows. This allows you to use a temporary set of variables within a rule.

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

.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 Output

.test {
  prop: 0;
}
.test2 {
  prop: 2;
}

Here is a more complicated gist of how I use this in a mixin for generating responsive background images with background-size: cover; (and an IE8 fallback).

这是一个更复杂的要点,我将如何在mixin中使用它来生成具有背景大小的响应式背景图像:cover; (以及IE8后备)。

#4


1  

I don’t have time to build out the examples, but none of the above are as quick and simple as defining a variable and then assembling the import based on it. Then just have multiple documents where the same variables are defined.

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

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