在LESS中使用属性名称中的变量(动态属性/属性名称插值) [英] Using variables in property names in LESS (dynamic properties / property name interpolation)

查看:5508
本文介绍了在LESS中使用属性名称中的变量(动态属性/属性名称插值)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到在SASS中编写的inuit.css有一个.vendor混合:

  @mixin vendor($ property,$ value ...){
-webkit - #{$ property}:$ value;
-moz - #{$ property}:$ value;
-ms - #{$ property}:$ value;
-o - #{$ property}:$ value;
#{$ property}:$ val;
}

有没有办法在LESS中复制这些奇怪的功能 更新:LESS> = 1.6
$ b b

从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< ; 1.6



据我所知,较少没有添加对动态插入属性的支持,这已经多次讨论过,请参见:





所以它通常做的方式将是参数混合和模式匹配...所以它是一个有点更硬的编码...但属性和不同的供应商无论如何有时需要一点不同



解决方法#1:将动态生成的属性注入属性值



解决方法的第一个选项有点丑,但我尝试它,它的工作原理是 http://less2css.org
所以,我试着将动态创建的属性注入到你硬编码的另一个属性的值(我只是给了一个随机的供应商名称 -inj 这里并指定它的值 ect ,但你可能想使用一些有用的,而不是如果你已经添加一个元素从所有供应商mixin包括)

  .vendors(@property,@value,@pre:ect){
-inj:〜@ {pre}; -webkit - @ {property}:@ {value}; -moz - @ {property}:@ {value}; -ms - @ {property}:@ {value}; -o - @ {property}:@ {value}; @ {property}:@ {value};
}

我们可以尝试一个例子 - 。让尝试转换短:



LESS:

  .test-class {
.vendors(transform,matrix(1,0,0,1,20,20));
.vendors(transform-origin,10px 10px);
}

CSS输出:
$ b

  .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,但感觉kinnda错=)






解决方法2:将动态生成的属性注入下面类的名称(最高为v1.3.3)



所以我再次使用这个想法...并想到一种不会产生不必要的属性的方法。它将动态创建的属性注入下一个类的名称中。让我告诉你我是如何工作的:



1)让我们定义一个一般的供应商mixin( @rest 参数将用于稍后排列多个供应商块)

  .vendors ,@value,@rest:){
@inject:〜@ {rest} -webkit - @ {property}:@ {value}; -moz - @ {property}:@ {value} -ms - @ {property}:@ {value}; -o - @ {property}:@ {value}; @ {property}:@ {value};
}

2)构建一个虚拟类/规则集我们希望供应商被包括在内,但是我们把它作为一个mixin,构造下一个类aswel - 所以我们真的做一个mixin,将递归地构建两个或更多的类。例如(使用与上面相同的例子),我们可以这样写(注意在 .vendor()中使用 @inject / code>调用将两个供应商块绑定在一起):

  .test(@nextclass){
。vendors(transform,matrix(2,0,0,2,20,20));
.vendors(transform-origin,10px 10px,@inject);
(〜{@ {inject}}。@ {nextclass}){/ * next class properties * /};
}

3)另一个类显示在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 {
/ *下一个类属性* /
}

$ b

编辑:为了更好的格式化,你可以包括javascript \\\
\t的插值,请参阅下面注释中的Scott建议。 >

这样,现在可以使用供应商mixin链接多个类,而不需要任何不必要的属性。






解决方法#3:使用递归将动态生成的属性注入到下面类(v1.4.0)的名称中:

Scott在其中一条评论中指出,1.4版本的更改不会允许解决方法#2。但是,如果我们有点智慧,我们可以克服这个问题。让我们看看上述解决方法的问题是什么,并解决它们。



1)第一个问题会是(〜。@ {index}){... 选择器插值已弃用,因此我们需要在单独的步骤中执行字符串插值。实现这个就足以从上面注入单个 .vendors mixin。



LESS:(使用Scott的换行建议):

  @nl:`\\\
\t`;
.vendors(@property,@value){
@inject:〜@ {nl} -webkit - @ {property}:@ {value}; @ {nl} -moz - @ {property }:@ {value}; @ {nl} -ms - @ {property}:@ {value}; @ {nl} -o - @ {property}:@ {value}; @ {nl} @ {property} @{值};;
}
.test(@nextclass){
.vendors(transform,matrix(2,0,0,2,20,20));
@inj:〜{@ {inject}`'\\\
'`}`'\\\
'`。@ {nextclass};
@ {inj} {/ * next class properties * /}
}
.this-class {
.test(next-class);
}

CSS输出:
$ b

  .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 {
/ *下一个类属性* /
}

2)第二个问题会是mixins中的变量不再'泄漏到他们的调用范围,但我注意到在1.4.0测试版,如果一个变量只引入一个mixin,它仍然可以从包含的规则集中调用,所以有了一个小的递归,你可以构造 .vendors 块,步骤将它们分配给一个新变量,然后将其用于注入。我也很兴奋,并使用在这个版本中引入的新的 extract()函数。对于变量 @i ,我们分配递归级别(要注入的供应商块数)。



LESS:

  @nl:`\\\
\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-origintransform;
@values:10px 10pxmatrix(2,0,0,2,20,20);

//要包含在同一类中的其他属性的字符串
@p:〜@ {nl} width:20px; @ {nl} height:12px; @ {nl } background-color:#000;;

.this-class {
.multi(@ properties,@ values,2,@ p);
@inj:〜{@ {inject}`'\\\
'`}`'\\\
'`.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 {
/ *下一个类属性* /
}

现在对于我来说,在1.4.0 beta版本中效果不错,但让我们看看未来会带来什么。


I noticed that inuit.css, which was written in SASS, has a .vendor mix-in:

@mixin vendor($property, $value...){
    -webkit-#{$property}:$value;
       -moz-#{$property}:$value;
        -ms-#{$property}:$value;
         -o-#{$property}:$value;
            #{$property}:$value;
}

Is there a way to replicate this in LESS with some of the odd features like e() and @{ } ?

解决方案

Update: LESS >= 1.6

As of version 1.6 (see changelog) property name interpolation is implemented in LESS. So you don't need any magic anymore. (For older versions, see my original answer.)

Your mixin would work basically as is:

LESS:

.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);
}


Original answer: LESS < 1.6

As far as I'm concerned less hasn't added support for dynamically inserted properties, which has been previously discussed on SO many times, see maybe:

So the way it is usually done would be with parametric mixins and pattern matching ... so it is a little bit more hard coding ... but properties and different vendors anyway sometimes require a little different format of parameters, so a little more control is added this way.

Workaround #1: inject dynamicaly generated properties into a properties value

The first option for a workaround is a bit ugly but I tried it and it worked on http://less2css.org. So, what I tried was to inject the dynamically created properties into a value of another property that you hard code (which I just gave a random "vendor" name -inj here and assigned it value ect, but you might want to use something usefull instead if you already add an element in from of all vendor mixin includes)

.vendors(@property, @value, @pre: ect) {
    -inj:~"@{pre}; -webkit-@{property}: @{value}; -moz-@{property}: @{value}; -ms-@{property}: @{value}; -o-@{property}: @{value}; @{property}: @{value}";
}

We can try it on an example - maybe something to make it worth ... lets try transform short:

LESS:

.test-class{
    .vendors(transform, matrix(1,0,0,1,20,20));
    .vendors(transform-origin,"10px 10px");
}

CSS output:

.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;
}

This seems to produce working css but it feels kinnda wrong =)


Workaround #2: inject dynamicaly generated properties into the name of the folowing class (up to v1.3.3)

So I played with this idea a little more ... and thought of a way that does not produce unnecessary properties. It injects the dynamically created properties into the name of the next class. Let me show you how I got it to work:

1) Let us define a general vendor mixin (the @rest argument will be used to line up multiple vendor blocks later)

.vendors(@property, @value, @rest:"") {
    @inject:~"@{rest} -webkit-@{property}: @{value}; -moz-@{property}: @{value}; -ms-@{property}: @{value}; -o-@{property}: @{value}; @{property}: @{value};";
}

2) Construct a virtual class/ruleset that we want the vendors to be included in, but we make it as a mixin that at the end constructs the next class aswel - so we really make a mixin that will recursively build two or more classes. For example (using the same example as above) we can write something like this (notice the use of @inject in the second .vendor() call to bind the two vendor blocks together):

.test(@nextclass){
    .vendors(transform, "matrix(2,0,0,2,20,20)");
    .vendors(transform-origin,"10px 10px", @inject);
    (~"{@{inject}} .@{nextclass}"){/*next class properties*/};
}

3) Now just we wrap this mixin into another class to display in the css:

.this-class{
    .test(next-class);
}

The resulting CSS will include this:

.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*/
}

The output will be just all in one line.

Edit: For nicer formatting you can include javascript interpolation of "\n" and "\t", see Scott's suggestion in comments below.

This way you can now chain up multiple classes all using the vendor mixin, without any unnecessary properties.


Workaround #3: inject dynamicaly generated properties into the name of the folowing class (v1.4.0) using recursion

I am adding this cause Scott pointed out in one of the comments that the changes that are coming with version 1.4 won't allow the workaround #2. But if we are a little resourceful, we can overcome this this problem. Let us see what are the problems of above workaround and fix them.

1) The first problem would be that the "(~".@{index}") { ... selector interpolation is deprecated", so we need to do the string interpolation in a separate step. Implementing this would be enough to inject a single .vendors mixin from above.

LESS: (using Scott's newline suggestion):

@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 output:

.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) The second problem would be that "variables in mixins no longer 'leak' into their calling scope", but I noticed in the 1.4.0 beta, that if a variable is only introduced in a mixin it still can be called from the including ruleset, so with a little recursion, you could construct the .vendors blocks, and in the last step assign them to a new variable, that you then use for injection. I also got excited and used the new extract() function introduced in this version of less. With variable @i we assign the level of recursion (number of vendor blocks to be injected).

LESS:

@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 output:

.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*/
}

Now this worked pretty well for me in 1.4.0 beta, but let us see what the future brings.

这篇关于在LESS中使用属性名称中的变量(动态属性/属性名称插值)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆