Skip to content
This page has been auto-translated and may contain errors.View in English

CSSの整理とスケーリング

docs.scrimba.com

新しいプロジェクトの最初のスタイルシートは書いていて楽しい。数百行進むと何かが変わる。1つのボタンの色を変えると、他の3つのボタンも変わってしまう。見出しは !important を付けるまで動かない。新しいルールを追加するたびに、古いルールを壊す可能性がある。CSSそのものはまだ正しい。足りなくなったのは、それを支える構造であり、構文ではなくその構造が、スタイルシートが1000行でも10万行でも実用的かどうかを決める。

CSSがスケーリングしにくい理由

CSSは**デフォルトではグローバル**です。書いたすべてのルールは、ページ上の任意の場所にあるマッチしたすべての要素に到達できます。p { color: navy; } と書くと、プロジェクト全体のすべての段落が紺色になります。意図したかどうかに関わらず。小さいページではこれは便利です。プロジェクトが大きくなると、ほとんどのトラブルの原因になります。

問題はルールの衝突として現れます。2つのスタイルシートが両方とも p をターゲットとしているか、一般的なルールと特定のルールが両方同じ要素に適用されます。今あなたはどちらが勝つかを計算する必要があります。あなたは CSSの仕組み でこのメカニズムを見ました。ブラウザーは詳細度と順序で衝突を解決します。CSSをうまくスケーリングすることは、最初からそうした衝突を作らないことについてです。

CSSに組み込みのスコープはありません。ルールは**グローバル**です。ページが読み込むすべてのファイル全体で、そのセレクターにマッチするあらゆる要素に適用されます。1つのコンポーネントのスタイルが別のコンポーネントに到達するのを止めるものはありません。言語にはそのルールがそのコンポーネントに属するという概念がないからです。その自由さがCSSを始めるのを素早く、成長させるのを厄介にしているのです。

コードベースが大きくなると、2つの力があなたに反対します。セレクターが増えると重複が増えるため、ルールが衝突します。ブラウザーは CSSの仕組み からのルールを使って各衝突を解決します。詳細度がまず、その次がソースの順序です。詳細度は上昇する傾向があります。なぜなら、今日の衝突に勝つ最速の方法は、少し具体性の高いセレクターを書くことであり、それが次の何かがそれをオーバーライドするために勝たなければならないバーを上げるからです。チェックせずに放っておくと、!important なしには誰も打ち負かすことができないセレクターで終わります。これがスタイルシートがメンテナンス可能に感じるのをやめる点です。

CSSは1つのフラットでグローバルな名前空間を出荷します。すべてのセレクターは同じスペースで競争し、1つの要素に複数のルールが適用される場合に勝つルールを拾うアルゴリズムであるカスケードは、各衝突を出所で解決してから、詳細度 でその後ソースの順序です。言語自体にはモジュール境界がないので、1つのコンポーネントのために書かれたセレクターは他のどれでも要素にマッチする自由があります。この章のすべてのスケーリング技術は言語が与えない境界を課すために存在します。

失敗モードは正確に名前を付く価値があります。以下の習慣すべてがそれに対する防御だからです。プレッシャーの下では、適用されないルールのための最速の修正は、そのセレクターをより具体的にすることです。親を追加して、別のクラスをチェーンして、idにフォールバックします。これらのそれぞれが直接の衝突に勝ち、ダウンストリームのすべてのもののための詳細度フロアを上げます。次のオーバーライドはより具体的である必要があります。これは**詳細度戦争**です。セレクターが上昇するだけ、!important で終わる一方向のラチェット。何も彼らを打ち負かすのが残っていないからです。脱出はこれらの戦いをより巧妙に勝つことではなく、詳細度を低くて平らなままに保つこと。それらはめったに開始しません。言語が今許す場所では、この章の終わりで説明されるカスケードレイヤーで詳細度から順序を完全に移動します。

css
/* ページ上のすべての段落に到達する1つのグローバルルール */
p {
  color: navy;
}

/* 別の場所にある2番目のルール、同じ要素のために競争しています */
.notice p {
  color: crimson;   /* .notice 内で勝ちます。より具体的です */
}
JunoCSSがスケーリングしにくい理由 CSSルールはグローバルです。1つのルールはページ全体の要素をスタイルでき、最初は便利で後で厄介です。プロジェクトが成長するにつれて、ルールが衝突を始め、ブラウザーは詳細度と順序を使って勝者を選ばなければなりません。CSSを整理することのほとんどは、ルールが最初から互いに戦わないように書くことについてです。
JunoCSSがスケーリングしにくい理由 CSSにはスコープがなく、すべてのルールはグローバルであり、マッチするあらゆる要素に到達する自由があります。コードベースが成長するにつれて、2つのことが噛みつきます。ルールが衝突し、詳細度が上昇します。なぜなら衝突の速い修正は常により具体的なセレクターだからです。その上昇をチェックしているままにして、スケーリングの残りははるかに簡単になります。
JunoCSSがスケーリングしにくい理由 CSSはモジュール境界のない1つのフラットグローバル名前空間であり、カスケードは詳細度で各衝突を解決し、その後順序で解決します。罠は詳細度ラチェットです。各速いオーバーライドはフロアを上げるため、次のものはより高く上がる必要があり、!important で底を打ちます。この章のすべての技術はラチェットが回転を始めない程度に詳細度を低く保つ方法です。

詳細度を低く平らに保つ

最も有用な単一の習慣は、**クラス**でスタイルすることであり、ほとんどの場合、一度に1つのクラスです。.card のようなクラスは素早く適用でき、再利用可能で、後で変更する必要があっても痛みがありません。単一のクラスは詳細度の低い穏やかなレベルだからです。

トラブルは2つのことから来ます。idと長いセレクターのチェーンです。#header のようなidはクラスよりもはるかにオーバーライドが難しく、.sidebar ul li a のようなチェーンは1つの正確な構造に結合しています。どこにでも配置できるプレーンなクラスを優先します。

CSSをメンテナンス可能に保つコア習慣は、詳細度を**低く平らに**保つことです。単一クラスでスタイルして、詳細度をスパイクさせる2つのもの、idと深い子孫チェーンを避けます。単一のクラスはスイートスポットです。意図したものをターゲットにするのに十分に具体的で、別の単一クラスが後でそれをオーバーライドでき、戦いなしでそれをできるのに十分に弱いです。

Idはクラスより遥かに高くスコアしているため、#id ルールはオーバーライドが痛く、あなたを上昇させます。長い子孫チェーンは異なる問題を引き起こします。.sidebar nav ul li a は詳細度を上げ、ルールを1つの正確な HTML 構造に溶接します。マークアップが変わるとすぐに壊れます。要素に独自のクラスを与えて、それを直接ターゲットにします。

詳細度を**低く平らに**保つことは、詳細度戦争に勝つのではなく、それを防ぐ習慣です。低いは各ルールが正しく選択しながらそれができるだけ少なくスコアすることを意味します。平らはルールが同じ低い重さの周りにクラスタリングするので、ソース順序だけでいずれかが他を上書きすることができることを意味します。ほとんどすべてが単一クラスセレクターであるスタイルシートはこのプロパティを持っています。何も難しく打ち負かす必要がありません。何も隣人より上でスコアされていないからです。

2つの構成は平らさを破り、両方ともデフォルトで避ける価値があります。Idはクラスより1桁大きい詳細度に貢献するため、単一の #id ルールはクラスルールのスタックの上に座り、別のidまたは !important でのみ打ち負かすことができます。クラスでスタイルしてidをフラグメントリンクと JavaScript フックのために予約します。深い子孫チェーンはセレクターあたりの詳細度を上げ、固定された祖先にルールを結合するため、.sidebar nav ul li a は上書きが難しく脆弱です。マークアップを変更してもそれは静かに照合を停止します。次のセクションの方法論は、あなたが直接要素に名前を付けることを可能にするために主に存在し、その先祖を通じてそれを見つけるためにチェーンに到達することはありません。

css
/* 優先:単一クラス、低く平ら */
.nav-link {
  color: navy;
}

/* 避ける:id、後で上書きするのが難しい */
#nav-link {
  color: navy;
}

/* 避ける:深いチェーン、脆弱で詳細度が高い */
.sidebar nav ul li a {
  color: navy;
}
Juno詳細度を低く平らに保つ クラスでスタイルしてください。ほとんどの場合、一度に1つのクラス。.card.nav-link のような単一クラスは再利用が素早く、後で上書きするのが痛みがありません。これはまさにあなたが望むものです。#header のようなidと .sidebar ul li a のような長いチェーンから遠ざかってください。どちらも変更するのがはるかに難しいからです。
Juno詳細度を低く平らに保つ 単一クラスはスイートスポットです。意図したものをヒットするのに十分に具体的で、別のクラスが戦いなしでそれをオーバーライドできるのに十分に弱いです。Idは詳細度を上げ、あなたを上昇させます。.sidebar nav ul li a のような深いチェーンはマークアップが移動する瞬間に壊れます。ルールが配置するのが難しい場合、要素に独自のクラスを与え、それをターゲットにしてください。
Juno詳細度を低く平らに保つ 低く平らなはすべてのルールが同じ小さい重さの近くでスコアすることを意味し、ソース順序だけで任意の衝突を解決できます。Idはクラスの1桁上に座り、!important または別のidだけがそれらを打ち負かします。フラグメントリンクとJSフックのために保持してください。深いチェーンは詳細度を上げ、ルールを1つのHTML形状に溶接します。これが直接要素に名前を付けることが先祖を通じてそれを狩るのを打つ理由です。

命名規則

クラスでスタイリングしたら、次の質問は何と呼ぶかです。.blue.thing2 のような名前は、クラスが何のためにあるのかを何も言わないため、すぐに崩れます。**命名規則**はクラスの名前を付ける合意された方法なので、その名前はそのクラスが何をするのか、どこに属しているのかをあなたに伝えます。

広く使われているのはBEMと呼ばれており、Block、Element、Modifierの略です。ブロックはカードのようなコンポーネントです。要素は、2つの下線で書かれた内部の部分です。修飾子は、2つのダッシュで書かれた変動です。

スタイリング単位としてのクラスで、命名はそれらを整理したままにするものになります。**命名規則**はクラス名の共有パターンであり、その仕事は名前を予測可能で衝突がないようにすることです。クラス名から、それがどのコンポーネントに属しているのか、どの部分をスタイルしているのかを理解でき、2つのコンポーネントが偶然同じ名前を再利用することはありません。

最も広く採用されている規則は BEM (Block、Element、Modifier) です。ブロックはコンポーネント (.card) であり、要素は2つの下線で結合された部分 (.card__title) であり、修飾子は2つのダッシュで結合された変動 (.card--featured) です。報酬は平らな詳細度です。すべての部分が独自の単一クラスを取得するため、.card__title に到達するために子孫チェーンが必要ありません。BEMと低く平らな習慣は互いに強化し合います。

**命名規則**は言語が欠けているスコープの代わりをします。コンポーネント境界をクラス名自体にエンコードすることにより、言語機能なしでコリジョンフリーの自己説明的な名前を与えます。クラスを読むと、そのコンポーネント、その部分、その変動を知ります。任意の一貫した規則がこれを提供します。価値は一貫性にあり、正確な句読点ではありません。

BEM (Block、Element、Modifier) は最も広く使われています。ブロックはコンポーネント (.card) に名前を付けます。要素は二重の下線で部分に名前を付けます (.card__title)。修飾子は二重ダッシュで変動に名前を付けます (.card--featured)。BEMを構成を超えて引き出す理由は、それが構成に詳細度を平らに保つことです。すべての要素は独自の単一クラスセレクターを取得するため、.card__title を直接アドレスして .card .title を書く代わりに、コンポーネント内のすべてのルールは同じ重さで座ります。これは前のセクションからの同じ低く平らなプロパティです。今、命名スキームから無料で落ちています。コストはHTMLのクラスリストが冗長であり、これはそれが買うことができる予測可能性のためにほとんどのチームが受け入れる取引です。

css
/* ブロック:コンポーネント自体 */
.card { }

/* 要素:ブロックの一部、2つの下線 */
.card__title { }
.card__body { }

/* 修飾子:ブロックの変動、2つのダッシュ */
.card--featured { }
html
<article class="card card--featured">
  <h2 class="card__title">週末のワークショップ</h2>
  <p class="card__body">レイアウトへの短い紹介。</p>
</article>
Juno命名規則 命名規則は、名前がそのクラスの目的を伝えるようにクラスに名前を付ける合意された方法です。BEMが一般的なものです。.card のようなブロック、2つの下線を持つその内側の .card__title のような要素、2つのダッシュを持つ .card--featured のような変動。BEMを使う必要はありませんが、いくつかの一貫したスキームを選んでそれに固執してください。
Juno命名規則 規則はクラス名を予測可能で衝突がないようにするため、名前はそのコンポーネントと部分を伝えます。BEMが広く使われている規則です。ブロック .card、要素 .card__title、修飾子 .card--featured。また、詳細度を平らに保ちます。すべての部分が子孫チェーンの代わりに独自の単一クラスを取得するからです。
Juno命名規則 規則はCSSが与えることのないスコープの代わりです。コンポーネント境界がクラス名に住んでいるため、名前は衝突なく自己説明的なままです。BEMは `.card として、 .card__title を持つブロック、要素、修飾子をエンコードし、.card--featured として、その実際の報酬は構成に詳細度を平らにすることであり、すべての部分が単一クラスになるからです。価格はマークアップのクラスリストが冗長であり、通常は予測可能性を得る価値があります。

ファイルの構造化

スタイルシートが成長するにつれて、1つの長いファイルは移動するのが難しくなります。一般的な修正は、CSSを、ルールが何をするかで数個のフォルダーに分割することです。**ベース**スタイル (body、見出しのようなプレーン要素のデフォルト)、コンポーネント (カード、ボタン、その他の部分)、ユーティリティ (間隔やテキスト配置クラスのような小さな単一目的ヘルパー)。

ファイルを分割するときに1つの詳細が重要です。それらを読み込む順序です。2つのルールが同じ詳細度を持つとき、後で来るものが勝ちます。そのため、後で読み込まれたスタイルシートはそれより前の詳細度をオーバーライドできます。最も一般的なものから最も特定のものへ、ファイルを読み込みます。

ロール別にCSSを分割して、成長するコードベースをナビゲート可能に保ちます。一般的な構造は3つのグループです。ベース (リセットと body、見出し、リンクのような要素のデフォルト)、コンポーネント (.card.btn のような自己完結したピース)、ユーティリティ (.text-center.mt-4 のような単一目的ヘルパー)。

これらのファイルを連結またはインポートする順序は化粧ではありません。ソース順序はカスケードのタイブレーカーだからです。2つのルールが等しい詳細度を持つ場合、後のものが勝ちます。そのため、あなたは最も具体的でないものから最も具体的なものへ読み込みます。ベースが最初に、その後コンポーネント、その後ユーティリティが最後に読み込まれるため、ユーティリティはコンポーネントをオーバーライドでき、コンポーネントはベースのデフォルトをオーバーライドでき、誰も詳細度を上げて強制する必要がありません。順序を正しく取得することは、すべてを単一クラスの詳細度で保持し、上書きが期待通りの場所に落ちるようにするものです。

ロール別にファイルを構造化することは、低く平らなCSSをスケール時にナビゲート可能に保つ方法であり、ロード順序は負荷をかけています。従来の分割は ベース (リセットと裸の要素のデフォルト)、コンポーネント (カプセル化されたピース、ファイルごとに1つ)、ユーティリティ (原子的な単一プロパティヘルパー) です。順序付けルールはカスケードから直接続きます。意図的に詳細度が平らに保たれているため、ソース順序が主要なタイブレーカーになるため、ファイルが読み込まれる順序は、等しい重さのどのルールが勝つかを決定します。

これが順序が最も具体的でないことから最も具体的な意図へ、ベース、次にコンポーネント、その後ユーティリティを実行する理由です。後のグループは詳細度のバンプなしで前のグループをオーバーライドできます。.text-center ユーティリティはコンポーネント独自のテキスト配置を打つ必要があり、同じ重さで最後に読み込まれるため、できます。これは機能しますが、規律によって施行される規則です。ユーティリティがコンポーネントの前にインポートされるのを防ぐ言語には何もなく、静かに全体のスキームを反転します。大きなチームで詳細度中のソース順序に依存することはまさにこの理由が最後のセクションの対象である理由、順序を位置的ではなく明示的にすることは脆弱です。

css
/* main.css: 順序は最も具体的でないものから最も具体的なものまで実行します */
@import "base/reset.css";        /* 要素のデフォルト */
@import "base/typography.css";

@import "components/card.css";    /* 自己完結したピース */
@import "components/button.css";

@import "utilities/spacing.css";  /* 最後に読み込まれるため、上書きできます */
@import "utilities/text.css";
Junoファイルの構造化 CSSをロール別にフォルダーに分割してください。要素のデフォルトのベース、カードやボタンのようなピースのコンポーネント、小さなヘルパーのユーティリティ。その後、それらを読み込む順序に注意してください。詳細度が関係ないとき、後のルールが勝ちます。一般的なものを最初に、特定のものを最後に読み込むため、ヘルパーはピースをオーバーライドできます。
Junoファイルの構造化 ロール別にファイルをグループ化してください。ベース、コンポーネント、その後ユーティリティ。詳細度が等しいとき、詳細度がタイブレーカーなので、最も具体的でないものから最も具体的なものへ読み込んでください。ユーティリティの最後に読み込まれるため、詳細度のバンプなしでコンポーネントをオーバーライドできます。順序を正しく取得することは、すべてを単一クラスの重さで保持し、上書きが落ちるようにするものです。
Junoファイルの構造化 詳細度が意図的に平らに保たれるとき、ソース順序は主要なタイブレーカーになり、ファイルロード順序は等しい重さのどのルールが勝つかを決定します。ベース、その後コンポーネント、その後ユーティリティは、後のグループが詳細度のバンプなしで前のグループをオーバーライドできることを意味します。勝ちは、チームが成長するにつれて順序が読める1つの宣言であり、インポート順序に関する部族の知識ではないことです。

カスケードを明示的にする

これまでのすべては、規則によってカスケードを管理可能に保ちます。低い詳細度、良い名前、注意深いファイル順序。ここでより深く行くにつれてもっと多くがあり、それは旅の方向を知る価値があります。モダンなCSSでは、ファイルが座っている場所に依存する代わりに、順序を直接制御し、より多くの人が同じスタイルシートで機能するにつれてカスケードを予測可能に保つ方法をあなたに与えます。あなたはプロジェクトが成長するにつれてこれらのツールに会い、上記の習慣がそれらの準備をするものです。

これまでの技術は、詳細度とソース順序を通じてカスケードを間接的に管理します。新しいCSSでは、それを直接管理できます。**カスケードレイヤー**は、@layer ルールで書かれた、名前付けられた順序バケットです。前面に層を宣言して、勝つ順序で、その後すべてのルールは層の内部は詳細度に関わらず、早期層のすべてのルールを打ちます。

css
/* 1回、最も負ける方から最も勝つ方へ順序を宣言します */
@layer base, components, utilities;

@layer components {
  .card { padding: 16px; }
}

@layer utilities {
  .p-0 { padding: 0; }   /* 等しい詳細度にもかかわらず .card を上書きします */
}

後の層が常に勝つため、ファイル順序が完璧である必要はなく、上書きを強制するために !important が必要なことはめったにありません。これが実際の利点です。層は「どのファイルが最初に読み込まれたか」の脆弱な領土から順序を移動し、すべてが読める1つの明示的な宣言に移動します。

ソース順序は位置的であるため、脆弱です。誰かがインポートを並べ替えるまで機能します。**カスケードレイヤー**の @layer ルールは、詳細度の上の*カスケードに座っている明示的な順序に置き換えます。層順序を宣言すると、カスケードは詳細度を見た前に層順序を相談します。そのため、早期層のルールが早期層で、より具体的な場合でも、後の層のルールは早期層のルールを打ちます。順序はファイル位置の副作用ではなく、読える名前の決定になります。

css
/* 1行はコードベース全体のための勝つ順序を修正します */
@layer reset, base, components, utilities;

@layer components {
  .card__title { font-size: 1.25rem; }
}

@layer utilities {
  .text-lg { font-size: 1.5rem; }   /* 勝ちます。ユーティリティはより後の層です */
}

これは2つの習慣を形作り直します。最初に、詳細度戦争をなくしてください。層順序は詳細度をランク付けするため、衝突に勝つためにより具体的なセレクターに到達するのをやめます。!important はほぼ必要ありません。その全体の仕事は逃げようとすることであり、詳細度があなたは別の方法で打つことができません。(層はさえ !important 自体を馴化し、その優先度を逆向きにして、早期層の*重要な宣言が勝つため、これはこのセクションを見直す価値があります。) 第二に、2つを整理するスタイル間の長い実行選択を明確にしてください。ユーティリティ最初のアプローチ、多くの原子的単一プロパティクラスから構成されたページ、およびコンポーネントのアプローチ、1つの意味クラスの後ろにスタイルをバンドルします。ほとんどのプロダクションコードベースは両方を実行し、層はそれらが設計で共存することを可能にします。components レイヤーにコンポーネントを入れ、後の utilities レイヤーにユーティリティを入れて、ユーティリティは詳細度を上げることなしでコンポーネントを確実にオーバーライドします。決定は「誰がカスケード戦いに勝つか」ではなく「このUI部分が良く読むかどうか」になり、カスケードは層順序ではなく誰がプッシャーセレクターを書いたかによって解決されるからです。その予測可能性はチームが成長するにつれて実際の賞です。勝つ順序は1つの宣言であり、すべてがインポート順序について部族の知識ではなく読むことができます。これらの層全体で色と間隔のような値を共有する必要がある場合、カスタムプロパティ はそれらをそれらをそれらを複製する代わりに一度定義することを可能にします。

Junoカスケードを明示的にする これまでのすべては習慣でカスケードを飼いならします。低い詳細度、クリアな名前、注意深いロード順序。さらに進むにつれて、CSSはファイルが最初に読み込まれた場所に依存する代わりに、勝つ順序を直接設定するツールを与えます。あなたはまだそれらを必要としません。この章の習慣は、あなたがそれらのためにあなたを準備するものです。
Junoカスケードを明示的にする@layer を使ったカスケードレイヤーは、名前付けられた順序バケットです。層順序を前面に宣言すると、後の層が詳細度に関わらず前の層のどんなルールも打ちます。つまり、ファイル順序が完璧である必要がなく、上書きを強制するために !important がめったに必要ありません。それは順序を脆弱なファイル位置から、すべてが読むことができる1つの行に移動します。
Junoカスケードを明示的にする カスケードレイヤーは詳細度の上に座るため、後の層が早期層のより具体的なルールでもそれを打ちます。これは詳細度ラチェットを解放し、ほとんどの !important の使用を引き直します。また、ユーティリティ最初とコンポーネントスタイルが共存することを可能にします。1つの層のコンポーネント、後の1つのユーティリティ、ユーティリティはどちらも上昇なしでコンポーネントをオーバーライドします。チームが成長するにつれて勝つのは、順序が1つの読める宣言であり、インポート順序についての部族の知識ではないことです。