更新:LESS >= 1.6
从 1.6 版开始(参见 changelog)属性名称插值在 LESS 中实现。所以你不再需要任何魔法了。 (对于旧版本,请参阅我的原始答案。)
您的 mixin 基本上可以按原样工作:
少:
.vendor(@property; @value){
-webkit-@{property}: @value;
-moz-@{property}: @value;
-ms-@{property}: @value;
-o-@{property}: @value;
@{property}: @value;
}
/*example*/
.test {
.vendor(transform, translateX(20px));
}
CSS:
.test {
-webkit-transform: translateX(20px);
-moz-transform: translateX(20px);
-ms-transform: translateX(20px);
-o-transform: translateX(20px);
transform: translateX(20px);
}
原答案:LESS
就我而言,less 并没有添加对动态插入属性的支持,这在之前已经讨论过很多次了,请参阅:
所以它通常的做法是使用参数混合和模式匹配......所以它有点更难编码......但无论如何属性和不同的供应商有时需要一些不同的参数格式,所以以这种方式添加了更多的控制。
解决方法 #1:将动态生成的属性注入到属性值中
解决方法的第一个选项有点难看,但我试过了,它在 http://less2css.org 上运行。
因此,我尝试将动态创建的属性注入到您硬编码的另一个属性的值中(我只是在这里给了一个随机的“供应商”名称-inj 并为其分配了值ect,但您可能想要如果您已经在所有供应商 mixin 包含的 from 中添加了一个元素,请改用有用的东西)
.vendors(@property, @value, @pre: ect) {
-inj:~"@{pre}; -webkit-@{property}: @{value}; -moz-@{property}: @{value}; -ms-@{property}: @{value}; -o-@{property}: @{value}; @{property}: @{value}";
}
我们可以在一个例子上试一试——也许值得一试……让我们尝试一下transform short:
少:
.test-class{
.vendors(transform, matrix(1,0,0,1,20,20));
.vendors(transform-origin,"10px 10px");
}
CSS 输出:
.test-class {
-inj: ect; -webkit-transform: matrix(1, 0, 0, 1, 20, 20); -moz-transform: matrix(1, 0, 0, 1, 20, 20); -ms-transform: matrix(1, 0, 0, 1, 20, 20); -o-transform: matrix(1, 0, 0, 1, 20, 20); transform: matrix(1, 0, 0, 1, 20, 20);
-inj: ect; -webkit-transform-origin: 10px 10px; -moz-transform-origin: 10px 10px; -ms-transform-origin: 10px 10px; -o-transform-origin: 10px 10px; transform-origin: 10px 10px;
}
这似乎可以产生有效的 css,但感觉有点不对 =)
解决方法 #2:将动态生成的属性注入到以下类的名称中(最高 v1.3.3)
所以我对这个想法进行了更多尝试......并想到了一种不会产生不必要属性的方法。它将动态创建的属性注入到下一个类的名称中。让我告诉你我是如何让它工作的:
1) 让我们定义一个通用的供应商混合(@rest 参数将用于稍后排列多个供应商块)
.vendors(@property, @value, @rest:"") {
@inject:~"@{rest} -webkit-@{property}: @{value}; -moz-@{property}: @{value}; -ms-@{property}: @{value}; -o-@{property}: @{value}; @{property}: @{value};";
}
2) 构建一个我们希望供应商包含在其中的虚拟类/规则集,但我们将其作为一个 mixin,最后构造下一个类 - 所以我们真的做了一个将递归构建两个或多个类的mixin。例如(使用与上面相同的示例)我们可以这样写(注意在第二个.vendor() 调用中使用@inject 将两个供应商块绑定在一起):
.test(@nextclass){
.vendors(transform, "matrix(2,0,0,2,20,20)");
.vendors(transform-origin,"10px 10px", @inject);
(~"{@{inject}} .@{nextclass}"){/*next class properties*/};
}
3) 现在我们将这个 mixin 包装到另一个类中以显示在 css 中:
.this-class{
.test(next-class);
}
生成的 CSS 将包括:
.this-class {
-webkit-transform: matrix(2, 0, 0, 2, 20, 20);
-moz-transform: matrix(2, 0, 0, 2, 20, 20);
-ms-transform: matrix(2, 0, 0, 2, 20, 20);
-o-transform: matrix(2, 0, 0, 2, 20, 20);
transform: matrix(2, 0, 0, 2, 20, 20);
-webkit-transform-origin: 10px 10px;
-moz-transform-origin: 10px 10px;
-ms-transform-origin: 10px 10px;
-o-transform-origin: 10px 10px;
transform-origin: 10px 10px;
}
.next-class {
/*next class properties*/
}
输出将全部在一行中。
编辑:要获得更好的格式,您可以包含 "\n" 和 "\t" 的 javascript 插值,请参阅下面 cmets 中 Scott 的建议。
通过这种方式,您现在可以使用供应商 mixin 链接多个类,而无需任何不必要的属性。
解决方法 #3:使用递归将动态生成的属性注入到以下类 (v1.4.0) 的名称中
我之所以添加这个原因,是因为 Scott 在其中一个 cmets 中指出,版本 1.4 中的更改不允许使用解决方法 #2。但如果我们有一点足智多谋,我们可以克服这个问题。让我们看看上面的解决方法有什么问题并解决它们。
1) 第一个问题是“(~".@{index}") { ... 选择器插值已被弃用”,因此我们需要在单独的步骤中进行字符串插值。实现这一点就足以从上面注入一个 .vendors mixin。
LESS:(使用 Scott 的换行建议):
@nl: `"\n\t"`;
.vendors(@property, @value) {
@inject:~"@{nl}-webkit-@{property}: @{value};@{nl}-moz-@{property}: @{value};@{nl}-ms-@{property}: @{value};@{nl}-o-@{property}: @{value};@{nl}@{property}: @{value};";
}
.test(@nextclass){
.vendors(transform, "matrix(2,0,0,2,20,20)");
@inj: ~"{@{inject}`'\n'`} `'\n'`.@{nextclass}";
@{inj} {/*next class properties*/}
}
.this-class{
.test(next-class);
}
CSS 输出:
.this-class {
-webkit-transform: matrix(2,0,0,2,20,20);
-moz-transform: matrix(2,0,0,2,20,20);
-ms-transform: matrix(2,0,0,2,20,20);
-o-transform: matrix(2,0,0,2,20,20);
transform: matrix(2,0,0,2,20,20);
}
.next-class {
/*next class properties*/
}
2) 第二个问题 将是“mixin 中的变量不再‘泄漏’到它们的调用范围内”,但我在 1.4.0 测试版中注意到,如果只引入一个变量在 mixin 中,它仍然可以从包含规则集中调用,因此通过一点递归,您可以构造 .vendors 块,并在最后一步将它们分配给一个新变量,然后将其用于注入。我也很兴奋,使用了这个less版本中引入的新的extract()函数。使用变量@i,我们指定递归级别(要注入的供应商块的数量)。
少:
@nl: `"\n\t"`;
.multi(@props,@vals,1,@inj) {
@property: extract(@props, 1);
@value: extract(@vals, 1);
@inject:~"@{inj}@{nl}-webkit-@{property}: @{value};@{nl}-moz-@{property}: @{value};@{nl}-ms-@{property}: @{value};@{nl}-o-@{property}: @{value};@{nl}@{property}: @{value};";
}
.multi(@props,@vals,@i,@inj:"") when (@i > 0) {
@property: extract(@props, @i);
@value: extract(@vals, @i);
@injnext:~"@{inj}@{nl}-webkit-@{property}: @{value};@{nl}-moz-@{property}: @{value};@{nl}-ms-@{property}: @{value};@{nl}-o-@{property}: @{value};@{nl}@{property}: @{value};";
.multi(@props,@vals,(@i - 1),@injnext);
}
@properties: "transform-origin" "transform";
@values: "10px 10px" "matrix(2,0,0,2,20,20)";
// string of other properties you want to include in the same class
@p: ~"@{nl}width:20px; @{nl}height:12px; @{nl}background-color:#000;";
.this-class {
.multi(@properties,@values,2,@p);
@inj: ~"{@{inject}`'\n'`} `'\n'`.next-class ";
@{inj} {/**/}
}
CSS 输出:
.this-class {
width:20px;
height:12px;
background-color:#000;
-webkit-transform: matrix(2, 0, 0, 2, 20, 20);
-moz-transform: matrix(2, 0, 0, 2, 20, 20);
-ms-transform: matrix(2, 0, 0, 2, 20, 20);
-o-transform: matrix(2, 0, 0, 2, 20, 20);
transform: matrix(2, 0, 0, 2, 20, 20);
-webkit-transform-origin: 10px 10px;
-moz-transform-origin: 10px 10px;
-ms-transform-origin: 10px 10px;
-o-transform-origin: 10px 10px;
transform-origin: 10px 10px;
}
.next-class {
/*next class properties*/
}
现在这对我来说在 1.4.0 测试版中运行良好,但让我们看看未来会带来什么。