定义变量:使用LESS CSS定义变量

47

假设我有三个分别用于网站不同页面的色彩方案。每种颜色都有一个浅色、中等色和深色定义,并且颜色方案由body中的类定义。假设“红色”色彩方案是默认值。如下所示:

颜色定义

@red-lt:   #121;
@red-md:   #232;
@red-dk:   #343;
@green-lt: #454;
@green-md: #565;
@green-dk: #676;
@blue-lt:  #787;
@blue-md:  #898;
@blue-dk:  #909;

基本默认样式示例

body { background-color: @red-dk;
  #container { background-color: @red-md;
     p { color: @red-dk; }
  }
}

不同的颜色方案样式示例

body.green { background-color: @green-dk;
  #container { background-color: @green-md;
     p { color: @green-dk; }
  }
}

我希望使用变量,这样我就不必为每个方案重新编写所有颜色变化,只需像这样写:

body.[color-var] { background-color: @[color-var]-dk;
  #container { background-color: @[color-var]-md;
     p { color: @[color-var]-dk; }
  }
}

...但我无法完全理解如何实现。请帮忙...


我不了解动态变量,但对于选择器,这个可以工作:~("body.@{color-var}") - Rob W
我撤回之前的评论,动态变量肯定是可能的:~"@{@{var}-suffix}"(请参见下面的答案)。 - Rob W
我曾经有同样的问题,但在这种情况下很难识别出自己的问题,如果问题以更通用的方式表达,对其他用户会更有帮助。 - Jon z
嗨,Jon,我不太擅长在没有具体例子的情况下解释更广泛的问题。如果您有办法使问题看起来更通用,请随意编辑(或至少添加一些关键词)。 - Kerri
@Kerri,有没有任何答案解决了你的问题?请标记为已接受。我猜最被投票的那个应该是——至少,它解决了我的问题 :) - igorsantos07
5个回答

81

使用插值转义、选择器中的括号以及参数化混合来达到期望的效果:

  • 动态变量通过插值实现:在字符串中,"@{variable}"将被替换为变量的值。它们也可以嵌套:给定@{@{var}-foo}@var: bar;,结果是"barfoo"
    生成的值会被引用。要去掉这些引号,请加上前缀~
  • 动态选择器通过选择器插值实现:body.@{var}会变成body.bar

示例:

@red-md:   #232;
@red-dk:   #343;

.setColor(@color) {
    body.@{color} { background-color: ~"@{@{color}-dk}";
        #container { background-color: ~"@{@{color}-md}";
         p { color: ~"@{@{color}-md}"; }
      }
    }
}
.setColor(~"red"); // Escape to prevent "red" turning "#FF0000"
//.setColor(~"blue"); etc..

变成:

body.red {
  background-color: #334433;
}
body.red #container {
  background-color: #223322;
}
body.red #container p {
  color: #223322;
}

注意:当这个答案最初被撰写时,选择器内插功能并不存在。如果你正在使用旧版的LESS编译器(在LESS 1.3.1a之前),请参考之前的版本以获取解决方案。旧方法的支持将在LESS 1.4.0中被删除。


+1 个好答案!我一直在寻找用 LESS 实现这个的方法,但是从文档中无法理解(通常我使用 Sass)。 - steveax
谢谢!我需要一点时间来理解这个,但它似乎是我正在寻找的。我会回来的! - Kerri
@moonunit7 http://leafo.net/lessphp/editor.html 的在线编辑器略有过时。最新版本(仍称为“v0.3.8”,尽管已添加了新功能)支持此答案中使用的语法。我已成功地使用最新的LESSPHP版本([提交21a012](https://github.com/leafo/lessphp/commit/21a012))运行此代码(http://pastebin.com/DhnW765E)。 - Rob W
如果这个解决了你的问题,你应该将其标记为“已回答”。(另外,向Rob点赞;LESS文档真是一团糟。) - jonathan3692bf
这是一个非常有用的答案。然而,这个语法更好、更易读:@currBgColor: "@{color}-dk"; background-color: @@currBgColor。另一个优点是,在使用这种语法时,你可以在调用 mixin/function 时添加这个动态参数(当使用 ~"@{@{color}-md}" 时似乎不可能),即 background-color: fade(@@currBgColor, 80%);。请参见 https://dev59.com/k2Ag5IYBdhLWcg3wOo79。 - Adriano
1
它们也可以嵌套:给定@{@{var}-foo}和@var: bar;,结果是“barfoo”。难道不是“bar-foo”吗? - RandomPleb

8
如果这些值确实遵循像这样的可预测格式,那么似乎是一个完美的应用场景,可以使用参数化混合解决:
Less:
@red:   #232;
@green: #565;
@blue:  #898;


.theme (@color) {
  background-color: @color - #111;
  #container {
    background-color: @color;
    p { color: @color + #111; }
  }
}

body.red {
  .theme(@red);
}

编译后的CSS:

body.red{background-color:#112211;}
body.red #container{background-color:#223322;}
body.red #container p{color:#334433;}

1
谢谢 - 我猜我应该在我的例子中更混合一些值 - 从数学上计算它们实际上是完全随机的。唯一不随机的是它们的名称 :/ - Kerri
@Kerri 使用 lighten(@color, <x>%);darken(@color, <y>%); 代替。 - Christoph
颜色是品牌调色板中非常特定的颜色公式,不遵循数学模式。 - Kerri
这很有帮助。 - Ahmad Vaqas Khan

6
我知道这个问题已经很老了,但对于那些看到这篇文章的人,我的答案也许可以帮助你。我不确定你想要用它来做什么,但是我的一个建议基于@ScottS的回答。在我的实际工作中,我需要创建一个Web应用程序,其中将显示几个品牌,每个品牌都有自己的文本颜色、背景等等...所以我开始追寻一种在LESS中实现这个目标的方法,而这个目标在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";
}

这很棘手,我不得不使用几个元素来获取所需的内容,首先使用了Seven Phase Max提供的一组混合器,你可以在这里找到它,然后@ScottS的答案是我的拼图中缺失的部分...希望这能帮助你和其他需要创建一组变量作为另一个变量的一部分并创建更动态的less文件的人。
您可以复制我的整个代码并在http://lesstester.com/上测试。

1

试试这个

@red-lt:   #121;
@red-md:   #232;
@red-dk:   #343;
@green-lt: #454;
@green-md: #565;
@green-dk: #676;
@blue-lt:  #787;
@blue-md:  #898;
@blue-dk:  #909;

@color: 'red-lt';

div{
background: @@color;
border: 1px solid lighten(@@color,20%);
}

0
据我所知,LESS 不支持“变量变量名”。但是,您可以以更语义化的方式重组声明:
/* declare palette */
@red-lt:   #121; 
@red-md:   #232; 
@red-dk:   #343; 
@green-lt: #454; 
@green-md: #565; 
@green-dk: #676; 
@blue-lt:  #787; 
@blue-md:  #898; 
@blue-dk:  #909; 

/* declare variables based on palette colors */
@lt: @red-lt;
@md: @red-md;
@dk: @red-dk;

/* ...and only use them for main declarations */
body { background-color: @dk;        
  #container { background-color: @md;        
     p { color: @dk; }        
  }        
}  

通过避免显式的颜色引用,这应该让您轻松地在调色板之间切换。


谢谢,但我还不确定是否理解了——似乎(a)lt、(a)md和(a)dk变量与(a)red-lt、(a)red-md和(a)red-dk变量完全相同,只是重命名为更短的变量。我不知道如何从那里切换到其他调色板。 (对不起,使用'(a)'而不是“at”字符——stackoverflow认为我正在尝试通知一堆用户) - Kerri
这个应该有多动态?我一定是读错了问题,但我认为你手动替换引用是合适的。另外,你是在客户端还是服务器端编译这些代码? - Oleg
抱歉如果我没有解释清楚。基本上,我想知道是否可以只编写一次“主声明”,然后,如果body类是“green”,例如,css会为所有颜色声明提取绿色值。换句话说,使用body类的名称来定义颜色变量名称的一部分。这可能不可能,但感觉Mixins或Parametric Mixins可以实现它 - 但我无法完全弄清楚如何实现。 - Kerri
@Kerri:为什么不在同一个文件中定义 .green p.red p 等呢?我不认为你能在运行时切换 body 颜色。 - Oleg
它们都在同一个文件中。我真的很糟糕地解释了这个问题!让我试着不用任何代码来解释:我有三种颜色方案(红色、绿色、蓝色)。每个方案都定义了dk、md和lt色调。这些色调分配到整个样式表中(一个div可能有dk边框,另一个div的背景颜色可能是lt)。每个页面都有一个定义颜色的body类(<body class="blue">)。我想使用"blue"的body类,并且无论在哪里定义颜色为"light"、"medium"或"dark",都将其变为"light blue"、"medium blue"等,而不必写出3次语句。 - Kerri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接