状態バリアント
この章では、Tailwind CSS で要素の状態に応じたスタイリングを学びます。
ホバー・フォーカス・アクティブ
hover
マウスホバー時のスタイルを指定します。
<button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-sm">
ホバーで色が変わる
</button>
<a href="#" class="text-blue-500 hover:text-blue-700 hover:underline">
ホバーで下線表示
</a>
備考
v4 では hover スタイルは @media (hover: hover) でラップされ、ホバー非対応デバイス (タッチ操作のみ) では適用されません。v3 までのタップ発火に依存している場合は @custom-variant hover (&:hover); で旧挙動に戻せます。
focus
フォーカス時のスタイルを指定します。
<input
type="text"
class="border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-500 focus:outline-hidden
px-4 py-2 rounded-sm"
placeholder="フォーカスで枠が青くなる"
/>
<button class="bg-blue-500 focus:ring-4 focus:ring-blue-300 text-white px-4 py-2 rounded-sm">
フォーカスリング
</button>
focus-visible
キーボード操作時のフォーカスのみに適用されます。
<button class="focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:outline-hidden
px-4 py-2 rounded-sm">
キーボードフォーカス時のみリング表示
</button>
focus-within
子要素がフォーカスされた時に親要素に適用されます。
<div class="border border-gray-300 focus-within:border-blue-500 focus-within:ring-1 focus-within:ring-blue-500 p-4 rounded-sm">
<label class="block text-sm mb-1">ラベル</label>
<input type="text" class="w-full focus:outline-hidden" />
</div>
active
クリック中のスタイルを指定します。
<button class="bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white px-4 py-2 rounded-sm">
クリック中に色が変わる
</button>
フォーム状態
disabled
<button class="bg-blue-500 disabled:bg-gray-300 disabled:cursor-not-allowed text-white px-4 py-2 rounded-sm" disabled>
無効なボタン
</button>
<input
type="text"
class="border disabled:bg-gray-100 disabled:text-gray-500 disabled:cursor-not-allowed px-4 py-2 rounded-sm"
disabled
value="無効な入力"
/>
required
<input
type="text"
class="border required:border-red-500 px-4 py-2 rounded-sm"
required
/>
invalid
<input
type="email"
class="border invalid:border-red-500 invalid:text-red-500 focus:invalid:ring-red-500 px-4 py-2 rounded-sm"
value="invalid-email"
/>
valid
<input
type="email"
class="border valid:border-green-500 px-4 py-2 rounded-sm"
value="valid@email.com"
/>
checked
<label class="flex items-center gap-2">
<input
type="checkbox"
class="w-5 h-5 appearance-none rounded-sm border border-gray-300 checked:bg-blue-500 checked:border-transparent"
/>
チェックボックス
</label>
indeterminate
<input
type="checkbox"
id="some-checkbox"
class="appearance-none indeterminate:bg-gray-300"
/>
<script>
document.getElementById('some-checkbox').indeterminate = true;
</script>
indeterminate 状態は HTML 属性では設定できず、JavaScript からのみ設定できます。
placeholder-shown
<input
type="text"
class="border placeholder-shown:border-gray-300 not-placeholder-shown:border-blue-500 px-4 py-2 rounded-sm"
placeholder="プレースホルダー"
/>
read-only
<input
type="text"
class="border read-only:bg-gray-100 read-only:cursor-not-allowed px-4 py-2 rounded-sm"
readonly
value="読み取り専用"
/>
グループ
親要素の状態に基づいて子要素をスタイリングします。
group-hover
<div class="group p-4 bg-white rounded-lg shadow-sm hover:bg-blue-500 cursor-pointer">
<h3 class="font-bold group-hover:text-white">タイトル</h3>
<p class="text-gray-600 group-hover:text-blue-100">説明文</p>
</div>
group-focus
<button class="group px-4 py-2 rounded-sm border focus:ring-2">
<span class="group-focus:text-blue-500">フォーカス時に青くなる</span>
</button>
名前付きグループ
複数のグループを区別できます。
<div class="group/card p-4 bg-white rounded-lg shadow-sm hover:shadow-lg">
<div class="group/title">
<h3 class="font-bold group-hover/card:text-blue-500">タイトル</h3>
<button class="opacity-0 group-hover/title:opacity-100">編集</button>
</div>
<p class="group-hover/card:text-gray-700">説明文</p>
</div>
ピア (兄弟要素)
兄弟要素の状態に基づいてスタイリングします。
peer
<div>
<input type="checkbox" id="toggle" class="peer sr-only" />
<label for="toggle" class="cursor-pointer">トグル</label>
<div class="hidden peer-checked:block mt-2 p-4 bg-gray-100 rounded-sm">
チェック時に表示されるコンテンツ
</div>
</div>
フォームバリデーション
<div>
<input
type="email"
class="peer border px-4 py-2 rounded-sm invalid:border-red-500"
placeholder="メールアドレス"
required
/>
<p class="hidden peer-invalid:block text-red-500 text-sm mt-1">
有効なメールアドレスを入力してください
</p>
</div>
名前付きピア
<div>
<input type="text" class="peer/name" placeholder="名前" />
<input type="email" class="peer/email" placeholder="メール" />
<p class="hidden peer-invalid/email:block text-red-500">
メールが無効です
</p>
</div>
構造ベースの擬似クラス
first / last
<ul>
<li class="py-2 border-b first:pt-0 last:pb-0 last:border-b-0">項目 1</li>
<li class="py-2 border-b first:pt-0 last:pb-0 last:border-b-0">項目 2</li>
<li class="py-2 border-b first:pt-0 last:pb-0 last:border-b-0">項目 3</li>
</ul>
odd / even
<table>
<tbody>
<tr class="odd:bg-gray-50 even:bg-white">
<td class="p-4">行 1</td>
</tr>
<tr class="odd:bg-gray-50 even:bg-white">
<td class="p-4">行 2</td>
</tr>
<tr class="odd:bg-gray-50 even:bg-white">
<td class="p-4">行 3</td>
</tr>
</tbody>
</table>
first-of-type / last-of-type
<div>
<p class="first-of-type:font-bold">最初の p 要素</p>
<p>2 番目の p 要素</p>
<p class="last-of-type:text-gray-500">最後の p 要素</p>
</div>
only-child
<ul>
<li class="only:text-center">唯一の子要素の場合のみ中央揃え</li>
</ul>
empty
<div class="p-4 empty:hidden">
<!-- 空の場合は非表示 -->
</div>
before / after
擬似要素 ::before と ::after のスタイリング。
<span class="before:content-['*'] before:text-red-500 before:mr-1">
必須項目
</span>
<a href="#" class="relative after:absolute after:bottom-0 after:left-0 after:w-full after:h-0.5 after:bg-blue-500 after:scale-x-0 hover:after:scale-x-100 after:transition-transform">
ホバーで下線アニメーション
</a>
コンテンツなしの擬似要素
<div class="relative before:content-[''] before:block before:absolute before:inset-0 before:bg-linear-to-r before:from-blue-500 before:to-purple-500 before:opacity-50">
グラデーションオーバーレイ
</div>
has
v3.4 で追加された has-* バリアント。CSS の :has() セレクタを Tailwind のユーティリティとして使用できます。v4 では has-checked: のような名前付き形式も利用できます。
<!-- 子要素にチェックされた入力がある場合 -->
<div class="has-[:checked]:bg-blue-50 has-[:checked]:border-blue-500 border p-4 rounded-sm">
<label class="flex items-center gap-2">
<input type="checkbox" />
オプション
</label>
</div>
<!-- 特定の子要素を持つ場合 -->
<div class="has-[img]:p-0 p-4">
<img src="..." />
</div>
バリアントの組み合わせ
複数のバリアントを組み合わせることができます。
<!-- レスポンシブ + ホバー -->
<button class="bg-blue-500 md:hover:bg-blue-600 px-4 py-2 rounded-sm">
md 以上でのみホバー効果
</button>
<!-- グループ + フォーカス -->
<div class="group">
<button class="group-focus:ring-2">ボタン</button>
</div>
<!-- ダークモード + ホバー -->
<button class="bg-white dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700">
ダークモード対応ホバー
</button>
実践例
インタラクティブなカード
<div class="group relative bg-white rounded-xl shadow-md hover:shadow-xl transition-shadow overflow-hidden">
<div class="absolute inset-0 bg-linear-to-r from-blue-500 to-purple-500 opacity-0 group-hover:opacity-10 transition-opacity"></div>
<img src="..." class="w-full h-48 object-cover group-hover:scale-105 transition-transform duration-300" />
<div class="p-6">
<h3 class="font-bold text-xl group-hover:text-blue-500 transition-colors">タイトル</h3>
<p class="mt-2 text-gray-600">説明文...</p>
<button class="mt-4 px-4 py-2 bg-blue-500 text-white rounded-sm opacity-0 group-hover:opacity-100 translate-y-2 group-hover:translate-y-0 transition-all">
詳細を見る
</button>
</div>
</div>
フローティングラベル入力
<div class="relative">
<input
type="text"
id="email"
class="peer w-full px-4 py-3 border rounded-lg placeholder-transparent focus:outline-hidden focus:ring-2 focus:ring-blue-500 focus:border-transparent"
placeholder="メールアドレス"
/>
<label
for="email"
class="absolute left-4 top-3 text-gray-500 transition-all
peer-placeholder-shown:top-3 peer-placeholder-shown:text-base
peer-focus:-top-2.5 peer-focus:text-sm peer-focus:text-blue-500
-top-2.5 text-sm bg-white px-1"
>
メールアドレス
</label>
</div>
アコーディオン
<div class="border rounded-lg">
<div>
<input type="checkbox" id="accordion1" class="peer sr-only" />
<label for="accordion1" class="flex justify-between items-center p-4 cursor-pointer hover:bg-gray-50 peer-checked:[&_svg]:rotate-180">
<span class="font-medium">セクション 1</span>
<svg class="w-5 h-5 transition-transform">...</svg>
</label>
<div class="hidden peer-checked:block px-4 pb-4">
アコーディオンの内容...
</div>
</div>
</div>
まとめ
hover:/focus:/active:で基本的なインタラクションdisabled:/invalid:/checked:でフォーム状態group-*で親要素の状態に基づくスタイリングpeer-*で兄弟要素の状態に基づくスタイリングfirst:/last:/odd:/even:で位置ベースのスタイリングbefore:/after:で擬似要素has-*で子要素の状態に基づくスタイリング- バリアントは組み合わせ可能
次に読む
- ダークモード —
dark:バリアントで配色を切り替える - アニメーション —
transition/animate-*で動きをつける - Tailwind CSS ガイド 目次 — 全 18 章の構成に戻る