LESSおよびSASSプリプロセッサーで変数を使用する方法

プリプロセッサで変数を管理するためのルールと設定をオーバーライドする手法







アーキテクチャの誤りの歴史、その結果、およびソースコードを適切に維持し、変更のコストを削減することを可能にする3つのルール。







背景



2014年に、同社はプロジェクトの再設計を開始し、当時のレイアウトの基礎を築きました。当時は、Bootstrap 3.0.1でした。 独立したサードパーティのライブラリとしてではなく、独自のコードと密接に統合しました。デザインの変数を編集し、LESSソースコードからカスタムブートストラップをコンパイルしました。 このプロジェクトは、ブートストラップ変数を使用し、新しい変数を設定ファイルに追加する独自のモジュールで覆われていました。







その瞬間、私はこれが正しいアプローチだと思いました。







結局、コードはスタイルを再定義することなく、目的の値ですぐにコンパイルされます。 CSSは、クリーンでコンパクトで、繰り返しがありません。 コンポーネントは、グローバル設定を使用してスタイル設定されます。







1年後、少し再設計して、プロジェクトは生産に入り、私たちは技術的な負債を取り上げました。 Bootstrapをバージョン3.6.xにアップグレードしようとしたときに、設定ファイルで新しいvariables.lessを保持するのは簡単ではないことがわかりました。 Bootstrapでは、変数の一部を名前変更または削除し、新しい変数を追加しました。 ブートストラップ自体のコンポーネントは問題なく更新されましたが、これらの変更によりコンパイル中にコンポーネントがクラッシュしました。







問題



状況を分析し、問題を定式化しました。







  1. 関連するコードが多すぎます。







    コンポーネント自体は個別のファイルにありました。 これにより、コンポーネントが独立しているという錯覚が生まれました。 しかし、コンポーネントは外部のvariables.lessファイルで宣言された変数を使用し、このファイルがないと機能しませんでした。 コンポーネントを取得して別のプロジェクトに移動することは不可能でした。 設定ファイルに沿ってドラッグする必要がありましたが、時間が経つとゴミになりました。







  2. グローバル変数が多すぎます。







    ブートストラップには、約400個の変数がありました。 未使用のBootstrapコンポーネントを無効にしましたが、再度必要になった場合に備えて、設定に変数を残しました。 また、変数を100個または1.5個追加しました。 すべての名前を思い出すことはできません。適切な名前をすばやく見つけるのは困難です。 命名規則やコメントがあっても、500以上の変数の構成内を移動するのは困難です。







  3. グローバル変数の名前は制御不能です。







    同じ変数を異なるファイルで使用でき、コード内のすべての発生を追跡するのは長く困難でした。 あるコンポーネントの変数の値を変更すると、他のコンポーネントが破損するリスクがありました。 ハードコードの開発者は、同様の名前と値を持つ新しい変数を作成し、命名ロジックに従わなくなりました。









決定方法



私たちの問題を克服するのに役立つ3つのルールを思いつきました。







  1. 変数は、宣言されているファイルでのみ使用されます。







    コンポーネント自体のファイルに必要な変数をすべて作成し、他のファイルの変数を使用しないのは正しいことです。 コンポーネントは独立し、コンパイル中に破損することなくプロジェクト間で接続および移動できます。 各コンポーネントには、他のコンポーネントで使用することは禁止されており、他のファイルでは呼び出されない独自の変数セットがあります。 変数が単一のファイルを超えない場合、変数がどのように使用され、何が影響するかを簡単に確認できます。







  2. コンポーネント内のすべての変数はローカルです。







    各コンポーネントには独自の変数があるため、それらをローカルにします。 これにより、ネーミングの問題がなくなります。コンポーネントでは、同じ名前で異なる値を持つ変数を使用できます-それらは互いに競合しません。







  3. グローバル変数は、設定ファイル内でのみ使用されます。







    最初の2つのルールのおかげで、グローバル変数の数を大幅に減らすことができますが、まだ必要です。 グローバル変数は、メインプロジェクトファイルまたはconfig.lessタイプのファイルで宣言されます。 ルール1も適用されます-変数はファイルの制限外では使用されません。 これは、コンポーネントファイル内でグローバル変数を使用できないことを意味します。 しかし、コンポーネント内のグローバル変数の値をプッシュする最初のルールに違反することなく、方法があります。 これを行う方法は、以下の例をご覧ください。









3番目のルールは冗長です。 最初の2つを観察することにより、3つ目を自動的に観察します。 しかし、実際には、ローカル変数を作成するのではなく、グローバル変数をすばやく使用するために、最も単純なパスに沿って進むという大きな誘惑があります。 3番目のルールは、これを行うことは有害であり、不必要な依存関係を作成し、コードバインディングにつながることを思い出させます。







実際にルールを適用します。







LESSでの実装



ページをスタイリングするための最も単純なコンポーネントを想像してください。 ルール#1に従って、コンポーネントファイル内に変数を作成します。







ルール1

変数は、宣言されているファイルでのみ使用されます。


/* page.css */ .page { padding: 40px; color: #000; background-color: #fff; }
      
      





そうだった。 コンポーネントコードの例。







 // page.less v0.1 @padding: 40px; @txt-color: #000; @bg-color: #fff; .page { padding: @padding; color: @txt-color; background-color: @bg-color; }
      
      





なっています。 変数はグローバルスコープで宣言され、あまりにも一般的な名前を持っています。 これは悪いです。







上記の例では、グローバルスコープで変数を宣言しました。このため、名前の競合が発生します。 同じ名前の変数が隣接するコンポーネントに現れると、コンポーネントは互いに壊れます。







ローカル変数



スコープは、セレクターの中括弧の間の「スペース」です: {



および}



。 中括弧内で宣言された変数は、これらの括弧内および子括弧内でのみ機能しますが、外部で使用することはできません。







角かっこがない場合、これは最高レベル- グローバルスコープです。







子スコープの変数は、親スコープの同じ名前の変数よりも大きくなっています。 グローバル変数は、名前の一致時に最も低い優先度を持ちます。







ルールNo. 2により、変数をローカルにし、セレクター内に移動します。







ルール2

コンポーネント内のすべての変数はローカルです。


 // page.less v0.2 .page { @padding: 40px; @txt-color: #000; @bg-color: #fff; padding: @padding; color: @txt-color; background-color: @bg-color; }
      
      





変数はセレクター内で宣言され、ローカルになったため、名前の競合は発生しません。







これで、他のコンポーネントとの名前の競合はなくなります。 最初と2番目の問題を解決しました。外部依存関係のない分離されたスニペットを取得しました。 しかし、この形式のコンポーネントのローカル変数を外部から再定義する方法はわかりません。 したがって、プロジェクトのグローバル変数を使用してコンポーネントをカスタマイズするために、異なる形式の表記法を思いつきました。







関数としてのミックスイン



LESSは、ミックスインを関数として使用できます。 ミックスイン内で変数を作成し、セレクター内でミックスインを呼び出すと、変数はこのセレクターのスコープで使用可能になります。







LESSドキュメントの関数としてのmixinを読んでください。

.page .page-settings()



内の変数の宣言を引き出し、 .page



セレクター内で呼び出します。







 // page.less v0.3 .page-settings() { @padding: 40px; @txt-color: #000; @bg-color: #fff; } .page { .page-settings(); padding: @padding; color: @txt-color; background-color: @bg-color; }
      
      





ミックスインは、セレクターの可視範囲に変数を配信します。







変数はグローバルミックスイン内でローカライズされます。 コードでミックスインを呼び出すと、変数は.page



セレクターのスコープで使用可能になりましたが、それでもローカルのままです。







このようなmixinはCSSコードを生成しません。その唯一のタスクは、目的のスコープに変数を配信することです。 たとえば、グローバルスコープでこのミックスインを呼び出すと、変数はグローバルになります。 ただし、変数をすぐにグローバルに宣言するのと同じです。







共通の名前を持ついくつかのグローバル変数の代わりに、1つのグローバルミックスインを作成しました。 プロジェクトに同じ名前の2つのコンポーネントを含めることはできません。つまり、ミックスインの名前は一意になります。







Mixin Fusion



LESSには変数の「遅延計算」があります。使用する前にLESS変数を宣言する必要はなく、後で宣言できます。 コンパイル時に、LESSパーサーは変数の定義を見つけ、CSSでこの変数の値をレンダリングします。







LESSドキュメントの遅延評価の例デフォルト変数のオーバーライドを参照してください。

変数を再定義すると、使用するすべての場所で、ソースコード内の順序で優先順位が付けられるため、最新の定義の値が有効になります。 この意味で、変数は定数のように振る舞います。







そのため、変数は使用前と使用後の両方で宣言でき、ミックスインは変数の一種です。 同じ名前で異なるコンテンツを持つ2つのミックスインを作成すると、それらは内部を結合します。 また、ミックスイン内に同じ名前の変数がある場合、オーバーライドが発生します。 最後のミックスインの優先順位が高くなっています。







3つのファイルを検討してください。







 // projectname.less @import 'normalize.css'; @import 'typography.less'; @import 'page.less'; //    ... @import 'config.less';
      
      





メインファイル。 コンポーネントと設定をインポートします。 構成は最後です。







 // page.less v0.3 .page-settings() { @padding: 40px; @txt-color: #000; @bg-color: #fff; } .page { .page-settings(); padding: @padding; color: @txt-color; background-color: @bg-color; }
      
      





成分 すべての変数はローカルであり、ミックスインに保存されます。







 // config.less @glob-text-color: white; @glob-bg-color: darkblue; //   .page-settings() { @txt-color: @glob-text-color; @bg-color: @glob-bg-color; }
      
      





プロジェクト構成 設定mixinを使用してコンポーネントパラメータを再定義します。







最も興味深いことはすべて設定で行われます。 グローバル変数を作成し、同じファイル内で使用してコンポーネントをカスタマイズしました。







Mixin .page-settings()



2回宣言されています。 デフォルト値を使用したpage.less



ファイル内の1回目、新しい値を使用したconfig.less



ファイル内の2回目。 コンパイルの段階で、ミックスインは接着され、新しい変数がデフォルトの変数をオーバーライドし、構成ファイルからの新しい値でCSSがレンダリングされます。







ルール3

グローバル変数は、設定ファイル内でのみ使用されます。

config.less



リストの最後に含まれていることに注意してください。 これは、構成内のmixin宣言がコンポーネントファイル内の元の宣言よりも高い優先度を持つようにするために必要です。 コンポーネントの前にconfig.less



を配置した場合、設定は適用されません。これは、「最後の定義が最も強い」というルールがミックスインにも作用するためです。







このようにして、コンポーネントのソースコードを変更せずに、コンポーネントファイル内でグローバル変数の値をロールしました。 この場合、3つのルールすべてが遵守されました。







  1. 変数はファイル内でのみ使用され、グローバル変数もconfig.less



    ファイルの外部では呼び出されませんでした。
  2. コンポーネント変数はローカルのままで、グローバルスコープを詰まらせませんでした。
  3. グローバル変数はコンポーネント内で直接使用されませんでしたが、グローバル変数の値はトリッキーな方法でコンポーネントに入りました。


制限事項



グローバル変数の名前がローカル変数の名前と一致することは不可能です。再帰が発生し、CSSはコンパイルされません。 間違えないようにするために、すべてのグローバル変数に接頭辞を付けて記述することをお勧めします。







 //   @txt-color: white; .page-settings() { //      @txt-color: @txt-color; }
      
      





間違った。 変数を再帰的に定義すると、コンパイルエラーが発生します。







 //  —   @glob-txt-color: white; .page-settings() { //    @txt-color: @glob-txt-color; }
      
      





そうだね。 グローバル変数には独自のプレフィックスglob-があり、名前の一致を排除します。







SASSでの実装



SASSはLESSとは異なり、スクリプトプログラミング言語に似ています。「遅延計算」はなく、変数はコードで使用する前に宣言する必要があります。 変数を定義してコードで使用し、それを再定義して再度使用すると、最初の呼び出しでCSSの元の値が取得され、2番目の呼び出しで新しい値が取得されます。 LESSのようなmixinトリックは失敗します。 しかし、他の解決策もあります。







マップオブジェクトにコンポーネントを設定するための変数セットを保存すると便利です。 これはキーと値のペアの配列です。 map-getメソッドは配列から特定の値を抽出し、map-mergeメソッドは2つの配列を1つに結合して、元の配列を補完または書き換えます。







SASSドキュメントのMapsについて読んでください。

外部からの再定義の可能性のない最も単純なコンポーネントは次のようになります。







 // page.scss v0.1 $page-settings: ( padding: 40px, bg-color: #fff, text-color: #000, ); .page { padding: map-get($page-settings, padding); background-color: map-get($page-settings, bg-color); color: map-get($page-settings, text-color); }
      
      





設定はマップオブジェクトに保存され、map-getを使用してコードで呼び出されます







別のファイルからコンポーネントを構成するには、元の設定で外部構成を制御する機能を提供する必要があります。 3つのファイルを検討してください。







 // projectname.scss @import: 'config'; @import: 'normalize'; @import: 'typography'; @import: 'page'; //    ...
      
      





メインファイル。

最初に設定をインポートし、次にコンポーネントをインポートします。







 // config.scss $glob-text-color: white; $glob-bg-color: darkblue; //  $page-settings: ( bg-color: $glob-bg-color, text-color: $glob-text-color, );
      
      





設定

グローバル変数を作成し、コンポーネントのパラメーターを再定義します。







 // page.scss v0.2 $page-override: ( ); // [1] @if variable-exists(page-settings) { $page-override: $page-settings; // [2] } $page-settings: map-merge(( padding: 40px, bg-color: #fff, text-color: #000, ), $page-override); // [3] .page { padding: map-get($page-settings, padding); background-color: map-get($page-settings, bg-color); color: map-get($page-settings, text-color); }
      
      





成分

チェックを追加:コンポーネントをオーバーライドする設定はありますか?







[1]



-コンポーネントでは、最初に空の$page-override



配列を持つ変数を宣言しました。







[2]



-次に、変数$page-settings



すでに存在するかどうかを確認しました。 また、構成内で既に宣言されている場合は、その値を変数$page-override



割り当てました。







[3]



-そして、元の設定と$page-override



を変数$page-settings









$page-settings



配列が以前にグローバル構成で宣言されている場合、 $page-override



はマージ時に設定を上書きします。 そうでない場合、変数$page-override



は空の配列を持ち、元の値は設定に残ります。







SASSのすべての微妙さを知っているわけではありませんが、この手法をより美しい方法で実装する方法があるかもしれません。

その結果、LESSとは異なり、コードで使用する前にすべての設定を事前に再定義する必要があるだけで、すべて同じ利点が得られます。







結論



あなたが何を書いているかは関係ありません-LESS、SASS、カスタムプロパティを備えたCSS、またはJavascript-できるだけ少ないグローバル変数が必要です。







CSSプリプロセッサでは、次の3つのルールを使用して混乱を回避します。







  1. 変数は、宣言されているファイルでのみ使用されます。
  2. コンポーネント内のすべての変数はローカルです。
  3. グローバル変数は、設定ファイル内でのみ使用されます。


コンポーネント内のグローバル設定をプッシュするには、変数をミックスイン(LESS)またはマップオブジェクト(SASS)に収集します。







正しい場所で設定を再定義します。LESSでは-組み込み後、SASSでは-組み込み前。







実際の例



私は2015年12月にLESSのためにこの手法を策定し、それ以来、仕事や個人のプロジェクトに適用しています。







1年半で、いくつかのパブリックnpmパッケージが登場しました。 これが実際の状況でどのように機能するかをよりよく理解するには、ソースコードをチェックしてください。







bettertext.css-サイトのタイポグラフィ。 11個の変数を使用して構成され、残りの40個は数式によって計算されます。 計算は別のミックスインで実行されるため、式を再定義できます。 コンポーネントにはクラスがなく、すべてのスタイルがタグに適用されます。 ローカルスコープを作成するために、変数内のすべてのセレクターをタグで配置します。LESSでは、これは「分離ルールセット」と呼ばれます。







LESSドキュメンテーションの独立したルールセットについて読んでください。

links.less-フォーカス、アニメーション、淡い下線付きのリンクのスタイル。 コンポーネントには、設定のミックスインの他に、独自のセレクター内のリンクに色を付けるための追加のグローバルミックスインがあります。







flxgrid.css-フレックス上のHTMLグリッドのジェネレーター。 5つの変数を使用して構成され、任意のブレークポイントと任意の数の列を持つアダプティブグリッドのクラスを生成します。 コンポーネントでは、計算とサービスミックスインはローカルスコープ内に隠されています。 グローバル設定で表示されるのはミックスインのみです。







space.less-レイアウトのインデントを管理するためのツール。 flxgrid.cssグリッドと連携して動作するように設計されています。 それらの適応性は同じ方法で設定されますが、space.lessは独自の設定とローカル変数の組み合わせを使用します-コードspace.lessはflxgrid.cssとは何の関係もありません。







ボーナストラック



今、新しいプロジェクトでLess上のBootstrap 3.xxを使用する必要がある場合、インポートされたすべてのBootstrapモジュールを変数(「切り離されたルールセット」)でbootsrtap-settings



し、 bootsrtap-settings



variables.less



ファイルのすべての設定をbootsrtap-settings



ブートストラップグローバル変数はグローバルではなくなり、ネイティブコード内で使用できなくなりました。 上記の例のように、必要に応じてBootstrap設定をカスタマイズし、プロジェクト設定でbootsrtap-settings



呼び出しbootsrtap-settings



。 次に、Bootstrapの更新では、カスタマイズされた設定を持つmixinのみを修正する必要があります。










ソース-http://paulradzkov.com/2017/local_variables/








All Articles