CSSセレクター総ざらい 第1回 基本セレクター

第1回目では、まずセレクター一般についての説明をします。次に5種類の基本セレクターについて解説します。普段の業務で使っているセレクターを今一度、基本仕様から押さえてみましょう。

発行

著者 坂巻 翔大郎 フロントエンド・エンジニア
CSSセレクター総ざらい シリーズの記事一覧

2018年当時と機能は変わりませんが、セレクター名が変わったものや、実装が進んだものもあります。把握しているものは記事中で修正、追記されていますが、最新仕様も併せてご確認ください。

セレクターとは

CSSセレクターというと、普段の業務で日常的に触れているものなので、そもそも「セレクターとは何か?」と考えたことはないかもしれません。

そこで、この記事ではまず「セレクターとは何か」について考えるところから始めてみましょう。

仕様書(*後述コラム)によると、セレクターはツリー構造における要素の特定のパターンを表すものとされています。

A selector represents a particular pattern of element(s) in a tree structure.

たとえば、セレクターがdiv spanであれば、HTMLの要素のツリー構造におけるdiv要素の子要素としてのspan要素を示すことになります。

HTMLで表すならば、次のコードのような要素のパターンが想定できます。

<div>
  <span></span> <!-- このspanを指す -->
</div>

<div>
  <div>
    <span></span> <!-- このspanも指す -->
  </div>
</div>

「HTMLで表すならば」という言葉を使ったのは、セレクターはHTML/CSSだけに使われるものではないからです。最初の定義にあるように、セレクターが持つツリー構造における要素の特定のパターンを表す機能は、JavaScriptなどでも、次のように使われます。

  • element.matches()関数は、要素が特定のセレクター文字列によって選択された場合にtrueを返す。それ以外の場合はfalseを返す。
  • document.querySelectorAll()関数や、セレクターを通して、ツリー構造中の要素の中から合致するものを絞り込む。
  • HamlEmmetなどのように、セレクターから、そのセレクターにマッチするマークアップを生成する。

セレクターで特定の要素のパターンを指定し、そのパターンに合致した箇所に任意の処理を行うという使われ方です。

*仕様書 Selectors Level 4

Selectors Level 4Selectors Level 3の上位になる新しいセレクターの仕様です。Level 4ではより便利なセレクターや仕組みが追加されています。

セレクターの仕様には「CSS」という名前が付いていません(Gridの仕様はCSS Grid Layout Moduleです)。これは前述したとおり、セレクターがCSSだけのものではないことからきています。

他の仕様でも、Media Queriesは「CSS」が付いていません。メディアクエリは、HTMLのmedia属性で利用されることもあるからです。CSSの名前は付いていませんが、CSSに限定されていないだけで、どちらもCSSでよく利用される機能です。

CSSにおけるセレクター

CSSにおけるセレクターは、CSSのルールセットを適用する要素を定義します。ここではおさらいとして「セレクター」や「ルールセット」がどの部分を指すかについて触れておきます。

CSSは、スタイルを適用する対象になるセレクターと、そのスタイルを設定する宣言ブロックからなります。宣言ブロックの中には、プロパティとプロパティ値を宣言していきます。この塊をルールセットと呼びます。

/* ルールセット */
セレクター { /* 宣言ブロック */
  width: 100px; /* 宣言(プロパティ:プロパティ値) */
  height: 50px; /* 宣言(プロパティ:プロパティ値) */
} /* 宣言ブロック */

セレクターで特定の要素のパターンを指定し、そのパターンに合致した箇所にスタイルが適用されます。

さらに、このセレクターには詳細度があります。このシリーズの最終回で解説する予定ですが、詳細度はCSSが適用される際の重みで、重いほうが優先されます。CSSを書いていて思うようにスタイルがあたらなかったことはないでしょうか。また、順番を変えたらスタイルがあたった、セレクターを長くしたらあたったといった経験はないでしょうか。セレクターに対する理解を深めれば、そういった「なんとなく」をなくすことができます。

まずは、基本セレクターから解説していきます。

基本セレクターと属性セレクター

基本セレクターは、大きく分けて4種類のセレクターに分けられます。

  1. 要素型セレクター
  2. クラスセレクター
  3. IDセレクター
  4. 全称セレクター

また属性セレクターと呼ばれ、属性値の条件に合わせて要素を指定できるセレクターがあります。

  • 属性セレクター

ぞれぞれについて解説していきます。

要素型セレクター

要素型セレクターは、HTMLの要素名をセレクターに指定します。

<div>div要素</div>
<p>p要素</p>
<div>div要素</div>
div { font-weight: bold; }

上記のHTMLとCSSでは、すべてのdiv要素にfont-weight: bold;があたります。

クラスセレクター

クラスセレクターは、class属性値を.(ドット)から始めて、セレクターに指定します。HTMLがclass="my-class"であれば、CSSでは.my-classとします。

<div class="my-class">my-classを持つ要素</div>
<div class="your-class">my-classを持たない要素</div>
<div class="my-class  our-class">my-classを持つ要素</div>
.my-class { font-weight: bold; }

上記のHTMLとCSSでは、class属性値にmy-classを持つ要素にfont-weight: bold;があたります。

IDセレクター

IDセレクターは、id属性値を#から始めて、セレクターに指定します。HTMLがid="my-id"であれば、CSSでは#my-idとします。

<div id="my-id">#my-id</div>
#my-id { font-weight: bold; }

上記のHTMLとCSSでは、id属性値にmy-idを持つ要素にfont-weight: bold;があたります。

【ワンポイント】HTML上に同じid属性値を持つ要素が複数ある場合

HTML上に同じid属性値を持つ要素が複数あるという状態は、いうまでもなくHTML文書としては妥当なものではありません。

ただ、もしid属性値が重複すると、その要素は無視されるわけではなく、CSSで指定したスタイルがid属性値が重複している要素すべてに適用されます。

JavaScriptのgetElementById()ではid属性値が重複している要素の中で、最初のものが取得できます。

全称セレクター

全称セレクターは、*をセレクターに指定します。

<section>
  <div class="my-div"></div>
  <span class="my-span"></span>
</section>
* { font-weight: bold; }

全称セレクターでは、すべての要素を対象とします。上記のHTMLの場合、sectiondivspan要素に対してfont-weight: bold;があたります。全称セレクターは詳細度に影響を与えません。

属性セレクター

属性セレクターは、[属性名][属性名=属性値]といったかたちで、要素の持つ属性や属性と属性値をセレクターに指定します。HTMLでtype="text"と指定していれば、CSSでは[type="text"]と指定します。

<input type="text" disabled>
[disabled] { /* ... */ }
[type="text"] { /* ... */ }

属性セレクターでは、ここまで解説したセレクターでは表現できない、より細かい条件で要素を指定することができます。

[attr]

<div attr></div>
[attr] { /* ... */ }

attr属性を持つ要素が対象になります。

[attr=value]

<div attr="value"></div>
[attr="value"] { /* ... */ }

attr属性を持ち、その属性値がvalueを持つ要素が対象になります。

【ワンポイント】属性セレクターの属性値をクォーテーションで囲む? 囲まない?

<div attr="value"></div>

attr属性値がvalueである要素を指定するセレクターは次のとおりです。

[attr=value] { /* ... */ }
[attr="value"] { /* ... */ }

属性値に空白が入らない場合は、ダブル(シングル)クォーテーションで囲っても囲まなくても問題ありません。ですが、次の例のように、属性値に空白を含めたい場合は、クォーテーションで囲む必要があります。

<div attr="The quick brown fox"></div>

このattr属性値にThe quick brown foxを含む要素を指定するセレクターをクォーテーションなしで記述してしまうと無効になります。

[attr=The quick brown fox] { /* ... */ }

空白を含む属性値を指定したい場合は、クォーテーションで囲みます。

[attr="The quick brown fox"] { /* ... */ }

筆者は普段から、空白の有無にかかわらず、属性セレクターを使う場合は、属性値をダブルクォーテーションで囲っています。

[attr~=value]

<div attr="value foo bar"></div>
<div attr="foo bar value"></div>
<div attr="foo value bar"></div>
[attr~="value"] { /* ... */ }

attr属性値が空白区切りのリストでその中の一つがvalueに一致する要素が対象になります。

[attr|=value]

<div attr="foo bar value"></div>
<div attr="foo bar value-piyo"></div>
[attr|="value"] { /* ... */ }

attr属性値が、valueと一致するか、valueで始まり直後にハイフンが続く要素が対象になります。これは言語のサブコードを対象としたい場合使われることがあります。

たとえば、lang属性を使い、中国語の場合はスタイルを変えたいという場合に利用します。中国語と言っても簡体字や繁体字などがあり、それぞれ言語コードが異なります。簡体字であればzh-CNであり、繁体字であればzh-TWとなります。

<div lang="zh">中国語</div>
<div lang="zh-CN">中国語(簡体字)</div>
<div lang="zh-TW">中国語(繁体字)</div>

2種類の中国語に対してスタイルをまとめてあてたい場合は、次のようなコードを書くこともできます。

[lang="zh"],
[lang="zh-CN"],
[lang="zh-TW"] { /* ... */ }

しかし、中国語の言語コードはzh-から始まり、その中の細かい区分をサブコード(CNTW)で区別しているので、まとめて中国語に対しての指定をする場合は、次のように書きます。

[lang|="zh"] { /* ... */ }

このセレクターが意味するのは「lang属性値にzhに一致するか、zhで始まり直後にハイフンが続く要素」となります。

【ワンポイント】[attr|=value]のさまざまな使い方

次のようにBEM風のクラスに対して、スタイルをあてることができます。

<div class="block">0</div>
<div class="block--extend1">1</div>
<div class="block--extend2">2</div>
[class|="block"] { padding: 10px; background-color: tomato; }
.block--extend1 { background-color: limegreen; }
.block--extend2 { background-color: gold; }

あくまで、こういった利用ができるといった例ですので、推奨するわけではありません。

言語コード以外にも、ある属性値が、特定の文字列から始まったり、特定の文字列から始まりハイフンが続くようなものであったときに、このセレクターを活用できるかもしれません。

[attr^=value]

<div attr="value"></div>
<div attr="value foo bar"></div>
<div attr="valueFooBar"></div>
[attr^="value"] { /* ... */ }

attr属性値がvalueから始まる要素を指定します。

[attr$=value]

<div attr="value"></div>
<div attr="foo bar value"></div>
<div attr="my-value"></div>
[attr$="value"] { /* ... */ }

attr属性値がvalueで終わる要素を指定します。

[attr*=value]

<div attr="value"></div>
<div attr="foo bar value"></div>
<div attr="my-value"></div>
[attr*="value"] { /* ... */ }

attr属性値にvalueを1つ以上含む要素を指定します。

属性値の大文字と小文字を区別したくない場合

属性セレクターの閉じ括弧の前にiまたはIを追加すると、属性値の大文字と小文字を区別しないようになります。

たとえば、次のようなHTMLを想定して、href属性値の.jpgである要素にマッチするセレクターを書きます。

<a href="foo.jpg"></a>

href属性値に.jpgを持つ要素を示すセレクターは、次のとおりです。

[href*=".jpg"] { /* ... */ } /* この場合 href="http://hoge.jpg.com" にもマッチしてしまいますが一応... */
[href$=".jpg"] { /* ... */ }

これのHTMLの属性値がもし、jpgではなくJPGになった場合、上記のCSSは適用されません。そこで、大文字と小文字を区別しないようにするiを使用します。

<a href="foo.jpg"></a>
<a href="foo.JPG"></a>
[href*=".jpg" i] { /* ... */ }
[href$=".jpg" i] { /* ... */ }

このiは、Selectors Level 4で追加された仕様です。最新のChromeやFirefox、Safariでは使用することができますが、IE 11とEdge 17では使用することができないので注意が必要です。

セレクターに使える文字、使えない文字

4.1.3 文字と活字ケース - Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification 日本語訳には、セレクターに使用できる文字の規則が書かれています。

使える文字

仕様書の重要な部分をまとめると、次のようになります。

  1. 文字[a-zA-Z0-9]およびISO 10646U+0080以上の文字、さらにハイフン(-)およびアンダースコア(_)のみを含むことができる。
  2. 数字([0-9])、2つのハイフン(--)、ハイフンの直後の数字(-[0-9])で開始できない。
  3. バックスラッシュ(\)で文字をエスケープできる。
  4. 日本語や絵文字といったものは、\XXXX形式のUnicodeエスケープをすることで利用できる。

まず、セレクターに使える文字に関しては、半角英数、記号は半角ハイフン(-)と半角アンダースコア(_)が利用できます。さらに、あまり知られていないかもしれませんが、日本語であったり絵文字といったマルチバイト文字を利用できます。

<div class="日本語">日本語です</div>
<div class="🍣">寿司です</div>
/* マルチバイト文字:日本語 */
.日本語 { /* 問題のないセレクター */ }
/* マルチバイト文字:絵文字 */
.🍣 { /* 問題のないセレクター */ }

日本語や絵文字を使ったセレクターを記述することはないかもしれませんが、セレクターとしては仕様に沿っているので有効です。

使えない文字

次に、セレクターに使えない、不正になるセレクターです。

.123 { /* 不正なセレクター */ }
.-100 { /* 不正なセレクター */ }
.--invalid { /* 不正なセレクター? */ }

数字で始まる、ハイフンの後に数字で始まる、2つのハイフンから始まるものは、セレクターとして不正になります。ただし、2つのハイフンから始まるセレクターに関してはSelectors Level 4では、問題のない有効なセレクターとなっています。2つのハイフンから始まるセレクターは、筆者が調べたところ、IE11では無効なセレクターになっていました。ChromeやFirefox、Edgeなどの最新バージョンでは使うことができました。

もしIE11で、2つのハイフンから始まるセレクターを使用したい場合は、ハイフンとハイフンの間にバックスラッシュ(\)によるエスケープを使用します。

.--invalid { /* IE11では無効なセレクター */ }
.-\-invalid { /* IE11でも有効なセレクター */ }

-_以外の半角記号は、セレクターには使用できませんが、エスケープをすれば、セレクターとして使用できます。

.(selector) { /* 不正なセレクター */ }
.\(selector\) { /* 有効なセレクター */ }

またバックスラッシュ以外のエスケープ方法では、\XXXX形式のUnicodeエスケープをすることができます。

/* ハイフンから始まり、数字が続く場合 */
.-100 { /* 不正なセレクター */ }
.\002D \0031 \0030 \0030 { /* `\XXXX`形式のUnicodeエスケープにより有効なセレクター */ }

/* マルチバイトと半角記号を含む場合 */
.\(^o^)/ { /* 不正なセレクター */ }
.\\(\^\o\^\) { /* バックスラッシュによるエスケープにより有効なセレクター */ }
.\FF3C \0028 \005E \006F \005E \0029 \FF0F { /* `\XXXX`形式のUnicodeエスケープにより有効なセレクター */ }

セレクターで使用できない文字を使用する方法としては、属性セレクターを使うという手もあります。

[class*="\(^o^)/"] { /* 有効なセレクター */ }

属性セレクターを使う方法はとても簡単です。ですが、書き方によっては意図しない要素にマッチすることもあるため、属性セレクターを使う場合は注意が必要です。

まとめ

今回は4種類の基本セレクターと属性セレクターについて解説しました。特に属性セレクターに関しては、属性と属性値を条件に指定して柔軟な要素選択ができました。

次回は結合子について解説します。