web-dev-qa-db-ja.com

LESSのプロパティ名で変数を使用する(動的プロパティ/プロパティ名の補間)

SASSで書かれたinuit.cssには.vendorミックスインがあることに気づきました。

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

e()や@ {}のような奇妙な機能を使ってLESSでこれを複製する方法はありますか?

29
Isabelle Harms

更新:LESS> = 1.6

バージョン1.6以降(changelogを参照)、プロパティ名の補間は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);
}

元の回答:LESS <1.6

私に関する限り、動的に挿入されたプロパティのサポートは追加されていません。これは、以前にSOで何度も説明されていますが、次を参照してください。

したがって、通常行われる方法は、パラメトリックミックスインとパターンマッチングを使用することです...したがって、少しハードコーディングが必要です...しかし、プロパティとベンダーが異なると、パラメーターの形式が少し異なることがあるため、制御が少し強化されます。このように追加されます。

回避策#1:動的に生成されたプロパティをプロパティ値に挿入する

回避策の最初のオプションは少し醜いですが、私はそれを試しましたが、うまくいきました http://less2css.org 。だから、私が試したのは、動的に作成されたプロパティを、ハードコーディングした別のプロパティの値に挿入することでした(ここでランダムな「ベンダー」名-injを付け、値ectを割り当てましたが、すべてのベンダーのミックスインに含まれる要素をすでに追加している場合は、代わりに何か便利なものを使用します)

.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出力:

.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)ベンダーを含める仮想クラス/ルールセットを作成しますが、最後に次のクラスを作成するミックスインとして作成します-したがって、実際には2つ以上のクラスを再帰的に構築するミックスインを作成します。たとえば(上記と同じ例を使用して)、次のように記述できます(2番目の.vendor()呼び出しで@injectを使用して、2つのベンダーブロックをバインドすることに注意してください)。

.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 {
  /*next class properties*/
}

出力はすべて1行になります。

編集:より良いフォーマットのために、"\n""\t"のjavascript補間を含めることができます。以下のコメントで、Scottの提案を参照してください。

このようにして、不要なプロパティなしで、ベンダーのミックスインを使用して複数のクラスをチェーン化できるようになりました。


回避策#3:再帰を使用して、動的に生成されたプロパティを次のクラス(v1.4.0)の名前に挿入します

私はこの原因を追加しています。スコットはコメントの1つで、バージョン1.4で行われる変更では回避策#2が許可されないと指摘しました。しかし、私たちが少し機知に富んでいれば、この問題を克服することができます。上記の回避策の問題点を確認し、修正してみましょう。

1)最初の問題は、「(~".@{index}") { ...セレクター補間が非推奨」であるため、別のステップで文字列補間を実行する必要があります。これを実装するだけで、上から単一の.vendorsミックスインを注入できます。

LESS:(スコットの改行の提案を使用):

@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)2番目の問題は、「ミックスイン内の変数が呼び出しスコープに「リーク」しなくなった」ということですが、1.4.0ベータ版では、変数がミックスインでのみ導入された場合でも、インクルードルールセットから呼び出すことができるため、少し再帰的に.vendorsブロックを作成し、最後のステップでそれらを新しい変数に割り当てて、インジェクションに使用できます。また、興奮して、このバージョンのlessで導入された新しいextract()関数を使用しました。変数@iを使用して、再帰のレベル(注入されるベンダーブロックの数)を割り当てます。

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出力:

.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ベータ版ではかなりうまく機能しましたが、将来がどうなるか見てみましょう。

51
Martin Turjak

'minus'をプロパティ名として使用でき、パーサーはそれを無視しますが、文字列の残りを追加できることを追加したかっただけです。そうすれば、空のinject:;またはinjプロパティを取得することはありません。それはまだハッキーですがねえ... :)

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

例:

.prefix(transition, "all .2s, color 0s");

出力されます:

-webkit-transition: all .2s, color 0;
-moz-transition: all .2s, color 0;
-ms-transition: all .2s, color 0;
-o-transition: all .2s, color 0;
transition: all .2s, color 0;
3
Miro