ウェブエンジニア問題集

詳細度とカスケード — スタイルが当たらない理由を理解する

「スタイルを書いたのに当たらない」「なぜか別のスタイルが優先される」——CSSあるあるの原因は、ほぼ詳細度(Specificity)カスケードにあります。

学習者学習者

スタイルを書いたのに効かない…!結局 !important を付けて無理やり通しちゃうんだけど、これでいいの?

スタイルが当たらなくて悩んでいるイメージ

カスケードとは

同じ要素に複数のスタイルが当たるとき、どれが優先されるかを決めるルールです。優先順位は次の順番で決まります。

  1. Origin(スタイルの出所)
    • ブラウザのデフォルト < 作者のスタイル < !important
  2. 詳細度(Specificity)
    • より具体的なセレクタが勝つ
  3. 記述順
    • 同じ詳細度なら後に書いたものが勝つ

詳細度の計算

詳細度は (a, b, c) の3つの数値で表されます。

セレクタの種類加算
インラインスタイル(style=""(1,0,0)
IDセレクタ(#id(0,1,0)
クラス・属性・擬似クラス(.class, [attr], :hover(0,0,1)
タイプ・擬似要素(div, ::before(0,0,1)
ユニバーサル(*(0,0,0)
p                  /* (0,0,1) */
.text              /* (0,1,0) */
#title             /* (1,0,0) */
.card p            /* (0,1,1) */
.nav .item:hover   /* (0,2,1) */
#header .nav a     /* (1,1,1) */

左から順に比較して、大きいものが勝ちます。


!important

p { color: red !important; }
p { color: blue; } /* これは負ける */

!important は詳細度の計算を無視して強制的に適用します。しかし乱用すると後から上書きできなくなり、メンテナンスが困難になります。基本的に使わないことが推奨されます。


継承(Inheritance)

一部のプロパティは親要素から子要素に継承されます。

body {
  font-family: sans-serif;
  color: #1a1a2e;
  line-height: 1.7;
}
/* すべての子孫要素に適用される */

継承されるプロパティ(代表): color, font-*, line-height, text-align など
継承されないプロパティ(代表): margin, padding, border, background, width, height など

inherit を明示的に書くと、継承されないプロパティも強制的に継承できます。

.child {
  border: inherit; /* 親のborderを継承 */
}

よくあるハマりどころ

クラスなのに当たらない

nav a { color: red; }    /* (0,0,2) */
.link { color: blue; }   /* (0,1,0) — こちらが勝つ */

.link の方が詳細度が高いので color: blue が適用されます。

IDセレクタが強すぎる

#content { font-size: 14px; }  /* (1,0,0) */
.content { font-size: 16px; }  /* (0,1,0) — 負ける */

IDセレクタを使うと詳細度が跳ね上がり、クラスで上書きできなくなります。


ちゃんと使うためのポイント

  • セレクタはなるべく詳細度を低く保つ(クラス中心、IDや要素セレクタの深いネストは避ける)
  • !important は使わない。どうしても使いたくなったらセレクタの詳細度設計を見直す
  • 「スタイルが当たらない」ときはデベロッパーツールで詳細度を確認する

次の最終章では、実務で頻繁に使うCSSの実践パターン集をまとめます。