。2016-4-20(Wed)改訂
css セレクタは、なかなか味なところがあるのだけれど、多少とっつきにくい面がある。私も随分誤解していたところがあったので、ここらでひとつまとめのメモを作成してみた。
[参考]css セレクタの仕様は、W3C が出している "Selectors Level 3 (W3C Recommendation 29 September 2011)"(和訳 「セレクタ Level 3」)。
html は、p とか h1 とかいうタイプの要素を使い、この p とか h1 とかはしばしば要素名と呼ばれる。
p
はタイプが p である要素(要素名が p である要素)を選択するセレクタである。
*
は、任意のタイプの要素にマッチする。
css セレクタでは、要素が持つ属性を使って要素を選択することができる。
p[country]
は、country 属性が設定されている p 要素を選択する。属性値は問題にならない。
p[country="ruritania"]
は、coutry 属性が ruritania である p 要素を選択する。
= の代わりに ~= を使って
p[keyword~="dog"]
のようにすると、次のいずれの p 要素も選択される。
<p keyword="dog">They love dogs.</p> <p keyword="dog cat">They love dogs and cats.l</p>
このとき、属性値はスペースで区切られた単語リストでなくてはならない。だから、次の p 要素はこのセレクタによって選択されない。
<p keyword="sadogashima">They love Sadoga-shima.</p>
また、^=, $=, *= はそれぞれ前方一致、後方一致、任意の場所の一致を表す。したがって、
(参考 Selector Level 3 6.3.1. Attribute presence and value selectors)
p[country="ruritania"][age="20"]
のようにすると、country 属性の値が ruritania で、かつ、age 属性の値が 20 である p 要素が選択される。
たとえば、
<p class="japan">日本</p>
という html の要素は、属性名が class で、その属性値が japan である。属性名が class のとき、css セレクタは、簡単な記法を使うことができる。
まず、
p.[class~="aichi"]
のように書くべきところを、次のように書くことができる。
p.aichi
このセレクタは、
<p class="aichi">愛知県</p> <p class="gifu aichi mie">東海三県</p>
のいずれの p も選択する。
また、
p.aichi.jiyugaoka
は、
p[class~="aichi"][class~="jiyugaoka"]
と同等で、
<p class="japan aichi jiyugaoka">日本 愛知県 自由ヶ丘</p> <p class="jiyugaoka aichi japan">自由ヶ丘 愛知県 日本</p>
のいずれの p も選択するが、
<p class="japan tokyo jiyugaoka">日本 東京都 自由ヶ丘</p> <p class="jiyugaoka">自由ヶ丘</p>
のいずれの p も選択しない。
(参考 Selector Level 3 6.2. Universal selector)
p#monkey
のようにすると id 属性を持っていてその値が monkey である p 要素だけが選択される。
*#monkey
#monkey
は、いずれも id が monkey である任意の要素にマッチする。
(参考 Selector Level 3 6.5. ID selectors)
A B
は要素 A の子孫(子、孫、曾孫、玄孫……のこと)に当たる B を選択し、
A > B
は 要素 A の子(孫以下を含まない)に当たる B を選択する。
A B や A > B が選択するのは、あくまで要素 B そのものである。ただ、css スタイルシートでこうしたセレクタを使って要素を特定し、その要素に属性をセットした場合、セットされた属性が子孫の要素に継承され、影響が B の子孫に出ることが珍しくない。
次のような table があったとする。
<table> <tbody> <tr> <td>あいうえお</td> </tr> </tbody> </table>
td { color: red; }
td の color 属性が red にセットされるので、「あいうえお」が赤字になる。
table { color: red; }
table にセットされた color 属性が td まで継承されていき、「あいうえお」が赤字になる。セレクタが選択している要素は、あくまで table 要素である。
table td { color: red; }
「table の子孫要素に当たる td」の color 属性が red にセットされ、「あいうえお」は赤字になる。
table > td { color: red; }
table の子に td があるかどうかを探し、その color 属性を red にしようとする。残念ながら table 直下に td は見つからず、セレクタは何も選択しない。もちろん、「あいうえお」は赤くならない。
table > tbody { color: red; }
table 要素直下に tbody が見つかり、tbody の color 属性に red がセットされる。これが、td まで継承され、「あいうえお」は赤字になる。
table > tbody > tr {color: red;}
table 直下の tbody の直下にある tr の color 属性が red にセットされ、これが td に継承されるので、「あいうおえ」は赤字になる。
table tr > td {color: red;}
table の子孫の tr が発見され、その tr 直下の td の color 属性が red にセットされるので、「あいうおえ」は赤字になる。
A+B は A のすぐ下の弟が B であるならばそれを選択する。A~B は A 以後にある弟たちから B であるものを選択する。
次のような html があったとする。
<p>zero</p> <h1>Numbers</h1> <p>one</p> <p>two</p> <h2>Big Numbers</h2> <p>three</p>
h1+p {color: red;}
「Numbers」の直後にある弟が選択される。つまり、「two」が赤字になる。文書の意味としては h1 は p より上位かもしれないが、html のツリー上では同じ親を持つ兄弟に過ぎない。
h1+p+p {color: red;}
「Numbers」の次の次の弟が選択され、「Big Numbers」が赤字になる。
h1+p+p+p {color: red;}
「Numbers」の次の次の次の弟は p ではないので何も選択されず、どこも赤字にならない。
h1~p {color: red;}
「Numbers」より後にある弟のうち p 要素すべて選択され、「one」「two」「three」が赤字になる。「Bignumbers」は p 要素ではないから赤字にならない。
参考 https://www.w3.org/TR/css3-selectors/#child-combinators
A, B
のようにすると、要素 A および要素 B が選択される。あるいは、同じことだが「A または B」にマッチする要素が選択される。
しばしば見誤るのが、次のようなケースだ。
<style type="text/css"> i b,u {color: red;} </style> <p> <u>甲</u> <i> <b>乙</b> <u>丙</u> </i> </p>
では、「甲」「乙」「丙」いずれも赤字となる。「i b,u」というセレクタは、「i b」というセレクタと「u」というセレクタをグループ化したものだからである。つまり、カンマはスペースよりも結合順位が低いわけで、これは普通の英文を考えてみると自然なことである。この優先順位を変更する括弧のようなものは用意されていない。
(参考 Selectors Level 3 5. Groups of selectors)
css セレクタにとって、div 要素はべつに特別な要素ではない。
「.クラス名」というセレクタは「*.クラス名」の略記であり、「div.クラス名」のことではない。
なお、W3C は div の使い方について、次のようにコメントしている。
Note: CSS は "class" 属性に対しかなりの力を与えているため、製作者は (HTML の DIV や SPAN など) 特定の表現をほとんど持たない要素に "class" 属性でスタイル情報を与えて自分の "文書言語" を設計できうる。しかし、製作者はこれを避けるべきである。これは、文書言語の構造化要素はその意図や意味を理解され、また受け入れられているが、製作者が定義した独自の class 定義はそうでないことにある。(セレクタ Level 3 6.4)
擬似クラスは、要素に条件をつけて絞り込む仕組みだと考えるとわかりやすい。絞り込むという作用は、要素にクラスを指定したときと似ているが、それ以外はべつだんクラスに似ているところはない。
具体例を挙げる。いま、ドキュメントの中に次のような 3 つの p 要素が含まれていたとする。
<p id="one">いち</p> <p id="two">に</p> <p id="three">さん</p>
まず初めに、
p[id="two"]:first-child { color:red; }
セレクタ頭にある p[id="two"] という部分が 2 つ目の p 要素を選ぶ。そして、これに後続する first-child という擬似クラスは、「兄弟たちの中の長兄であるか」をテストする。2 つ目の p 要素はこの条件を満さないので、このセレクタはどの要素も選び出さない。
これに対して、
p[id="one"]:first-child { color:red; }
では、tr[id="tr1"] が選んだ 1 つ目の p 要素は、first-child という条件を満たす。その結果、この要素がこのセレクタによって選ばれ、color 属性に red がセットされる。この結果「いち」が赤字になる。
p:first-child { color:red; }
この例では、セレクタ頭の p は、3 つの p 要素をすべて選択する。そして、その各 p 要素が、first-child という擬似クラスによってテストされた結果、長兄に位置する 1 つ目の p が選び出され、「いち」が赤字になる。
擬似クラス last-child は、末弟であるかどうかをテストするという点を除けば first-child と同じなので省略。
これは、単純に first-child を一般の「n 番目の兄弟」に拡張した擬似クラスではない。大変楽しい擬似クラスで、実用上も優れたものである。
擬似クラス
具体例で考えるために、ドキュメント中に次のような 3 つの p 要素があったとする。
<p>いち</p> <p>に</p> <p>さん</p> <p>し</p> <p>ご</p>
まず、例として
p:nth-child(2n+1) { color:red; }
とすると、どのような要素が赤字になるかを考えてみる。
まず、セレクタ頭にある p は、ドキュメント中にある 5 つの p 要素を選び出す。そのそれぞれが擬似クラス
ここで、擬似クラス
という値をとることになる。
これを受けて、擬似クラス
いち
に
さん
し
ご
これはとりも直さず奇数行ということであり、nth-child(2n+1) のことを nth-child(odd) と表記できるように決まっているのもこれゆえだ。
同様に、すべての偶数行を選択したいならば、
p:nth-child(2n+2) { color: red }
いち
に
さん
し
ご
次の例を考えてみよう。
p:nth-child(0n+3) { color: red }
n に対する 0n+3 は、
となる。したがって、このセレクタは 3 つ目の p 要素だけを選択する。
いち
に
さん
し
ご
なお、0n+3 の「0n+」の部は省略することが可能なので、たんに
p:nth-child(3) { color: red }
と書いても同じである。
さて、ここからが大変面白い話である。次のような例を考えてみよう。
p:nth-child(-n+3) { color: red }
n と -n+3 を対照する表を作ってみると、
となる。したがって、このセレクタは、5 つの p 要素のうち、3,2,1,0,-1,-2 個目のものだけ選択する。しかし実際は 0,-1,-2 個目の p 要素というものは存在しないので、3,2,1 個目の p 要素が選択される。ようするに、これによって「前から数えて 3 つの p 要素を選ぶ」ということが実現するのである。
いち
に
さん
し
ご
したがって、ドキュメント中に次のように 5 つの p 要素があったときに、
<p>いち</p> <p>に</p> <p>さん</p> <p>し</p> <p>ご</p>
p:nth-last-child(-n+3) { color: red }
のようなスタイルシートを書くと、下から 3 行が赤くなる。
いち
に
さん
し
ご
ところで、
p:nth-child(-n+3):nth-last-child(-n+3) { color: red }
これは、p 要素に対して、「nth-child(-n+3) かつ nth-last-child(-n+3) であるかどうか」がテストされる。その結果、「上から 3 行以内かつ下から 3 行以内」という条件を満たす 3 つ目の p 要素だけが選択される。
いち
に
さん
し
ご
ドキュメント中に次のように 5 つの p 要素があったときに、
<p>いち</p> <p>に</p> <p>さん</p> <p>し</p> <p>ご</p>
「上から 4 行目以外」という選択をするには、
p:not(:nth-child(4)) { color: red }
とすればよい。
いち
に
さん
し
ご
参考 Selectors Level 3 6.6. Pseudo-classes
近々書くます
おわり