このページの中身

CSSの仕組み

「なぜか上書きできない」の原因は、5段のどこかにあります。順に見れば、だいたい3段目までで見つかります。

CSSの適用が決まる順序と、詳細度の数え方を示した図
図を大きく見る
図の中身を文字で読む
  • 「上書きできない」ときは、この順に上から確かめる。
  • 1. !important が付いているか 付いていれば、以下はすべて無視される
  • 2. カスケードレイヤーの順序 後から宣言したレイヤーが勝つ。詳細度より先に効く
  • 3. インラインスタイルか style 属性は、レイヤー外の通常宣言より強い
  • 4. 詳細度の点数 同じレイヤーの中で、大きいほうが勝つ
  • 5. 記述順 ここまで同点なら、後に書いたほうが勝つ
  • 詳細度=3つの数の組。左の桁が1つでも多ければ、右がいくつあっても勝つ。
  • セレクタ ID クラス・属性・擬似クラス 要素・擬似要素
  • #main .card p 1 1 1 ID が1つあるので最強
  • .card .title.is-active 0 3 0 クラスを何個重ねても届かない
  • :where(.card) p 0 0 1 :where() の中身は 0 と数える
  • :where() で包むと詳細度が上がらないので、上書きしやすい土台になる。逆に :is() は、中で最も強いものが採用される。

ひと目で#

「なぜか上書きできない」の原因は、ほぼこの5段のどこかにあります。

カスケード
どの宣言を採用するかを決める仕組み
詳細度
セレクタの強さ。ID、クラス等、要素の3つの数の組
カスケードレイヤー
@layer で層を作る。詳細度より先に効く
カスタムプロパティ
--name で値に名前を付ける。継承する
論理プロパティ
上下左右ではなく、文章の流れで方向を書く
ボックスモデル
幅がどこまでを含むか。border-box にすると外周まで

上書きできないときに見る順#

順確かめること
1!important が付いていないか
2相手があとのカスケードレイヤーにいないか
3インラインの style になっていないか
4詳細度で負けていないか
5相手のほうがあとに書かれていないか

使い分け#

こういうときやること
外部ライブラリを上書きしたい@layer で層の順を決める。詳細度を上げない
上書きしやすい土台を作りたい:where() で包む。詳細度が0になる
命名の衝突を避けたいBEM。ブロック、要素、修飾子で名前空間を作る
クラスを組み合わせて組みたいユーティリティファースト
縦書きや多言語に備えたい論理プロパティ(margin-inline など)

詳細度で戦わない#

引き継いだサイトで色を1つ変えたいだけなのに、既存のセレクタが長くて効かない。ここでセレクタを伸ばして勝つと、次に直す人はさらに長い一手を探すことになります。

セレクタを伸ばして勝つ場合と、カスケードレイヤーで層の順を決める場合を比べた図
図を大きく見る
図の中身を文字で読む
  • ✕ セレクタを伸ばして勝つ ○ 層の順で決める
  • 勝つたびに詳細度が積み上がる .btn(0,1,0) @layer vendor, site;(あとの層ほど強い)
  • vendor 層(先)
  • 引き継いだCSS・ライブラリをまるごと入れる
  • .nav .btn(0,2,0)
  • #header .nav .btn(1,2,0) site 層(あと)
  • 自分のCSS。.btn(0,1,0)のままで勝つ
  • #header .nav .btn.is-on { … !important }
  • あとの層は、詳細度に関係なく必ず勝つ
  • 次に直す人は、これより強い一手を探すことになる !important も長いセレクタも要らない
  • 層の順は @layer vendor, site; と最初に宣言した順で決まる。ファイルの読み込み順ではない。
  • 詳細度で戦うのは同じ層の中だけになり、競争が外へ広がらない。

あとの層は、詳細度に関係なく必ず勝ちます。 引き継いだCSSを丸ごと先の層に入れ、自分の分をあとの層に置けば、.btn の1クラスのままで上書きできます。層の順は最初の @layer の宣言で決まり、ファイルの読み込み順とは関係ありません。

このコードで動いている見本です

間違えやすいところ#

実装#

このコードで動いている見本です

直す例#

架空の案件を1つ例にとります。どこを見て、何をどう直すかを書きます。

引き継いだ会計事務所のサイトで、CTAボタンの色を1つ変えるだけの依頼です。.btn { background: … } を足しても効きません。開発者ツールで見ると、勝っているのは #main .contact-box ul li a.btn(1,2,3)でした。

前の担当者も同じ場面に立って、セレクタを伸ばして勝ったのだと分かります。ここでさらに長い一手を足すと、次の人はもっと長い一手を探します。

やることは、勝ち方を変えることです。引き継いだCSSを @layer vendor に丸ごと入れ、自分の分を @layer site に置きます。あとの層は詳細度に関係なく勝つので、.btn の1クラスのままで色が変わります。触るのは追加する1ファイルだけで、引き継いだCSSは1行も書き換えません。

コピーする#

方向を持つ余白は、上下左右ではなく文章の流れで書きます。縦書きや他言語に組み替えるとき、打ち消しの記述が要らなくなります。

このコードで動いている見本です

確認する#

使えるパターン#

このページで扱う語#

このページで扱う語を並べる本文では太字2 語

語の名前から引くなら用語索引へ。

BEM
ブロック・エレメント・モディファイアの3要素でクラス名を構成する命名規約。
ユーティリティファースト
1つの役割だけを持つ小さなクラスを組み合わせてスタイルを組む方式。

この話が要る場面#

このページが答えになる、現場の困り事です。困り事の側から探すと、同じ場所に着きます。

CSSが上書きできない

!important、カスケードレイヤーの順、インライン style、詳細度、記述順の順に確かめる。

このコードで動いている見本です

外部ライブラリのスタイルを上書きしたい

セレクタを長くしない。@layer で層の順を決めるほうが、あとで壊れない。

このコードで動いている見本です

上書きしやすい土台を作りたい

:where() で包む。中身の詳細度が0になるので、あとから素直に上書きできる。

このコードで動いている見本です

幅がpaddingの分だけ膨らむ

box-sizing: border-box を全体に当てる。

このコードで動いている見本です

縦書きや多言語に備えたい

上下左右ではなく論理プロパティで書く。margin-inline や inset-block-start。

このコードで動いている見本です

カスタムプロパティが効かない

:root にしか置いていない。要素に持たせると継承で子に届き、局所で切り替えられる。

このコードで動いている見本です

この場面のほかの困り事と、そのまま貼れる部品はCSSで詰まるにまとめてある。逆引きには全188件。

出典#

関連#

この資料は、Webサイトを作るときに引くためのものです。 何のために作ったか。作っているのは AK²Lab。