Kodokon kodokon.com

CSSアーキテクチャ:BEM、ユーティリティファースト、ファイル構成

BEMとユーティリティファーストのアプローチ、チームにおける実際のトレードオフを比較し、カスケードレイヤーでファイルを構造化しましょう。

11 分 · 3 問

このレッスンを Kodokon で開く

CSSはコンポーネントの規模では壊れません。プロジェクトの規模で壊れます。既存のルールに「勝つ」ためだけに詳細度がどんどん上がっていくこと、影響範囲がわからないコードを消すのが怖いこと、スタイルがある画面から別の画面へ漏れ出すこと。CSSアーキテクチャとは何よりも詳細度とスコープを管理する戦略です。2つの支配的な流派、BEMとユーティリティファーストは、同じ問題に正反対の道で答えています。

BEM(Block、Element、Modifier)はスタイル付けされるすべてのノードに名前を付けます。.card(独立したブロック)、.card__title(ブロックに属する要素)、.card--featured(ブロックのバリアント)。この規約はフラットな詳細度を保証し(どこでも単一のクラス、子孫セレクタは決して使わない)、順序の衝突が起きず、所有関係を記述する名前が得られます。その代償は、絶えず名前を考え出すことと、値の本当の重複(同じmargin-top: 16pxが20個のブロックに書き直される)です。

CSS
.card {
  padding: 16px;
  border-radius: 8px;
}

.card__title {
  font-size: 1.25rem;
}

.card__title--muted {
  color: #6b7280;
}

.card--featured {
  border: 2px solid var(--brand);
}
BEM:フラットな詳細度、明示的な所有関係

ユーティリティファーストのアプローチ(その支配的な体現がTailwind)は論理を逆転させます。もう名前はなく、HTMLの中で組み合わせる単一責任のアトミックなクラスだけです。その利点は測定可能です。名前付けの労力がゼロで、スタイルがマークアップと同じ場所に置かれ(コンポーネントを消せばそのスタイルも消える)、ユーティリティが共有されるため最終的なCSSバンドルのサイズがほぼ一定に保たれます。トレードオフもあります。冗長なHTML、DRYを保つためにコンポーネント層(React、Vue、パーシャル)を必要とするマークアップへの重複の移動、そして語彙を覚える学習コストです。

HTML
<article class="flex flex-col gap-4 rounded-lg
  border border-gray-200 p-4 shadow-sm">
  <h2 class="text-lg font-semibold">Invoice</h2>
  <p class="text-sm text-gray-600">
    Paid on March 12
  </p>
</article>
ユーティリティファースト:スタイルはマークアップの中に生きる

これらのアプローチは互いに排他的ではありません。成熟した多くのチームはこれらを組み合わせています。レイアウトと余白にはユーティリティを、複雑なパターンや状態にはコンポーネントクラス(BEMやCSS Modules)を使うのです。ファイル構成については、ITCSSの原則が今も基準です。汎用から具体へと順序づけます(リセット、基本要素、コンポーネント、ユーティリティ)。ネイティブの@layerルールは、この規約をエンジンレベルの保証に変えます。レイヤー間の優先順位は、そこに含まれるセレクタの詳細度とは無関係です。

CSS
@layer reset, base, components, utilities;

@layer base {
  h2 { font-size: 1.5rem; }
}

@layer components {
  #hero .btn { padding: 12px 24px; }
}

@layer utilities {
  .p-0 { padding: 0; }
}
カスケードレイヤー:順序が詳細度に勝つ

理解度チェック

このレッスンの要点をしっかり覚えているか確認しましょう。

  1. .card__title--mutedにおいて、--mutedのセグメントは何を表しますか?
    • CSSカスタムプロパティ
    • モディファイア:card__title要素のバリアント
    • card__titleの子要素
    • JavaScriptが管理する状態
  2. カスケードに対する@layerの主な貢献は何ですか?
    • レイヤーのセレクタの詳細度を上げる
    • レイヤーの順序をセレクタの詳細度より優先させる
    • Shadow DOMのようにコンポーネントのスタイルを分離する
    • レンダリングを高速化するためにレイヤーを並列に読み込む
  3. ユーティリティファーストのアプローチを採用するとき、どんなトレードオフを受け入れることになりますか?
    • ページ数に比例して大きくなるCSSファイル
    • 上書きしづらい高い詳細度
    • コンポーネント層に重複解消を頼る冗長なHTML