配置に役立つ擬似クラス

作成者:カランカラン
💡

質問やフィードバックがありましたら、フォームからお願いします

本文は台湾華語で、ChatGPT で翻訳している記事なので、不確かな部分や間違いがあるかもしれません。ご了承ください

近年、CSSには多くの擬似クラスが追加され、もはや過去のように実装が限られたブラウザだけではなくなりました。今日は、いくつかのCSS擬似クラスを紹介し、実際のケースを通じてレイアウトの助けとなることを目指します。

  • :is
  • :where
  • :has
  • :lang
  • :focus-within
  • :first-child:last-child

:is

以前は、同じCSSルールを複数のセレクタに適用する際、以下のように書いていました:

.a-class,
.b-class {
  font-size: 25px;
}

この書き方には問題はありませんが、:isを使用することで、宣言を簡素化できます:

:is(.a-class, .b-class) {
  font-size: 25px;
}

適用するセレクタが多い場合、:isを使うことで、より読みやすくなります。まだWorking Draftの段階ですが、Can I useのデータによれば、98.1%のユーザーが利用可能です。

単一のクラスだけでなく、他のセレクタと組み合わせて使用することもできます:

:is(.a-class, .b-class) a:hover {
  opacity: 0.8;
}

:where

:whereの機能は:isと同じですが、優先度に違いがあります。:whereを使用すると、重みがなく、優先度は*と同じです。しかし、:isは、リスト内で最も優先度の高い重みを最終的な重みとして適用します。

この例では、#pageがあるため、重みがクラスセレクタよりも高くなり、最終的な色は赤になります。もし:whereを使用している場合、内部のセレクタは追加の重みを持ちません。

そのため、最終的に適用される色は黄色になります。 上記の結果から、使用シーンは以下のように分けられます:

  • :where()を使用してglobalスタイル(例:リセットなど)を作成し、変更時に簡単に上書きできるようにする
  • :is()を使用して複数のセレクタにlocalスタイルを適用し、全てのセレクタが同じ重みを持つようにする

:has

:hasは、条件を満たす子要素が存在する場合に、親要素をマッチさせることができます。この説明は少し難しいかもしれませんので、具体的な例を使って説明します。実用的なシーンの一つは、「子要素がfocusされたときに親要素のスタイルを変更する」ことです。 例えば、検索機能を実装する際に、検索アイコンを入力ボックスの横に配置します。入力ボックスがfocusされたとき、入力ボックスだけでなくアイコンを含む全体にfocusのスタイルを適用したい場合、input:focusだけでは目的を達成できません。 これまでの解決方法は、DOMの構造を変更してCSSセレクタを有効にするか、JavaScriptでfocusイベントをリスニングして、クラスを追加して親要素にinputがfocusされたことを知らせるものでした。しかし、:hasを使用すると、構造を変更せずにCSSの中でこれを実現できます。

これにより、inputがfocusされたとき、.form:has(input:focus)が発動し、スタイルが親要素に適用されます。「子要素が条件を満たすときに親要素をマッチさせる」ことができるのは、フロントエンドエンジニアの長年の願望であり、これが実現に向けて大きな一歩を踏み出しました。 :hasには他にも使い方があり、特に「子要素が特定の条件を満たすときにこのセレクタを適用する」シーンでの活用が期待できます。

例えば、テーマを切り替える際に、body:has(input[type="checkbox"]:checked)を使用すると、JavaScriptなしで色のテーマを切り替えつつ、合理的なDOM構造を保つことができます。

:hasの使用シーンに関しては、webkitのブログにさらに多くの使用シーンが紹介されています。:hasは比較的新しい擬似クラスであり、ブラウザのサポート状況はまだ高くありません(82.92%)。導入する際は、事前に計画を立てておく必要があります。

:focus-within

ある程度経験のあるフロントエンドエンジニアであれば、先ほどの例は:focus-withinで置き換えられることに気づくかもしれません。:focus-withinは、子要素がfocusされたときに親要素をマッチさせることができます。これにより、親要素のスタイルを変更することが可能です。 例えば、focusされたときにフォームにbox-shadowを追加したい場合、次のように書けます:

しかし、:focus-withinはfocusにのみ適用でき、多様な選択を行うことができないため、focus以外の状況をマッチさせたい場合は、より柔軟な:hasを使用することができます。

:lang

多国語対応のウェブサイトを実装する際、現在のウェブサイトの言語を示すために<html>lang属性を追加します。異なる言語に対して異なるフォントを表示する必要がある場合、:langを使用しないと次のように書く必要があります:

html[lang="zh"] p { font-family: var(--font-zh); }
html[lang="en"] p { font-family: var(--font-en); }

これは少し冗長に感じますが、:langを使用することで、セレクタの記法を簡素化できます。

p:lang(en) {
  font-family: var(--font-en);
}

p:lang(zh) {
  font-family: var(--font-zh);
}

:first-child と :last-child

これらは非常に一般的な擬似クラスですが、まだ多くのフロントエンドエンジニアが知らないことがあります。この二つの擬似クラスは、最初の子要素または最後の子要素を指定することができ、最も一般的な使用シーンは、margin-rightを指定する際に最後の要素には適用したくない場合です。この場合、次のように書くことができます。

.tab {
  margin-right: 8px;
}

.tab:last-child {
  margin-right: 0;
}

また、:notと組み合わせて簡素化することも可能です:

.tag:not(:last-child) {
  margin-right: 8px;
}

なぜJavaScriptを使わないのか?

一部のユーザーは、特にブログなど静的な記事が多いウェブサイトではJavaScriptを無効にしていることがありますが、あまり読みやすさを失いたくない場合、上記で紹介した擬似クラスがレイアウトの問題を解決する手助けとなります。簡単にできるなら、複雑なことは誰も望まないでしょう。

この記事が役に立ったと思ったら、下のリンクからコーヒーを奢ってくれると嬉しいです ☕ 私の普通の一日が輝かしいものになります ✨

Buy me a coffee