2026年7月9日

2026年7月9日

CSSの詳細度とカスケードレイヤーの仕組み|WordPressでスタイルが効かない原因

WordPressで追加CSSを書いたのに見た目が変わらない、というとき、多くの原因は「同じ要素に別のCSSも当たっていて、そちらが優先されている」ことです。どのCSSが勝つかは、カスケードと呼ばれる決まった順番の判定で決まります。この記事では、その判定順、詳細度の数え方、カスケードレイヤー(@layer)の扱い、そしてWordPressのコアやテーマのCSSとの関係を順に説明します。

カスケードの判定順

同じ要素の同じプロパティに複数の宣言が当たったとき、ブラウザは次の順に比べ、差がついた時点で勝ちを決めます。

  1. 出どころと重要度: ブラウザ既定のCSS、利用者のCSS、サイトのCSSの区別と、!important が付いているかどうか
  2. コンテキスト: Shadow DOM の内側か外側か(通常のWordPressテーマではほとんど関係しません)
  3. style属性: 要素の style="…" に直接書いた宣言は、セレクターで書いた宣言より優先されます
  4. カスケードレイヤー: @layer で分けたグループの順番
  5. 詳細度: セレクターの強さ
  6. 出現順: 上の条件がすべて同じなら、後から読み込まれた・後に書かれた宣言が勝つ

日常的に問題になるのは、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/ の下のフォルダー名を書きます。

スタイルが効かないときの調べ方

  1. 対象の要素を右クリックし、「検証」(Chrome・Edge)または「調査」(Firefox)で開発者ツールを開く
  2. 「Styles(スタイル)」パネルで、自分が書いた宣言を探す
  3. 宣言が見つからない: CSSが読み込まれていないか、セレクターが要素に一致していません。クラス名の綴り、キャッシュ系プラグインやブラウザのキャッシュを確認します
  4. 宣言に取り消し線が付いている: ほかの宣言に負けています。上に表示されている(勝っている)ルールのセレクターを見て、詳細度を比べます。Chrome・Edge では、セレクターにマウスを合わせると詳細度が表示されます
  5. 勝っているルールが @layer の外で、自分のルールがレイヤーの中: レイヤーの規則で負けています。自分のCSSをレイヤーの外に出します
  6. 勝っているのが 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は後に出力されるので、同じ詳細度で書けば勝ちやすい
  • 効かないときは開発者ツールで取り消し線と勝っているルールを確認し、相手より少しだけ強いセレクターにする

お気軽にご相談ください

お見積りへ お問い合わせへ
▲