🦚

tailwindcssで入れ子だけど特定の要素にスタイル指定したかった話

に公開

tailwindcssで操作に応じたスタイル定義でつまったので備忘録です

きっかけ

チェックボックスにチェックしたときに変更するスタイルの範囲を指定したかった

https://github.com/tailwindlabs/tailwindcss/issues/17314
tailwindcssのissueがあがっているように
入れ子でグループを区別した際、
group-has-checkedのようなそれぞれの入れ子だけスタイルを適用するのは
現時点ではできないようです

とりあえず書く

ドキュメントに書いているように入れ子でグループを指定するにはgroup/{name}とすればいいので
そのようにかいてみます
ドキュメント詳細はこちらから
https://tailwindcss.com/docs/hover-focus-and-other-states

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
  <title>とりあえず書いてみる</title>
</head>

<body>
  <div class="m-4">
    <div class="group/main border border-black-50">
      <label for="first-check">
        <input type="checkbox" name="" id="first-check">
        <span>1つめのチェックボックス</span>
      </label>
      <div class="hidden group-has-checked/main:block">
        <p>1つめのチェックボックスをチェックしました!</p>
      </div>
      <div class="group/sub border border-red-500">
        <label for="second-check">
          <input type="checkbox" name="" id="second-check">
          <span>2つめのチェックボックス</span>
        </label>
        <div class="hidden group-has-checked/sub:block">
          <p>2つめのチェックボックスをチェックしました!</p>
        </div>
      </div>
    </div>
  </div>
</body>

</html>

結果

2つめのチェックボックスしかチェックしていないのに
1つめがチェックされたときに表示する文字列も表示されてしまう
とりあえず書いたときの画面キャプチャ

補足

group/main-has-checkedgroup/sub-has-checkedではスタイル反映できなかったです
group/main-has-checked, group/sub-has-checkedに書き換えた場合の画面キャプチャ

打開策

直接スタイル定義します
is()とwhere()とhas()、3つの疑似関数クラスを組み合わせて使います

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
  <title>直接スタイル定義する</title>
  <style>
    .show-main {
      &:is(:where(.main) *) {
        display: none;
      }

      &:is(:where(.main):has(#first-check:checked) *) {
        display: block;
      }
    }

    .show-sub {
      &:is(:where(.sub) *) {
        display: none;
      }

      &:is(:where(.sub):has(#second-check:checked) *) {
        display: block;
      }
    }
  </style>
</head>

<body>
  <div class="m-4">
    <div class="main border border-black-50">
      <label for="first-check">
        <input type="checkbox" name="" id="first-check">
        <span>1つめのチェックボックス</span>
      </label>
      <div class="show-main">
        <p>1つめのチェックボックスをチェックしました!</p>
      </div>
      <div class="sub border border-red-500">
        <label for="second-check">
          <input type="checkbox" name="" id="second-check">
          <span>2つめのチェックボックス</span>
        </label>
        <div class="show-sub">
          <p>2つめのチェックボックスをチェックしました!</p>
        </div>
      </div>
    </div>
  </div>
</body>

</html>

補足

利用した疑似クラス関数の詳細はこちらから
https://developer.mozilla.org/ja/docs/Web/CSS/:is
https://developer.mozilla.org/ja/docs/Web/CSS/:where
https://developer.mozilla.org/ja/docs/Web/CSS/:has

結果

意図したスタイルをあてられました
直接スタイル定義した場合の画面キャプチャ

蛇足

指定したチェックボックスの親要素だけスタイルを定義する

.main:has(#first-check:checked) {
  background-color: aquamarine;
}

.sub:has(#second-check:checked) {
  background-color: cadetblue;
}

子要素や孫要素だけにスタイルをあてるのはtailwindcssだけではむずかしかったです
利用用途はかなり限定的ですが、
いままでjsを使っていた部分がcssだけで実現できるようになるのは
すごいです..

Discussion