グローバルCSSの時代の終わり

すべてのCSSセレクターはグローバルスコープに存在します。



CSSを扱ったことのある人は誰でも、このグローバル機能に我慢する必要があります。 かつて学術文書を様式化するために作成されたモデルは、現在、最新のWebアプリケーションを作成するための便利なツールではありません。



絶対に、すべてのセレクターは、別のセレクターを把握したり、「余分な」要素を定型化する可能性があります。 この「グローバルな」闘争では、セレクターはルールをページに適用しないため、完全に失われることさえあります。



cssファイルを変更するたびに、スタイルが存在するグローバル環境について慎重に検討する必要があります。 コードに最低限のサポートを提供するだけの労力を必要とする他のWeb開発テクノロジーはありません。



そうではないはずです。 グローバルスタイルの時代を後にする時です。 クローズド CSSの時間です。



多くの言語では、グローバルスコープの変更があったとしても非常にまれであることは受け入れられています。


Browserifyなどのツールのおかげで、 Webpackおよびjspmのフロントエンド開発者は、それぞれが依存する他のモジュールを明示的に要求する小さなモジュールで構成されるコードを作成できます。



しかし、CSSはそれ自体に免責され続けています。



私たちの多くはCSS機能に非常に慣れているため、最近までこの問題を解決する他の方法はありませんでした。ただし、ブラウザの製造元からのサポートを待つことを除きます。 そしてその後も、ほとんどのユーザーがShadow DOMを完全にサポートするブラウザーを手に入れる瞬間はもうすぐではありません。



開発者は、クラスの命名方法を規定する特定の規則体系を使用することを提案することにより、グローバルクラスの問題を回避しました。 OOCSS、SMACSS、BEM、SUIT-これらの手法はすべて、名前空間の衝突を回避し、スコープをシミュレートするように設計されています。



間違いなく、これはCSSを使いこなす良い試みでした。 しかし、これらのメソッドは本質的に問題を解決しませんが、回避しようとするだけです-どちらを選択しても、セレクターはグローバルのままです。



2015年4月22日すべてが変更されました


Webpackを使用すると、javascriptモジュール内に直接CSSをインポートできます。 このような「トリック」について初めて聞いた場合は、 こちらこちらをご覧ください



Webpack css-loaderが登場し、これを書くことができます:



require('./MyComponent.css');
      
      





一見奇妙に見えます。 javascript



ではなく.css



インポートされているという事実に目を閉じても。



結局、通常、 require



の呼び出しは変数に格納するrequire



があります。 これが行われない場合、原則として、これはグローバル変数が宣言されたことを意味します。 貧弱なアーキテクチャの明確な兆候。



しかし、これはCSSです-グローバルスコープは回避できません。 以前は考えられていました。



2015年4月22日に、Webpackの作者であるTobias Kopperscss-loader



新しい機能を追加し、 placeholdersという名前を付けました。 現在、それは可視性の閉じた領域として知られています。



この関数を使用すると、CSSファイルからクラス名をエクスポートし、javascript内でクラス名を要求できます。



要するに、代わりに:



 require('./MyComponent.css');
      
      





これを書くことができます:



 import styles from './MyComponent.css';
      
      





styles



変数の値は何ですか? まず、CSS自体がどのように見えるかを見てみましょう。



 :local(.foo) { color: red; } :local(.bar) { color: blue; }
      
      





この例では、css- :local(.identifier)



認識される構文を使用しています。 このようなコードは2つの識別子をエクスポートします[ 一意性のため、それらを「識別子」と呼びます。 perev。 ]: foo



およびbar







これらの識別子は、javascriptで使用できるクラス名を示します。 Reactの使用例を次に示します。



 import styles from './MyComponent.css'; import React, { Component } from 'react'; export default class MyComponent extends Component { render() { return ( <div> <div className={styles.foo}>Foo</div> <div className={styles.bar}>Bar</div> </div> ); } }
      
      





最も重要なことは、識別子が保証された一意のクラス名を指していることです。



閉じたスコープをシミュレートしようとして、セレクタごとに長いプレフィックスをスカルプトする必要がなくなりました。 さまざまなコンポーネントが独自のfoo



bar



を安全に使用でき、これにより名前の衝突が発生することはありません。



ここでパラダイムシフトがどれほど深刻かを考えてみてください。



これで、ページの無関係な要素がランダムに「痛む」ことはないと確信して、CSSファイルに変更を加えることができます。 そこで、CSSで閉じたスコープを構築するための適切なモデルを導入しました。



さらに、「グローバル」クラスが持っていたすべての利点はまだ利用できました。 唯一の違いは、開発の他の領域と同様に、必要なクラスを明示的にインポートする必要があることです。 コードはグローバル変数に依存しないでください。



サポートされているCSSコードの作成は、名前を作成するための一連のルールではなく、開発段階でのスタイルのカプセル化により可能になりました。


このシナリオでは、webpackの実際のクラス名をすべて制御しました。 そして、これは完全にカスタマイズできるものです。



デフォルトでは、css-loaderはクラスをハッシュに変換します。



たとえば、次のエントリ:



 :local(.foo) { … }
      
      





これは次のようにコンパイルされます。



 ._1rJwx92-gmbvaLiDdzgXiJ { … }
      
      





これは、開発およびデバッグ中に特に便利ではありません。 生成されたクラスを読みやすくするために、css-loaderに渡すパラメーターとしてwebpack構成で目的の形式を設定できます。



 loaders: [ ... { test: /\.css$/, loader: 'css?localIdentName=[name]__[local]___[hash:base64:5]' } ]
      
      





この場合、クラスは次のようにコンパイルされます。



 .MyComponent__foo___1rJwx { … }
      
      





これで、このコードが参照するコンポーネントの識別子と名前の両方がすぐに表示されます。



そして、環境変数NODE_ENV環境変数 )の助けを借りて、開発と本番のコンパイルロジックを分離できます



 loader: 'css?localIdentName=' + ( process.env.NODE_ENV === 'development' ? '[name]__[local]___[hash:base64:5]' : '[hash:base64:5]' )
      
      





スタイルの管理をwebpackに任せているため、クラス名の縮小を追加することがこれまで以上に簡単になりました。


たとえば、BEMなどによって名前空間を作成するための方法論を既に順守している場合、すべてのcssコードを分離されたスタイルに転送することは簡単で論理的なアクションになります。



すぐに、ほとんどのCSSファイルが排他的にプライベート識別子を使用することがわかります。



 :local(.backdrop) { … } :local(.root_isCollapsed .backdrop) { … } :local(.field) { … } :local(.field):focus { … } etc.…
      
      





グローバルクラスの必要性は、たまにしか発生しません。 これは考えを請います:



すべてのセレクターがデフォルトで閉じられており、特別な構文がグローバルセレクターを導入する場合にのみ使用される場合はどうなりますか?


それでもコードが次のようになっている場合はどうでしょうか:



 .backdrop { … } .root_isCollapsed .backdrop { … } .field { … } .field:focus { … }
      
      





通常の状況では、そのような名前は一般的すぎますが、css-loaderはこの問題を解決し、モジュールのスコープ内でのみ表示されるようにします。



また、グローバルクラスの必要性を回避できない場合には、特別:global



構文を使用できます。



したがって、たとえば、エントリはReactCSSTransitionGroupアドオンによって追加された標準クラスを使用するようになります。



 .panel :global .transition-active-enter { … }
      
      





このコードは、グローバルクラス.transition-active-enter



依存するプライベート.panel



識別子を作成し.transition-active-enter







デフォルトで識別子が閉じられるような構文を提供する方法を考えた途端、これはそれほど難しくないことが明らかになりました。



PostCSS助けになりました-プラグインの形で独自のCSSコンバーターを書くための素晴らしいツールです。 たとえば、最も人気のあるAutoprefixerはもともとPostCSSプラグインでしたが、現在では多くのスタンドアロンツールとして使用されています。



さらに、元の記事の著者は、アイデアを実装する実験ライブラリについて簡単に説明しています。 以下にその使用例を示します 著者のアイデアは後にコミュニティに受け入れられ、ウェブパック自体に統合されました。 このテクノロジーはCSS Modulesと呼ばれ、css-loaderの一部になりました。 パイロットプロジェクトはもはや関係ありません。 CSSモジュールを使用する最後の例はこちら



分離されたCSSクラスはほんの始まりに過ぎません。



ねえ、あなたはCSSを修正しました- ツイート


クラス名の制御を自動ビルドシステムに移すというアイデアには、大きな可能性があります。 最適化のために手動でクラスを結合する人間のコンパイラは必要なくなりました。 ビルドシステムの方がはるかに優れています。



さまざまなコンポーネントをスタイリングする一般的なクラスを自動的に生成できます。 このような最適化は、コンパイラ設定の単なるチェックになる場合があります。


クローズドCSSの使用を開始すると、後戻りはできないことに気付くでしょう。 CSSクラスを完全に分離し、 すべてのブラウザーで機能する手法を拒否するのはそれほど簡単ではありません。



クローズドCSSは、大規模プロジェクトでスタイルを整理して名前を付ける方法についての考え方を劇的に変えます。 私たちは旅の始まりに立ちます。 クローズドCSSの時代はまだ始まったばかりです。



CSSモジュールで自分試してください 。 それらが実際に動作しているのを見たら、これは誇張ではないことに同意するでしょう。グローバルなCSSの時代は終わりに近づいています。 未来はモジュール式です。






[ 出版-翻訳。 投稿者Mark Dalgleish 元の記事へのリンク ]



All Articles