2026年7月9日
2026年7月9日
CSSの詳細度とカスケードレイヤーの仕組み|WordPressでスタイルが効かない原因
WordPressで追加CSSを書いたのに見た目が変わらない、というとき、多くの原因は「同じ要素に別のCSSも当たっていて、そちらが優先されている」ことです。どのCSSが勝つかは、カスケードと呼ばれる決まった順番の判定で決まります。この記事では、その判定順、詳細度の数え方、カスケードレイヤー(@layer)の扱い、そしてWordPressのコアやテーマのCSSとの関係を順に説明します。
カスケードの判定順
同じ要素の同じプロパティに複数の宣言が当たったとき、ブラウザは次の順に比べ、差がついた時点で勝ちを決めます。
- 出どころと重要度: ブラウザ既定のCSS、利用者のCSS、サイトのCSSの区別と、
!importantが付いているかどうか - コンテキスト: Shadow DOM の内側か外側か(通常のWordPressテーマではほとんど関係しません)
- style属性: 要素の
style="…"に直接書いた宣言は、セレクターで書いた宣言より優先されます - カスケードレイヤー:
@layerで分けたグループの順番 - 詳細度: セレクターの強さ
- 出現順: 上の条件がすべて同じなら、後から読み込まれた・後に書かれた宣言が勝つ
日常的に問題になるのは、4〜6の「レイヤー」「詳細度」「出現順」です。
詳細度の数え方
詳細度は、セレクターに含まれるものを3つの区分で数え、(ID, クラス, 要素)の形で表します。左の数が大きいほうが勝ち、同じなら次の数を比べます。
| 区分 | 含まれるもの |
|---|---|
| ID | #site-header |
| クラス | .button、属性セレクター [type="submit"]、疑似クラス :hover :first-child |
| 要素 | p、a、疑似要素 ::before |
全称セレクター * と結合子(空白、>、+、~)は数えません。
| セレクター | 詳細度 |
|---|---|
a |
(0, 0, 1) |
.entry-content a |
(0, 1, 1) |
.entry-content a:hover |
(0, 2, 1) |
#main .entry-content a |
(1, 1, 1) |
.a.b.c.d.e.f.g.h.i.j.k |
(0, 11, 0) |
最後の行のように、クラスをいくつ重ねても、ID 1つには勝てません。区分は繰り上がらないためです。
/* 同じ要素に両方が当たる場合、背景は red になる */
#site-header { background-color: red; } /* (1, 0, 0) */
body .site-header.is-sticky { background-color: blue; } /* (0, 2, 1) */
特殊な疑似クラス
:is()、:not()、:has()は、カッコ内でいちばん強いセレクターの詳細度になります:where()は中身にかかわらず詳細度が0です
:where() は「あとから上書きされる前提の初期スタイル」を書くのに使われます。WordPressのコアもこの仕組みを使っています(後述)。
!important
!important を付けた宣言は、付いていない宣言より先に判定され、詳細度や出現順に関係なく勝ちます。!important 同士がぶつかると、また詳細度と出現順で比べることになり、上書きのための !important が積み重なっていきます。使うのは、プラグインがstyle属性で直接指定している値を上書きするなど、ほかに手段がない場合に限るのが無難です。
カスケードレイヤー(@layer)
@layer は、CSSをグループ(レイヤー)に分け、詳細度より先にグループの順番で勝ち負けを決める仕組みです。Chrome・Edge 99、Firefox 97、Safari 15.4 以降で使えます(2026年11月時点)。
/* 最初にレイヤーの順番を宣言する。後ろのレイヤーほど強い */
@layer reset, base, components;
@layer components {
.button { background: #3858e9; }
}
@layer base {
/* 詳細度は (1, 1, 0) と高いが、base は components より前のレイヤーなので負ける */
#main .button { background: #1e1e1e; }
}
覚えておくべき規則は3つです。
- 後ろに宣言されたレイヤーほど強く、レイヤーの勝ち負けは詳細度より優先される
- どのレイヤーにも入っていないCSSは、すべてのレイヤーより強い(通常の宣言の場合)
!importantの宣言では順番が逆になり、前のレイヤーの!importantほど強くなる
WordPressで@layerを使うときの注意
WordPressのコア、テーマ、プラグインが出すCSSは、レイヤーに入っていないものが多くあります(開発者ツールで、対象のルールが @layer の中にあるかを確認できます)。そのため、自分のCSSだけを @layer で包むと、詳細度をどれだけ上げても、レイヤー外のコアやテーマのCSSに負けます。
レイヤーは、テーマやプラグインを自作していて、自分のCSS同士の優先順位を整理したいときに使い、既存のCSSを上書きする目的では、自分のCSSはレイヤーに入れずに書くのが基本です。
WordPressのCSSが出力される順番と強さ
グローバルスタイルは詳細度 (0, 1, 0) にそろえてある
WordPress 6.6 以降、theme.json やサイトエディターの「スタイル」から出力されるブロックのスタイルは、:root :where(.wp-block-button .wp-block-button__link) のような形で、詳細度が (0, 1, 0) にそろえられています(WordPress公式の開発者ノート「WordPress 6.6 CSS Specificity」による)。
このため、ブロックの見た目を変えるだけなら、クラス1つのセレクターで足ります。詳細度が同じなら、後に出力されたほうが勝ちます。
追加CSSはあとに出力される
- クラシックテーマ: 「外観 > カスタマイズ > 追加CSS」の内容は、
<style id="wp-custom-css">として<head>の終わり近く(wp_headの優先度101)に出力され、テーマやグローバルスタイルのCSSより後に来ます - ブロックテーマ: 「外観 > エディター > スタイル」の「追加CSS」(WordPress 6.2 以降)の内容は、グローバルスタイルのCSSの一部として出力されます
いずれも詳細度が同じなら勝ちやすい位置にあるため、まずは相手と同じ詳細度のセレクターで書いてみて、それでも負ける場合に相手のセレクターを確かめます。
テーマのstyle.cssを直接編集しない
テーマの style.css を直接書き換えると、テーマの更新で上書きされて消えます。CSSを足す場所は、追加CSSか、子テーマのスタイルシートにします。子テーマの style.css は、親テーマの style.css をコピーするのではなく、必要な見出し(Theme Name と、親テーマのフォルダー名を書く Template)と追加分のCSSだけを書きます。
/*
Theme Name: My Child Theme
Template: twentytwentyone
*/
.site-header {
border-bottom: 1px solid #ddd;
}
Template には親テーマの表示名ではなく、wp-content/themes/ の下のフォルダー名を書きます。
スタイルが効かないときの調べ方
- 対象の要素を右クリックし、「検証」(Chrome・Edge)または「調査」(Firefox)で開発者ツールを開く
- 「Styles(スタイル)」パネルで、自分が書いた宣言を探す
- 宣言が見つからない: CSSが読み込まれていないか、セレクターが要素に一致していません。クラス名の綴り、キャッシュ系プラグインやブラウザのキャッシュを確認します
- 宣言に取り消し線が付いている: ほかの宣言に負けています。上に表示されている(勝っている)ルールのセレクターを見て、詳細度を比べます。Chrome・Edge では、セレクターにマウスを合わせると詳細度が表示されます
- 勝っているルールが
@layerの外で、自分のルールがレイヤーの中: レイヤーの規則で負けています。自分のCSSをレイヤーの外に出します - 勝っているのが
element.style(style属性): セレクターでは勝てないので、ブロックの設定画面で値を変えるか、最後の手段として!importantを使います
上書きするときは、相手より少しだけ強いセレクターにするのが基本です。body や html を先頭に付ける、クラスを1つ足す、といった程度で足りることがほとんどです。IDや !important で一気に強くすると、次に上書きするときにさらに強いセレクターが必要になります。
まとめ
- どのCSSが勝つかは、重要度、style属性、レイヤー、詳細度、出現順の順に判定される
- 詳細度は(ID, クラス, 要素)で数え、区分は繰り上がらない。
:where()は常に0 @layerは詳細度より優先され、レイヤー外のCSSはすべてのレイヤーより強い。既存のCSSを上書きする目的では、自分のCSSをレイヤーに入れない- WordPress 6.6 以降、グローバルスタイルのブロック用CSSは (0, 1, 0)。追加CSSは後に出力されるので、同じ詳細度で書けば勝ちやすい
- 効かないときは開発者ツールで取り消し線と勝っているルールを確認し、相手より少しだけ強いセレクターにする