Tailwind CSS の has クラスを使いこなそう
Tailwind CSS の v3.4 で追加された :has() 擬似クラス。
便利なのは分かっているのですが、自然に使いこなせるまで馴染んでおらず、なんとなく避けたまま実装していました。
しかし、よくよくドキュメントを読んでみると、Tailwind CSS ならではの拡張性でより直感的に :has() 擬似クラスを利用できることが分かりました。
スタートアップのプロダクト開発支援をしている Gaji-Labo では、モダンな開発環境として Tailwind CSS と Next.js を採用することが多くあります。
特に Next.js の App Router でのインタラクティブな実装において、:has() 擬似クラスが多いに活躍しそうです。
ということで本記事では、まず :has() 擬似クラスの基本を押さえたうえで、Tailwind CSS で使用できる3つの has クラスの特徴と使用方法についてまとめてみたいと思います。
:has() 擬似クラスとは
:has()
は、引数の中で指定したセレクタを含んでいる要素を指定できる機能です。
/* imgタグ含むpタグを指定 */
p:has(img) {
padding: 1em;
}
/* エラーになった入力欄を含む.formクラスを指定 */
.form:has(input:invalid) {
border: 1px solid red;
}
/* 最後の子要素がpタグのsectionを指定 */
section:has(p:last-child) {
margin-bottom: 2em;
}
基本的には親要素を指定して DOM ツリーの上方向に要素選択します。また、相対セレクタを引数として渡すことで、親要素以外にも多くの要素をターゲットできます。
Tailwind CSS では、この :has() 擬似クラスをシンプルに使用するクラスと、group / peer と組み合わせたクラスを利用できます。
Tailwind CSS における :has() 擬似クラスの基本
Tailwind CSS で提供されている has クラスには以下の3種類があります。
- has-[…]:子要素の存在条件によるスタイリング
- group-has-[…]:親要素の配下の存在条件によるスタイリング
- peer-has-[…]:兄弟要素の配下の存在条件によるスタイリング
通常の :has() はもちろん、より複雑な条件でのスタイリングを簡単に行うことができます。
実際に使ってみましょう。
has-[…]
まずは普通の has から。
has-[...]
のような書き方で、ブラケットの中で子孫の状態やコンテンツを指定することで、親要素のスタイルを変更できます。
<!-- チェックボックスがチェックされると背景と文字色を変更する -->
<div class='p-6'>
<label class='
rounded-md grid w-fit grid-flow-col gap-2 border p-4
has-[:checked]:bg-indigo-50 has-[:checked]:text-indigo-900 has-[:checked]:ring-indigo-200
'>
CheckBox
<input type='checkbox' class='checked:border-indigo-500' />
</label>
</div>
group-has-[…]
2つ目は group を使用した書き方。group-has-[…]
です。
こちらは、親要素の子孫の状態や内包するコンテンツに基づいて、指定した要素をスタイリングできます。
下のデモでは、親要素内に img タグが存在するかどうかで、他のテキストの font-size を変更しています。
<!-- カード内の画像の有無によりテキストのフォントサイズを変更する -->
<div class="grid gap-2 p-4 w-80">
<div class="group p-4 rounded border bg-white">
<img
src="https://images.unsplash.com/photo-1682686581427-7c80ab60e3f3"
alt="カード画像"
class="w-full rounded mb-4 h-48 object-cover"
/>
<h3 class="font-bold text-xl group-has-[img]:text-md group-has-[img]:mb-2">
カードのタイトル
</h3>
<p class="text-gray-600 group-has-[img]:text-xs group-has-[img]:leading-relaxed">
ここにカードの説明文が入ります。画像の有無によってテキストのスタイルが自動的に調整されます。
</p>
</div>
<div class="group p-4 rounded border bg-white">
<h3 class="font-bold text-xl group-has-[img]:text-md group-has-[img]:mb-2">
カードのタイトル
</h3>
<p class="text-gray-600 group-has-[img]:text-xs group-has-[img]:leading-relaxed">
ここにカードの説明文が入ります。画像の有無によってテキストのスタイルが自動的に調整されます。
</p>
</div>
</div>
peer-has-[…]
最後にpeer-has-[...]
です。
こちらは、兄弟要素の子孫の状態や内包するコンテンツに基づいて、指定した要素をスタイリングできます。
下のデモでは、セレクト要素の選択内容によって、その兄弟要素テキストの表示・非表示を切り替えています。
<div class="space-y-4 p-4">
<select class="peer w-min appearance-none border row-start-1 col-start-1 rounded-lg bg-slate-50 border-slate-300 text-slate-700 p-4">
<option value="">配送方法を選択してください</option>
<option value="standard">通常配送</option>
<option value="express">スピード配送</option>
</select>
<div class="peer-has-[option[value='standard']:checked]:block hidden text-gray-600">
通常配送は3-5営業日でお届けします
</div>
<div class="peer-has-[option[value='express']:checked]:block hidden text-red-600">
スピード配送は翌営業日にお届けします
</div>
</div>
App Router のサーバーコンポーネントで活躍しそう
Next.js の App Router では、すべてのコンポーネントがデフォルトでサーバーコンポーネントとして扱われます。
これによりパフォーマンスや SEO などにおいて様々なメリットを受けられますが、インタラクティブな実装をするにはクライアントコンポーネントに切り替える必要がありました。
しかし、Tailwind CSS の has クラスを活用すれば、ある程度の柔軟でインタラクティブな実装をサーバーコンポーネントのまま行えそうです。
サーバーコンポーネントの利点を最大限に活かすため、今後は has クラスを活用していこうと思いました。
Gaji-Labo では、Next.js の App Router や Tailwind CSS といったフロントエンド技術を活用し、スタートアップのプロダクト開発を支援しています。
フロントエンドエンジニアをはじめ、各職種でメンバーを募集しておりますので、興味のある方はぜひご案内資料をご覧ください!
Gaji-Labo フロントエンドエンジニア向けご案内資料
Gaji-Labo は Next.js, React, TypeScript 開発の実績と知見があります
フロントエンド開発の専門家である私たちが御社の開発チームに入ることで、バックエンドも含めた全体の開発効率が上がります。
「既存のサイトを Next.js に移行したい」
「人手が足りず信頼できるエンジニアを探している」
「自分たちで手を付けてみたがいまいち上手くいかない」
フロントエンド開発に関わるお困りごとがあれば、まずは一度お気軽に Gaji-Labo にご相談ください。
オンラインでのヒアリングとフルリモートでのプロセス支援にも対応しています。
Next.js, React, TypeScript の相談をする!