HOME

css セレクタにかんするメモ

。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

ID による指定

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

html の div 要素

css セレクタにとって、div 要素はべつに特別な要素ではない。

「.クラス名」というセレクタは「*.クラス名」の略記であり、「div.クラス名」のことではない。

なお、W3C は div の使い方について、次のようにコメントしている。

Note: CSS は "class" 属性に対しかなりの力を与えているため、製作者は (HTML の DIV や SPAN など) 特定の表現をほとんど持たない要素に "class" 属性でスタイル情報を与えて自分の "文書言語" を設計できうる。しかし、製作者はこれを避けるべきである。これは、文書言語の構造化要素はその意図や意味を理解され、また受け入れられているが、製作者が定義した独自の class 定義はそうでないことにある。セレクタ Level 3 6.4

擬似クラス

擬似クラスは、要素に条件をつけて絞り込む仕組みだと考えるとわかりやすい。絞り込むという作用は、要素にクラスを指定したときと似ているが、それ以外はべつだんクラスに似ているところはない。

:first-child

具体例を挙げる。いま、ドキュメントの中に次のような 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

擬似クラス last-child は、末弟であるかどうかをテストするという点を除けば first-child と同じなので省略。

:nth-child( )

これは、単純に first-child を一般の「n 番目の兄弟」に拡張した擬似クラスではない。大変楽しい擬似クラスで、実用上も優れたものである。

擬似クラス nth-child( ) の ( ) の中は、an+b という形をしているのが基本である。たとえば、nth-child(2n+1) のような感じだ。ようするに an+b というときの n は文字通り "n" という文字を書くわけで、これに対して a と b には、整数を書くのである。

具体例で考えるために、ドキュメント中に次のような 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(2n+1)( ) 中のn には 0 以上の整数(つまり 0,1,2,3,...)が次々と(そして延々と)代入されると考える。その結果、2n+1 は、それぞれの n に対して、

という値をとることになる。

これを受けて、擬似クラス nth-child(2n+1) は、5 つの p 要素が「1,3,5,7... 番目の兄弟という立場にあるかどうか」をテストする。我々の例にかんして言うなら p 要素は 5 つ目までしか存在しないので、このセレクタによって選択されるのは 1, 3, 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 要素を選ぶ」ということが実現するのである。

いち

さん

:nth-last-child( )

nth-child( ) は、( ) 内が与える数列を、上から何番目の兄であるかを表すのに使った。nth-last-child( ) では、( ) 内が与える数列が、下から何番目の弟であるかを表すのに使われる。

したがって、ドキュメント中に次のように 5 つの p 要素があったときに、

<p>いち</p>
<p>に</p>
<p>さん</p>
<p>し</p>
<p>ご</p>
p:nth-last-child(-n+3) { color: red }

のようなスタイルシートを書くと、下から 3 行が赤くなる。

いち

さん

ところで、nth-child( )nth-last-child( ) を同時に使ったら、どうなるだろうか。

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 要素だけが選択される。

いち

さん

:not( )

ドキュメント中に次のように 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

擬似要素

近々書くます

おわり