モダンなWebプロジェクトにおけるCSSの整理方法
CSSは書くのは簡単ですが、保守するのは困難です。数百行程度なら管理可能に感じますが、6ヶ月後には何を変更すると何が壊れるか分からず、変更することが怖くなります。問題はCSS自体ではなく、構造の欠如にあります。
ここでは、スケールし、可読性を保ち、モダンなツールと連携する実践的なCSS整理アプローチを紹介します。
重要なポイント
- ネイティブのCSSカスケードレイヤー(
@layer)を使用してスタイルの順序を制御し、詳細度の競合を解消する。 - デザイントークンをプリミティブからセマンティックへの階層構造で整理することで、テーマ変更を1箇所で済ませ、数十箇所の修正を不要にする。
- CSS Modulesや同様のスコープツールを使用して、コンポーネントスタイルをコンポーネントと同じ場所に配置する。
- ネストは浅く保つ — 通常、2階層が詳細度の問題が再発する前の限界。
- グローバルスタイルとコンポーネントスタイルを分離し、意図しない影響がない明確なファイル構造を採用する。
明確なレイヤー構造から始める
CSSアーキテクチャにおける最も重要な決定は、スタイルがどこに存在し、どの順序で適用されるかを制御することです。ネイティブのCSSカスケードレイヤー(@layer)は、これを明示的にします。
@layer reset, tokens, base, components, utilities;
レイヤーを事前に宣言することで、後のレイヤーが前のレイヤーよりも優先されます — 詳細度に関係なく。もはや、詳細度を高めたセレクタや!importantハックでカスケードと戦う必要はありません。
実践的なレイヤーの順序:
- reset — ブラウザのデフォルトを正規化
- tokens — CSSカスタムプロパティ(デザイントークン)
- base — 要素レベルのスタイル(
body、h1、a) - components — スコープされたUIスタイル
- utilities — 単一目的の上書き
この構造により、予測可能な詳細度と、任意のスタイルがどこに属するかについての明確なメンタルモデルが得られます。
デザイントークンは基盤に配置する
デザイントークンは、色、スペーシング、タイポグラフィ、その他のデザイン決定のための名前付き値です。CSSカスタムプロパティとして定義することで、コードベース全体で単一の信頼できる情報源を作成します。
:root {
--color-primary: oklch(55% 0.2 250);
--space-md: 1rem;
--font-body: "Inter", sans-serif;
}
トークンをプリミティブからセマンティックへと整理します:
- プリミティブ:
--blue-500: oklch(55% 0.2 250) - セマンティック:
--color-action: var(--blue-500) - コンポーネント:
--btn-bg: var(--color-action)
この階層により、コンポーネントスタイルを探し回ることなく、セマンティックトークンを変更するだけでプロジェクト全体のテーマを変更できます。
コンポーネントベースのスタイリング: スタイルをスコープする
グローバルスタイルシートはベーススタイルを処理します。コンポーネントはそれ以外のすべてを処理します。重要な原則: スタイルを所属するコンポーネントと同じ場所に配置する。
CSS Modulesは、React、Vue、またはバンドラーベースのプロジェクトでこれを実現する最も簡単な方法です。各.module.cssファイルはデフォルトでローカルスコープされます — クラス名はビルド時に一意の識別子に変換されるため、あるコンポーネントの.buttonが別のコンポーネントの.buttonと衝突することはありません。
/* Button.module.css */
.button {
background: var(--btn-bg);
padding: var(--space-sm) var(--space-md);
}
ネイティブCSSネスト(現在すべてのモダンブラウザでサポート)も、コンポーネントスタイルにおけるプリプロセッサの必要性を減らします:
.card {
padding: var(--space-md);
& .card-title {
font-size: 1.25rem;
}
}
ネストは浅く保ちましょう — 通常2階層で十分です。深いネストは、避けようとしていた詳細度の問題を再現します。
ネイティブ@scopeは現在広く利用可能ですが、アプリケーションコードではCSS Modulesやフレームワークレベルのスコープほど一般的ではないため、デフォルトではなく新興オプションとして扱ってください。
Discover how at OpenReplay.com.
ユーティリティファーストCSS: Tailwind v4の位置づけ
Tailwind CSS v4は異なるアプローチを取ります: コンポーネントCSSを書く代わりに、ユーティリティクラスを使用してマークアップ内で直接スタイルを構成します。バージョン4はCSS優先の設定モデルに移行しました — JavaScriptの設定ファイルではなく、@themeを使用してCSSファイル内でTailwindを設定します。
@import "tailwindcss";
@theme {
--color-primary: oklch(55% 0.2 250);
}
Tailwindは、高速な反復と一貫したデザイン制約を求めるチームに適しています。トレードオフは、冗長なマークアップとセマンティックでないクラス名です。多くのチームはハイブリッドアプローチを使用します: レイアウトとスペーシングにはTailwindユーティリティ、複雑なコンポーネントロジックにはCSS Modulesまたはカスタムプロパティを使用します。
実践的なファイル構造
ほとんどのプロジェクトでは、この構造がうまくスケールします:
styles/
index.css ← インポートのみ、@layer順序を宣言
tokens.css ← デザイントークン
reset.css ← ブラウザの正規化
base.css ← 要素スタイル
utilities.css ← ヘルパークラス
components/
Button/
Button.jsx
Button.module.css
グローバルスタイルはstyles/に配置します。コンポーネントスタイルはコンポーネントの隣に配置します。正当な理由なしにこの境界を越えるものはありません。
まとめ
優れたCSS整理は、いくつかの一貫した習慣に帰着します: レイヤーの順序を早期に宣言し、ルートでデザイントークンを定義し、コンポーネントスタイルをローカルにスコープし、セレクタを浅く保つこと。厳格な方法論は必要ありません — チーム全体が理解し、従う明確な規約が必要です。
シンプルに始めましょう。プロジェクトが要求する場合にのみ構造を追加します。
よくある質問
はい。Tailwind v4はネイティブカスケードレイヤー(theme、base、components、utilities)を中心に構築されています。その出力をラップする代わりに、自分のCSSを適切なレイヤーに配置することでカスケードを制御し、Tailwindのユーティリティと予測可能に組み合わせることができます。
それらは異なる問題を解決します。CSSネストは冗長性を減らし、関連するルールをグループ化しますが、クラス名をスコープしません。CSS Modulesはビルド時に一意の識別子を生成することでローカルスコープを保証します。buttonやtitleのようなクラス名を複数のコンポーネントが共有する可能性があるプロジェクトでは、CSS Modulesがより信頼性の高い分離メカニズムです。
すべてのデザイントークンはCSSカスタムプロパティですが、すべてのカスタムプロパティがデザイントークンというわけではありません。デザイントークンは、ブランドカラー、スペーシングスケール、タイプサイズなどの意図的なデザイン決定を表します。プリミティブからセマンティックへの階層構造で整理されているため、単一のセマンティックトークンを変更するだけで、個々のコンポーネントスタイルを編集することなくプロジェクト全体のテーマを変更できます。
TailwindのようなユーティリティファーストCSSは、迅速なプロトタイピングと、マークアップ内でスタイル決定を同じ場所に配置することを好むチームに最適です。コンポーネントスコープCSSは、複雑なUIロジックや厳格な関心の分離を持つプロジェクトに適しています。多くのチームは両方を組み合わせ、レイアウトとスペーシングにはユーティリティを使用し、ステートフルまたは高度にカスタマイズされたコンポーネントにはスコープスタイルシートを予約します。
Truly understand users experience
See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data. . Check our GitHub repo and join the thousands of developers in our community..