季節の変わり目に弱いosuga-hです。 お急ぎの方はクイズをすっ飛ばして、続きからお読みください。

突然ですがクイズです。

以下のHTMLとCSSで指定されているdivはマウスオーバで何色になるでしょう? ※答えは緑か赤かのどちらかです。

Q1. まずはジャブから

<style type="text/css">
.sample:hover .s1 div { background-color:#0F0}
.sample:hover .s1 div { background-color:#F00}
</style>
<div class="sample">
    <div class="s1">
        <div>このdiv</div>
    </div>
</div>
このdiv

Q2. idを付けてみる

<style type="text/css">
.sample:hover .s2 div#sample2 { background-color:#0F0}
.sample:hover .s2 div { background-color:#F00}
</style>
<div class="sample">
    <div class="s2">
        <div id="sample2">このdiv</div>
    </div>
</div>
このdiv

Q3. idとクラス

<style type="text/css">
.sample:hover .s3 div#sample3 { background-color:#0F0}
.sample:hover .s3 div.sample3 { background-color:#F00}
</style>
<div class="sample">
    <div class="s3">
        <div id="sample3" class="sample3">このdiv</div>
    </div>
</div>
このdiv

Q4. 親を持たせてみる

<style type="text/css">
.sample:hover .s4 #outer4 div.sample4 { background-color:#0F0}
.sample:hover .s4 div     #sample4    { background-color:#F00}
</style>
<div class="sample">
    <div class="s4">
        <div id="outer4">
            <div id="sample4" class="sample4">このdiv</div>
        </div>
    </div>
</div>
このdiv

Q5. 最後の問題

<style type="text/css">
.sample:hover .s5 #outer5 div.sample5 { background-color:#0F0}
.sample:hover .s5 div#sample5.sample5 { background-color:#F00}
</style>
<div class="sample">
    <div class="s5">
        <div id="outer5">
            <div id="sample5" class="sample5">このdiv</div>
        </div>
    </div>
</div>
このdiv
どうですか?全部わかりましたか? ここからが本題になります。

CSSルールの優先順位 詳細度(specificity)とは

CSSを書いていて、「あれ?追加したCSSが適用されないんだけど?」ということありませんか? そんな時は、十中八九、「詳細度」が既存のルールに負けています。※ブラウザのバグってこともあるけど・・・ ここからは詳細度とは何か?どうやって決まるのかを解説します。 詳細度に関してはの詳しい説明はW3Cのサイトでも確認できます。 Selectors Level 3 - 9. Calculating a selector's specificity

詳細度の求め方

 CSSルールの優先順位は単純にあとから定義してあれば有効というわけではなく、セレクタを定められたアルゴリズムで評価しそのスコアが高いものが優先されます。 このスコアの事を「詳細度(specificity)」と言います。ある要素に2つ以上のCSSセレクタがヒットしている時、詳細度が比較されるわけです。  詳細度の比較にはセレクタに含まれるid、クラス、html要素の数が使われ、それ以外のセレクタ(*など)は考慮されません。 簡単に詳細度の比較の様子を示します。
  1. セレクタに指定されているid、クラス、html要素の数をそれぞれ数える
  2. 指定されているidの数が多い方が強い
    ↓引き分けたら
  3. 指定されているクラスの数が多い方が強い
    ↓引き分けたら
  4. 指定されている要素数の多い方が強い
    ↓引き分けたら
  5. 後から定義された方が勝つ

style属性と!important

詳細度以外に優先順位に関わる要素としてhtml要素のstyle属性に記述されているスタイルと、!important指定されているスタイルがあります。 これらも含めての優先順位は以下のように決定されます。
  1. !important
  2. style属性
  3. 詳細度が一番高いCSSルール

実験してみよう!

詳細度の理解を深めるために色々実験してみましょう。

id x1個 vs クラス x10個

idの数が優先的に比較されるならどんなにクラスが大量に指定してあってもidで指定してあるルールが勝つはず。
<style type="text/css">
.sample:hover .t0 #test0 { background-color:#0F0}
.sample:hover .t0 .t00 .t01 .t02 .t03 .t04 .t05 .t06 .t07 .t08 .t09 { background-color:#F00}
</style>
<div class="sample">
    <div class="t0">
        <div class="t00">
            <div class="t01">
                <div class="t02">
                    <div class="t03">
                        <div class="t04">
                            <div class="t05">
                                <div class="t06">
                                    <div class="t07">
                                        <div class="t08">
                                            <div id="test0" class="t09">このdiv</div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
このdiv

style属性に!importantが書いてあったら誰も勝てない

style属性よりCSSルールで!important指定してある方が強いわけですが、style属性で定義されているスタイルに!importantを指定したらいかなる方法でも上書き出来ないはず。
<style type="text/css">
.sample:hover .t1 #test1 { background-color:#0F0;}
.sample:hover .t1 .t10 .t11 { background-color:#F00 !important}
</style>
<div class="sample">
    <div class="t1">
        <div class="t10">
            <div id="test1" class="t11" style="background-color:#00F !important">このdiv</div>
        </div>
    </div>
</div>
このdiv
マウスオーバしても色を変えられない。

詳細度を上げたかったら

詳細度の関係でセレクタを増やさなければいけないとき、いろんな方法で詳細度を上げる方法がありますが、私はだいたい以下のようなルールでセレクタを調整しています。
  • #target
    ↓とりあえず要素名を追加
  • div#target
    ↓親があれば
  • div div#target
    ↓idの付いている親がすでに存在するなら
  • #parent #target
    ↓どうにもならない場合の最終手段
  • #target { width : 100px !important }
!importantを使わなければいけないようなケースではすでにCSSに無理が来ている可能性が高いのでリファクタリングを考えた方がいいでしょう。

まとめ

要素にルールを適用するときセレクタに出現するid、クラス、要素数を用いて詳細度が比較され、一番高い詳細度のルールが適用されます。 CSSを書いていて、ルールが思うように適用されないときは、その要素に適用されているルールを調べ、それらより高い詳細度になるようにセレクタを調整しましょう。