こんにちはウェブエンジニアの横部です。
普段はPHPやJavaなどの内部処理にかかわる部分を担当しております。
今回は開発で久々にCSSを触る機会があったので、知ってて当たり前かもしれないが、自分が知っているようでよく知らなかったCSSについて、実際のブラウザでの検証結果を踏まえて紹介したいと思います。
セレクタについて
CSSはセレクタを使って、スタイルが定義されます。
セレクタにはそれぞれ名称があります。
例えば、*(アスタリスク)は全称セレクタと呼ばれるもので、全ての要素を指します。
また要素名は要素型セレクタ(タイプセレクタ)と呼ばれ、各要素(p等)を指します。
classはclassセレクタ、IDはIDセレクタと呼ばれています。
他にも様々なセレクタが存在し、セレクタごとにスタイルが定義された結果、全体のデザインが決定していきます。
では、実際にどうスタイルが定義されて適用されていくのかを検証していきます。
同じセレクタ、異なる値
CSSでは同じセレクタで異なる値の場合、より後に読み込まれたほうが優先されるようになっています。
例えば以下のようなソースがあったとき、ブラウザ上では実際にどう出力されるのか検証してみました。
CSSはブラウザによって挙動が異なるという問題があるため、メジャーなブラウザであろうIE, Firefox, Chromeで検証しました。
sample1-1.css
1 |
p { color: red; } |
sample1-2.css
1 2 |
@import url('sample1-1.css'); p { color: yellow; } |
sample1-3.css
1 |
p { color: blue; } |
sample1.html
1 2 3 4 5 6 7 8 9 |
<html> <head> <link rel='stylesheet' href='sample1-2.css' type='text/css' media='all' /> <link rel='stylesheet' href='sample1-3.css' type='text/css' media='all' /> </head> <body> <p>■P■</p> </body> </html> |
結果、このような出力が得られました。
出力結果(上からIE11、FireFox36、Chrome40)
では何故このような結果になったのでしょうか?
それは、CSSは以下の流れで処理が行われて最後に定義されたスタイルが適用されるためです。
1. HTMLが読み込まれる
2. sample1-2.cssが読み込まれる
3. sample1-1.cssがインポートされる
4. p要素に赤色が適用される
5. p要素に黄色が適用される
6. sample1-3.cssが読み込まれる
7. p要素に青色が適用される
8. 結果が出力される
詳細度の異なるセレクタ、異なる値
今度は、詳細度の異なるセレクタで異なる値のケースを見ていきましょう。
先ほどの検証結果から、同じセレクタであれば最後に定義されたスタイルが適用されることがわかりました。
それを踏まえて以下のサンプルを実際にブラウザで出力させてみます。
sample2.css
1 2 3 4 5 |
#id { color: green; } p.class { color: yellow; } .class { color: orange; } p { color: red; } * { color: purple; } |
sample2.html
1 2 3 4 5 6 7 8 9 10 11 12 |
<html> <head> <link rel='stylesheet' href='sample2.css' type='text/css' media='all' /> </head> <body> <p id="id" class="class">■P with ID & class■</p> <p class="class">■P with class■</p> <div class="class">■DIV with class■</div> <p>■P■</p> ■*■ </body> </html> |
結果はこのようになりました。
出力結果(上からIE11、FireFox36、Chrome40)
一見、最後の*(アスタリスク)で定義されたスタイルが適用され、全て紫色になるように思えます。
しかし実際は、全ての色が異なる結果になりました。
これはセレクタの種類によって詳細度が異なるためです。
セレクタの詳細度
IDセレクタ > classセレクタ > 要素型セレクタ > 全称セレクタ
実際の内部処理としては、IDセレクタ、classセレクタ、要素型セレクタがいくつあるのか?を集計してそこから詳細度を算出しています。
例えば、IDセレクタが1つ、classセレクタが2つ、要素型セレクタが3つだった場合、
IDセレクタ数を百の位、classセレクタ数を十の位、要素型セレクタ数を一の位に当てはめます。
全称セレクタは無視されます。
すると123という結果になります。これが詳細度の値です。
この詳細度の値が大きければ大きいほど、優先順位は高くなるという仕組みです。
9. Calculating a selector's specificity
これを先ほどのセレクタに当てはめると、#id=100,p.class=11,.class=10,p=1,*=0となり、
結果として、#id > p.class > .class > p > *のような優先順位となります。
CSSコーディングについて
IDとclassは役割に応じた明快な名前をつけるのはもちろん、
それぞれ区別がつくようコーディング規約を設けるべきです。
例えば、IDには区切り文字にアンダースコア、classはキャメルケースを使う等。
1 |
<div id="page_top" class="editContent"> |
その理由としては、IDやclassはJavaScriptが要素を特定するために用いることがある為、
IDとclassの区別がつかない(!?)プログラマーによってJavaScriptでバグが発生したとしても原因究明が容易になります。
IDとclassの区別がつかない(!!)プログラマーによって、IDをclassとして定義されるということもなくなります。定義されていても、規約違反なので発見は容易になります。
また、アプリケーションよりのウェブ実装を行う場合は、
IDはJavaScriptが要素を特定するために用いるものという認識で、
セレクタには使わない(固有名でもclassとして定義する)という考え方もあります。
class名を工夫することで、オブジェクト指向言語における継承のようなことを実現することも可能です。
sample3.css
1 2 |
.account { color: blue; background-color: yellow; } .account-error { color: red; } |
sample3.html
1 2 3 4 5 6 7 8 9 |
<html> <head> <link rel='stylesheet' href='sample3.css' type='text/css' media='all' /> </head> <body> <div class="account">■login■</div> <div class="account account-error">■not login■</div> </body> </html> |
出力結果(上からIE11、FireFox36、Chrome40)
スタイルが定義されていない場合
さて、検証によって判明した仕様から、既に記述されたCSSを保守する際は、詳細度を理解してコーディングしないと、
「意図しない箇所のスタイルが変わっている・・・」
「期待した色に変わらない・・・」
という悲劇が待ち受けています。
その為、ここでは詳細度の概念を踏まえたうえで、スタイルが定義されていない場合、どう適用されていくのかを実際に検証していきます。
例えば以下のようなコードを実際にブラウザで出力してみます。
sample4.css
1 2 |
input[type="submit"].next-step { background-color: yellow; color: blue; } input[type="submit"][disabled].next-step { color: red; } |
sample4.html
1 2 3 4 5 6 7 8 9 10 11 |
<html> <head> <link rel='stylesheet' href='sample4.css' type='text/css' media='all' /> </head> <body> <div><input type="submit" value="■有 効■"></div> <div><input type="submit" value="■無 効■" disabled="disabled"></div> <div><input type="submit" class="next-step" value="■有 効■"></div> <div><input type="submit" class="next-step" value="■無 効■" disabled="disabled"></div> </body> </html> |
結果はどのようになるでしょうか?
スタイルが定義されてない場合、ブラウザで定義されているデフォルトのスタイルが適用されます。
disabled属性がないinput要素では背景と文字のスタイルが定義されていますが、
disabled属性があるinput要素では文字のスタイルしか定義されていません。
この場合、disabled属性があるinput要素の背景はどうなのでしょうか?
1.デフォルトのスタイルが適用される
2.詳細度の低いセレクタで定義されたスタイルが適用される
正解は、2です。
詳細度の低いセレクタで定義されたスタイルが適用されて、背景は黄色になります。
結果、以下のようになりました。
出力結果(上からIE11、FireFox36、Chrome40)
CSSではスタイルが定義されてない場合、
基本的にブラウザのデフォルト定義が適用されますが、
既に詳細度の低いセレクタでスタイルが定義されていた場合は、
そのスタイルが詳細度の高いセレクタにも適用されます。
なので、「意図しない箇所のスタイルが変わっている・・・」となった場合は、
詳細度の高いセレクタでスタイルが定義されていなかった為に、
詳細度の低いセレクタで定義したスタイルが適用されたことが原因と考えられます。
また、スタイルは、常に詳細度の高いセレクタで定義されたものが適用されます。
なので、「期待した色に変わらない・・・」となった場合は、
先ほどとは逆に詳細度の高いセレクタでスタイルが既に定義されていた為、適用できなかった可能性があります。
このようなバランス感覚をクライアントが理解してないと、正に以下の記事に記載されたとおりの体験をする羽目にもなります。
「クライアントよ、お前の依頼の大変さを思い知れ!これがデザイナーにとっての「デザイン修正」だ!」
最後に
以上が、自分が知ってるようでよく知らなかったCSSになります。
改めてCSSの事を調べて、デザイナーの大変さを思い知った感じです。
このブログをご覧になっている皆さんは、「CSSなんて十分知っているよ」という人がほとんどかもしれませんが、この記事を見ることで、「これは知らなかった」という事が見つかれば幸いです。
ここまで見ていただいてありがとうございました。