2.3 セレクタ

XHTMLで記述した機能や意味のブロックをスタイルシートに結びつけ、それらを具体的な表現として利用者に提供する媒介となるのがセレクタです。セレクタをうまく用いると、機能、意味と表現の関係が明瞭になり、スケーラビリティやメンテナンス性も向上します。

セレクタにはいくつかの種類があり、それぞれ対象要素を決めるためのマッチングパターンが定められています。

書籍原稿からXHTMLを生成して公開しています。実装状況に関する注は、2005年末〜2006年初にかけて調べたもので、ブラウザのバージョンアップなどにより変化することがあります。

2.3.1 名前をセレクタとして用いる

XHTML文書では、要素型名やクラス、ID属性値によって要素に名前を与え、その役割を示します。これらの名前は、スタイル規則を記述するセレクタとして用いられ、それぞれの機能、役割に対応する表現を与えます。

2.3.1.1 要素型セレクタ

最も基本的なセレクタは、XHTMLの要素型名に対応する要素型セレクタ(type selector)です。要素型名をそのままセレクタとして記述します。

要素型名の代わりにアスタリスク(*)を記述すると、文書ツリーのすべての要素にマッチする特殊なセレクタ(ユニバーサルセレクタ)として機能します。また、複数の要素型に同じ規則を適用させる場合は、要素型名をカンマ(,)で区切って列挙することでグループ化できます(グループ化機能は、要素型セレクタに限らず全てのセレクタのパターンで利用できます)。

[例2.14]

h1 {font-size: 175%}
h1, h2, h3, h4 {font-family: sans-serif} /* グループ化 */
* {color: black}                         /* ユニバーサルセレクタ */

2.3.1.2 クラスセレクタ

class属性によって与えたクラス名は、クラスセレクタを使ってスタイル宣言と結びつけることができます。クラスセレクタは、ピリオド(.)によって表現され、要素型セレクタ(E)にピリオドでクラス名(c)を連結して示します。

E.c という組合せは、E要素の中で cクラスを持つものだけにスタイルを適用するセレクタで、E要素のサブクラスを表現することになります。

要素型名をユニバーサルセレクタ(*)にすると、要素型を問わずcクラスをもつ要素に対してスタイルを適用します。要素型名がユニバーサルセレクタである場合は、*を省略して、ピリオドから書き始めるクラスセレクタとすることができます。

[例2.15]

/* class="note"を持つp要素にマッチ */
p.note {color: green}

/* class="note"を持つ全ての要素にマッチ */
*.note {font-size: 90%}
.note  {font-family: fantasy}

XHTMLでは、class属性に複数のクラス名を空白で区切って記述することができます。複数のクラス名を併せ持つ要素にスタイル規則を適用したい場合は、セレクタにクラス名をピリオドで区切って列挙します(*23)

[例2.16]

p.foo.baz {text-decoration: underline}

このスタイル規則は、次のような段落を下線付きで表現します。

[例2.17]

<p class="foo bar baz">ある段落…</p>

この場合、セレクタで指定するクラス名の順序は関係しません。

*23
クラス属性値とクラスセレクタが完全に一致する必要はなく、クラスセレクタで列挙したクラス名が全て含まれていればマッチします(IE6では、最後のクラスが含まれていれば、それ以前のクラスに関係なくマッチしてしまいます)。単一のクラス名によるセレクタは、空白区切りの複数のクラス名を持つ要素に対しても、そのクラスが含まれていればマッチします。

2.3.1.3 IDセレクタ

id属性で与えた名前は、IDセレクタによってスタイル宣言と結びつけることができます。IDセレクタはハッシュ(#)によって表現します(*24)

クラスセレクタと同様、要素型セレクタ、ユニバーサルセレクタとセットで記述することも、これらを省略して#で書き始めることもできますが、IDによる名前は文書中でユニークなので、どの記述方法をとっても適用される対象要素に違いはありません(*25)

[例2.18]

/* いずれも同じ要素にマッチする */
div#header {color: navy}
*#header   {font-size: 1em}
#header    {text-align: right}
*24
「id属性値が"foo"であるdiv要素」をdiv#fooと表記するのは便利で分かりやすいので、本書ではセレクタの説明以外でも、特定要素を示す簡略記法として本文中で用いることがあります。同様にクラスセレクタを使った「div.bar」も、「class属性値が"bar"であるdiv要素」の意味で本文中に登場することがあります。
*25
もちろん、ここでid="header"がpなど異なる型の要素に与えられているとすれば、div#headerはマッチしません。IDセレクタに要素型名を加えると、後述のカスケーディングの優先順位を高めたり、共通スタイルシートの規則を文書によって適用状況を変えたりすることができます。

2.3.2 名前を組み合わせる

CSSでは、ツリー上の位置関係を利用してスタイルの適用対象を指定することができます。CSS1で文脈セレクタ(contextual selector)と呼ばれていたように、文書のコンテクストを表現のコントロールに利用することができるため、階層的な構造を持つ機能ブロックをスタイルにマップするのに適しています。

文脈セレクタは、複数のセレクタを結合子(combinator)で組み合わせて記述します。最後に記されたセレクタが対象要素を、それ以前のセレクタがコンテクストを表します。

(図)

文脈セレクタの例で用いる簡易要素ツリー。兄弟レベルは、左にあるものが文書中で先に出現する。左上のol要素に重なっている点線の「toc」はこの要素のクラス属性を示す

以下のセレクタは、上図の要素ツリーを持つXHTML文書に対して適用した場合の例を用いつつ説明します。

2.3.2.1 子孫セレクタ

要素の親子(およびその子孫)関係に基づいて対象要素を決めるのが子孫セレクタ(descendant selector)です。これは任意のセレクタを空白文字で結合して "A B" の形で列挙したもので、要素Bが要素Aの子孫要素である場合に、要素Bに対して宣言ブロックのスタイルが適用されます。

[例2.19]

address em {color: green}

address要素内に記述されたem要素の文字色を緑にします。この場合、emはaddressの孫であっても対象となります。

(図)

[例2.20]

ol * dfn {font-weight: bold}

ol要素内のdfn要素で、直接の子要素ではなく間に何か他の要素がひとつ以上はさまれているものに対して、文字を太字にします。

(図)

[例2.21]

ol.toc li {border: 1px gray solid}

'toc'というクラス名を持つol要素の子孫であるli要素に対して、枠を表示します。

(図)

2.3.2.2 子要素、隣接セレクタ

要素Bが要素Aの直接の子要素であるときに限って適用するセレクタを子要素セレクタ(child selector)と呼び、 > を結合子として "A > B" の形で記述します。子孫セレクタよりも限定の度合いが高くなります。

[例2.22]

ol.toc > li {font-size: 1.2em}

'toc'というクラス名を持つol要素の直接の子要素であるli要素(章レベルの目次項目)のみをフォントサイズを大きくして表示します(入れ子になった節、項レベルの目次項目には適用されません)。

(図)

隣接セレクタ(adjacent sibling selector)は、2つの要素AとBが、文書ツリー上で同じ親を持ち、かつこの順序で連続している場合に、+を結合子として "A + B" という形で記述し、Bにスタイルを適用するセレクタです。

[例2.23]

h1 + p {margin-top: 1.5em}

この規則は、大見出し(h1)の直後にくる段落(p)の前に広めのマージンをとります。

(図)

2.3.3 属性セレクタ

class属性、id属性だけでなく、要素がもつ属性一般を基準にしてスタイルを適用することができます。この属性セレクタ(attribute selector)は、[ ]内に属性のマッチングパターンを記述して示します。パターンには次の4つがあります(*26)

セレクタマッチ対象
[attr]要素が属性attrをもっている場合にマッチ(属性値は関係しない)
[attr=value]要素の属性attrの値がvalueに等しい場合にマッチ
[attr~=value]要素の属性attrの値が空白で区切られたリストになっており、そのうちの一つがvalueに等しい場合にマッチ
[attr|=value]要素の属性attrの値がハイフンでつながれた複数の語からなっており、その最初がvalueに等しい場合にマッチ

なんらかのtitle属性をもつabbr要素をそれと分かるように明示するには、次のような規則が考えられます。

[例2.24]

abbr[title] {background: #ffdcdc}

lang属性が英語と指定されている段落は欧文フォントで表示したいと考えたとき、言語コードはenだったりen-USだったりとバリエーションがあります。このようなケースでは、|= を用いたセレクタが効果を発揮します。

[例2.25]

p[lang|="en"] {font-family: "Times", serif}

複数の属性を条件としてマッチするセレクタは、[ ]のパターンを列挙することで記述できます。たとえばrel属性値に"friend"を含み、hreflangが英語であるリンクをハイライトするには次のような規則が使えるでしょう。

[例2.26]

a[rel~="friend"][hreflang|="en"] {background: #dcfbc9}

次の例は、クラスセレクタ、IDセレクタと同じ要素にマッチする働きをします(*27)

[例2.27]

[class~=foo] {color: red} /* .foo と同じ要素にマッチ */
[id=bar] {color: green}   /* #bar と同じ要素にマッチ */

ただし、属性セレクタでの記述は、クラスセレクタ、IDセレクタと比べて、後述の優先度の計算には違いが生じます。

*26
CSS3では、これらに加えて属性値がvalueではじまることを表す[attr^=value]、valueで終わることを示す[attr$=value]、属性値の一部にvalueが含まれることを示す[attr*=value]という部分文字列属性セレクタも加わり、より強力なマッチが可能になります。
*27
CSS2仕様書の例では、(どの程度意識的か分かりませんが)属性セレクタの属性名がclassの場合は引用符なしになっています。Appendix Gの構文規則によると、属性セレクタのvalは[IDENT | STRING]であることから、class、idの場合は識別子として引用符なし、それ以外は文字列として引用符付きにするという規則と捉えることもできます。もっとも、他の場所の例をみると、それほど厳密な使い分けをしているようには思われず、ブラウザも引用符の有り無しは区別していないようなので、あまり気にする必要はないかも知れません。

2.3.4 疑似クラスと疑似要素

ときには文書ツリー以外の条件によって要素にスタイルを設定したり、要素として直接マーク付けしない部分を対象にしたいことがあります。これらを扱うセレクタが疑似クラスセレクタ、疑似要素セレクタです(*28)

2.3.4.1 疑似クラスセレクタ

疑似クラス(pseudo-class)は、名前や属性、内容といった文書ツリーに現れるものを用いず、それ以外の特徴によって対象要素を特定する仕組みです。

ハイパーリンクのアンカーは、通常リンク先が未訪問か訪問済みかによって異なるスタイルが与えられます。この条件は文書ツリーでは表現できないので、擬似クラス :link:visited をセレクタとしてスタイルを宣言します。

[例2.28]

a:link {color: blue}
a:visited {color: purple}

さらにリンクアンカーは、キーボードによる選択、マウスの通過などによってダイナミックにスタイルを変化させることがあります。マウスなどが要素の上に差し掛かった状態を :hover、マウスボタンの押下などによってアクティブになった状態を :active、タブキーなどによってアンカーが選択された状態を :focus によって表します(*29)。これらは排他的ではないので、複数の状態が同時に生じることもあります。

[例2.29]

a:focus  {border: dotted 1px gray}
a:hover  {background: silver}
a:active {color: red}

言語情報はHTMLではlang属性で表しますが、XML一般にはxml:lang属性で表します。これらを属性セレクタで個別に扱う代わりに、擬似クラス :lang を用いて汎用的に要素内容の言語に応じたスタイルを設定できます。セレクタは :lang(C) という形で、Cには言語コードを記述します(言語コードは属性セレクタの |= と同じくハイフンの前にマッチします)。

[例2.30]

:lang(ja) p {line-height: 1.5}

ある要素が別の要素の最初の子要素である場合にスタイルを適用する :fisrt-child 擬似クラスが用意されています。次の例は、イントロセクションの最初の子要素が段落(p要素)であれば、イタリック体で表示するというスタイル規則です。

[例2.31]

div.intro > p:first-child {font-style: italic}

これは、div.introの中で“最初に登場する段落”を意味するのではないことに注意してください。例えばdiv.introの中にh2、pの順で子要素が記述されているとき、このp要素は上記のセレクタにマッチしません。

div.intro > *:first-child とすれば、要素型を問わずdiv.introの最初の子要素にマッチします。div.intro *:first-child とすると、div.introの孫要素以降も対象にして、何らかの要素の最初の子要素であるもの全てにマッチしてしまいます。

*28
リンクおよび:hover、:active擬似クラスと:first-letter、:first-line疑似要素は主要なブラウザで実装されていますが、それ以外はサポートされない場合があるので、使い方には注意が必要です。
*29
ダイナミックセレクタ(:focus、:active、:hover)はリンクアンカー以外の要素にも適用できるもので、実際Firefox、Opera8などでは実装されています。IE6はリンクアンカーでしか機能しませんが、IE7ではリンク以外もサポートされる見込みです。

2.3.4.2 疑似要素セレクタ

疑似要素(pseudo-element)は、文書のマーク付け言語では直接記述されないものを、文書ツリー上の抽象概念として表すために用います。

タイポグラフィでよく使われる、最初の1文字を大きく(initial cap、drop cap)したり、最初の1行を大文字にするなどの効果は、通常は直接マーク付けされていない部分を対象にします。そこで、これらを :first-letter:first-line 擬似要素として、あたかもこれらの部分がツリーに存在するかのように扱います(*30)

[例2.32]

p.intro:first-letter {font-size: 250%; float: left}
p.intro:first-line {text-transform: uppercase}

元の文書に存在しない内容を生成して、ある要素内容の前、もしくは後ろに付加するには、:before:after 擬似要素セレクタとcontentプロパティを合わせて使います。次の例は、印刷メディアの場合はリンクアンカーの後ろにURLも表示するというスタイル規則です。

[例2.33]

@media print {
	a[href]:after {content: '<' attr(href) '>' }
}

複数のセレクタを結合子で組み合わせる場合、疑似要素セレクタはその最後に1回のみ使うことができ、具体的な対象要素を特定できるセレクタ(例えばp.intro)とセットでなければなりません。

*30
CSS3では、疑似クラスセレクタと区別するため、疑似要素セレクタは2つのコロンを前に置いて ::first-letter のように記述します。ただし後方互換性のために、CSS2の疑似要素セレクタ(:first-letter、:first-line、:before、:afterの4つ)は、そのまま利用できる(ブラウザが処理する)とされています。

2.3.5 機能ブロックとセレクタ

一般にスタイルの設計は、広域的なスタイルから小さなブロックのスタイルへ、集合的な要素型から個別の要素へという具合に、広く汎用的なところから始めて順次対象を絞り込みながら細かな規則を加えていくと、効率的でメンテナンスしやすいものとなります。これをセレクタの使い方に当てはめると、

といったステップが考えられます。

第1章でも述べたように、XHTMLでの機能の記述は、すべての機能要素にIDで名前を与えたりせず、できるだけコンテクストによる機能指示を用いるべきです。スタイルの設計に際しても、IDセレクタやクラスセレクタばかりに依存するのではなく、大きな機能ブロックの中での役割を子孫セレクタによって記述することが大切です。

IDだけに頼った機能表現では、それぞれの機能ブロック間の関連を示すことができません。子孫セレクタを活用した記述は、機能を構造化して互いの関係を明示することであり、文書構造の見通しを良くすることにもつながります。