カスケードレイヤー
問題
CSSの詳細度(specificity)の競合は、バグやフラストレーションの最も一般的な原因の一つです。開発者は、詳細度の競合を管理するために、過剰に具体的なセレクター、!important、またはBEMのような命名規則に頼ります。サードパーティCSS(デザインシステム、コンポーネントライブラリ、リセット)を統合する際、どのスタイルが優先されるかの制御はますます困難になります。AIエージェントは、詳細度の競合を引き起こすCSSを生成したり、修正として!importantを使用したりすることがよくあります。
解決方法
@layerアットルールは、カスケードに対する明示的な制御を提供します。レイヤーの優先度はセレクターの詳細度より前に評価されます — 後で宣言されたレイヤーのシンプルなセレクターは、先に宣言されたレイヤーの複雑なセレクターに常に勝ちます。これにより、設計上の詳細度の競合が解消されます。
完全なカスケード評価順序は、origin/importance > インラインスタイル > cascade layers > 詳細度 > ソース順序です。
コード例
レイヤー順序の宣言
レイヤーが最初に宣言される順序が優先度を決定します。宣言リストの最後のレイヤーが最も高い優先度を持ちます。
/* Declare layer order upfront — this is the recommended pattern */
@layer reset, base, components, utilities;
/* Now populate layers in any order */
@layer reset {
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
}
@layer base {
body {
font-family: system-ui, sans-serif;
line-height: 1.6;
}
a {
color: #2563eb;
}
}
@layer components {
.button {
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
.button-primary {
background: #2563eb;
color: white;
}
}
@layer utilities {
.sr-only {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
}
.text-center {
text-align: center;
}
}
サードパーティCSSのレイヤーへのインポート
/* Put third-party styles in a low-priority layer */
@import url("normalize.css") layer(reset);
@import url("some-library.css") layer(vendor);
@layer reset, vendor, base, components, utilities;
レイヤーの優先度が詳細度を上書きする
@layer base, components;
@layer base {
/* High specificity: (0, 2, 1) */
nav ul li.active a.nav-link {
color: black;
}
}
@layer components {
/* Low specificity: (0, 1, 0) — but this WINS because
'components' is declared after 'base' */
.nav-link {
color: blue;
}
}
ネストされたレイヤー
@layer components {
@layer card {
.card {
border: 1px solid #e5e7eb;
border-radius: 8px;
}
}
@layer button {
.button {
padding: 0.5rem 1rem;
}
}
}
/* Reference nested layers with dot notation */
@layer components.card {
.card {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
}
revert-layerの使用
revert-layerキーワードは、プロパティ値を前のレイヤーで設定された値にロールバックします。
@layer base, theme, overrides;
@layer base {
a {
color: blue;
text-decoration: underline;
}
}
@layer theme {
a {
color: #8b5cf6;
text-decoration: none;
}
}
@layer overrides {
/* Roll back to the base layer value */
.classic-link {
color: revert-layer;
text-decoration: revert-layer;
/* Result: color is #8b5cf6 from theme?
No — revert-layer goes to the PREVIOUS layer.
Actually: color reverts to theme's value first,
then theme could revert-layer to base's value. */
}
}
revert-layerの実用的なユースケース:
@layer defaults, theme;
@layer defaults {
button {
background: #e5e7eb;
color: #1f2937;
}
}
@layer theme {
button {
background: #2563eb;
color: white;
}
/* Opt specific buttons out of theming */
button.no-theme {
background: revert-layer; /* Falls back to #e5e7eb */
color: revert-layer; /* Falls back to #1f2937 */
}
}
レイヤーに属さないスタイルが最も高い優先度を持つ
どのレイヤーにも属さないスタイルは、常にレイヤー内のスタイルに勝ちます。
@layer base {
p {
color: gray;
}
}
/* Unlayered — this wins */
p {
color: black;
}
ブラウザサポート
- Chrome 99+
- Firefox 97+
- Safari 15.4+
- Edge 99+
グローバルサポートは96%を超えています。
AIがよくやるミス
- レイヤーで優先度を管理する代わりに、スタイルのオーバーライドに
!importantを使用する - レイヤー順序を事前に宣言せず、最初に出現した順序に基づく予測不可能な優先度になる
- サードパーティ/ベンダーCSSをレイヤーの外に配置する(最も高いレイヤー外の優先度を与えてしまう)
- レイヤーに属さないスタイルがすべてのレイヤー内スタイルに勝つことを知らない
revert-layerとrevertを混同する —revertはユーザーエージェントスタイルシートにロールバックし、revert-layerは前のカスケードレイヤーにロールバックする- レイヤーの順序付けで優先度の問題を解決できるのに、過剰に具体的なセレクターを生成する
使い分け
- 複数のスタイルソースを持つ大規模なコードベースでの詳細度の管理
- 詳細度の競合なしにサードパーティCSSを統合する
- 明確なCSSアーキテクチャの確立(reset、base、components、utilities、overrides)
!importantの使用を構造化されたレイヤー優先度に置き換える- コンシューマーがコンポーネントスタイルを予測可能にオーバーライドする必要があるデザインシステムの構築
ライブプレビュー
レイヤーの順序が勝者を決定する
レイヤーの優先度が詳細度に勝つ