CSSを書いていると、class名やid名がほんの少し違うだけの要素に、同じスタイルをまとめて当てたい場面がよく出てきます。box01、box02、box03…と一つずつセレクタを並べていくと、コードは無駄に長くなり、後から直すのも一苦労です。
そんなとき私が使っているのが、属性セレクタによる正規表現風のパターンマッチです。「〜で始まる」「〜で終わる」「〜を含む」といった条件でまとめて要素を選べるので、CSSがぐっとスマートになります。
この記事では、MDNの定義を確認しながら、実際に動くコードで使い方を整理していきます。
関連記事:CSSでフォントサイズを動的に調整!max-font-size、min-font-sizeの設定方法
CSSに正規表現は使える?答えは「属性セレクタ」
まず前提として、CSSのセレクタに正規表現そのものを書くことはできません。ただ、属性セレクタを使えば、正規表現に近い部分マッチが実現できます。MDNでは属性値のマッチング方法として、次のような種類が定義されています。
- [attr^="値"] … 値で始まる(前方一致)
- [attr$="値"] … 値で終わる(後方一致)
- [attr*="値"] … 値を含む(部分一致)
- [attr~="値"] … 空白区切りの単語のうち1つが完全一致
- [attr|="値"] … 値と完全一致、または値の直後にハイフンが続く
このうち正規表現の感覚に一番近いのは、前方一致・後方一致・部分一致の3つです。
前方一致・後方一致・部分一致の3つの基本
前方一致 [attr^="値"]
class名やid名が特定の文字列で始まる要素を選びます。
<div class="box01"></div>
<div class="box02"></div>
<div class="clear box03"></div>
[class^="box"] {
background: blue;
}
class名が"box"で始まる1行目と2行目が対象です。3行目はclass属性の値が"clear box03"で、先頭が"clear"になっているため対象外になります。属性値の先頭全体を見る点がポイントで、"^"が「〜で始まる」を表します。なお、divそのものを狙うときは div[class^="box"] のように空白を空けずに書きます(div [class^="box"] と空白を入れると子孫要素を指す別の意味になります)。
後方一致 [attr$="値"]
class名やid名が特定の文字列で終わる要素を選びます。
<div class="box01-blue"></div>
<div class="box02-green"></div>
<div class="box03-blue"></div>
[class$="blue"] {
background: blue;
}
class名が"blue"で終わる1行目と3行目が対象になり、"green"で終わる2行目は対象外です。正規表現と同じく、"$"が「〜で終わる」を示します。
部分一致 [attr*="値"]
class名やid名に特定の文字列が含まれている要素を選びます。
<div class="box01-hoge-blue"></div>
<div class="box02-green hoge"></div>
<div class="box03-blue-hoge"></div>
[class*="hoge"] {
background: blue;
}
3つとも値のどこかに"hoge"を含んでいるので、すべての要素にスタイルが適用されます。"*"は「値の中に1つ以上その文字列を含む」を意味します。
意外と便利な [attr~="値"] と [attr|="値"]
前方・後方・部分一致に加えて、MDNにはもう2つのマッチング方法が定義されています。挙動が微妙に違うので、部分一致との差を意識すると使い分けやすくなります。
[attr~="値"]:空白区切りの単語一致
属性値を空白で区切った単語リストのうち、1つが完全一致する要素を選びます。class属性を複数指定したときの挙動が分かりやすい例です。
<div class="btn primary"></div>
<div class="btn-primary"></div>
[class~="primary"] {
color: red;
}
1行目は"btn"と"primary"という2つの単語に分かれ、その中に"primary"がそのままあるのでマッチします。2行目は"btn-primary"で1つの単語なのでマッチしません。部分一致[*=]なら両方マッチしますが、[~=]はあくまで単語単位という違いがあります。
[attr|="値"]:ハイフン区切りの前方一致
属性値が値と完全一致するか、値の直後にハイフンが続く場合にマッチします。言語コードの指定でよく使われる書き方です。
<p lang="en">...</p>
<p lang="en-US">...</p>
<p lang="fr">...</p>
[lang|="en"] {
font-style: italic;
}
"en"と"en-US"がマッチし、"fr"は対象外です。前方一致[^=]と似ていますが、[|=]は「値そのもの」か「値+ハイフン」に限られる点が異なります。
大文字小文字を無視する i フラグ
閉じ角括弧の直前に i を付けると、値の比較で大文字・小文字を区別しなくなります(ASCIIの範囲)。ファイル拡張子やドメインなど、表記ゆれを吸収したいときに役立ちます。
a[href$=".pdf" i] {
/* .pdf も .PDF も .Pdf もマッチする */
font-weight: bold;
}
このひと文字を付けるだけで、リンク先の拡張子が大文字で書かれていても取りこぼさなくなります。
実用例:そのまま使える動くコード
ファイル拡張子でアイコンを出し分ける
リンク先の拡張子に応じて、リンクの前にアイコンを差し込む例です。後方一致とiフラグの組み合わせが効きます。
<a href="manual.pdf">マニュアル</a>
<a href="photo.JPG">写真</a>
a[href$=".pdf" i]::before { content: "\ud83d\udcc4 "; }
a[href$=".jpg" i]::before { content: "\ud83d\uddbc\ufe0f "; }
iフラグを付けているので、".JPG"のような大文字表記のリンクにもアイコンが付きます。
外部リンクを自動で判定する
httpで始まり、かつ自サイトのドメインを含まないリンクに、外部リンクの目印を付ける例です。
<a href="https://example.com">外部サイト</a>
<a href="https://www.webernote.net/page.html">内部ページ</a>
a[href^="http"]:not([href*="webernote.net"])::after {
content: " \u2197";
}
[href^="http"]で絶対URLのリンクを拾い、:not([href*="webernote.net"])で自サイトを除外しています。属性セレクタを組み合わせると、こうした条件分岐もCSSだけで書けてしまいます。
まとめ:正規表現風セレクタの押さえどころ
CSSに正規表現そのものは書けませんが、属性セレクタを使えば正規表現に近いパターンマッチができます。最後にポイントを整理します。
- [^=]前方一致・[$=]後方一致・[*=]部分一致が基本の3つ
- [~=]は空白区切りの単語単位、[|=]はハイフン区切りの前方一致で挙動が違う
- 値の末尾に i を付ければ大文字小文字を無視できる
- 拡張子アイコンや外部リンク判定など、実務でそのまま使える
ただし属性セレクタは要素数が多いページだと処理に時間がかかることもあります。使いすぎには気をつけつつ、必要な場面で上手に取り入れてみてください。