tailwindcss だけでモーダルを実装してみる

## この記事が解説すること

tailwindcss だけでモーダルを実装する方法を解説します。
本気で tailwindcss だけしか使えない環境はレアだと思いますが、でも tailwindcss だけで済むのだったらそれが何よりという環境の方はいると思って書いていきます。

## 結論のコードはこれ

```use_fragment_modal.html
<a href="#modal" class="block w-fit"><img src="/dist/sample_thumb.jpg" class="w-24 rounded-lg" /></a>
<div id="modal" class="hidden target:block">
    <div class="block w-full h-full bg-black/70 absolute top-0 left-0">
    <a href="#" class="block w-full h-full cursor-default"></a>
        <div class="w-3/4 mx-auto mt-20 relative -top-full">
            <img src="/dist/sample.jpg" />
        </div>
    </div>
</div>
```

もしくはこれ。

```no_fragment_modal.html
<div class="group">
    <button class="block w-fit"><img src="/dist/sample_thumb.jpg" class="w-24 rounded-lg" /></button>
    <div class="hidden group-focus-within:block">
        <div class="block w-full h-full bg-black/70 absolute top-0 left-0">
            <button class="block w-3/4 mx-auto mt-20">
                <img src="/dist/sample.jpg" />
            </button>
        </div>
    </div> 
</div>
```

## 見た目はこうなる

| before | after |
|---|---|
| ![127.0.0.1_5500_src_index.html(iPhone SE).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116105/74c1ad28-6a1c-c131-f2b6-f834e52ad916.png) | ![127.0.0.1_5500_src_index.html(iPhone SE) (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116105/c55a8174-834d-e313-7beb-f2ff268d8ae3.png) |

## use_fragment_modal.html の解説

1行目と2行目がほぼ本質となります。
1行目の`<a href="#modal">` と2行目の `<div id="modal" class="hidden target:block">` で、リンクをクリックしたときに2行目以降の div の中身が表示されるようになります。
https://tailwindcss.com/docs/hover-focus-and-other-states#target
上記のマニュアルにある通り、 `target:` は要素の ID が現在の　URL フラグメントと一致するときにスタイルを適用するように指示する擬似クラスです。
1行目のリンク先は `#modal` で、これは2行目の `id="modal"` に一致するので、デフォルトでは `hidden` であったスタイルがこの時に `block` へと変わり、2行目以降に記述されている要素が見えるようになります。
あとは2行目の div の中身がモーダルっぽい挙動をするように調整すればいいだけです。
今回は4行目のa要素を画像の下に敷く感じで、画像以外のところをクリックしたらモーダルが閉じるようにしてみました。

## no_fragment_modal.html の解説

1行目と3行目、そして `button` 要素がキモです。
1行目で `class="group"` を指定していますが、この `group` クラスの子要素で `group-{modifire}` を指定すると、 `group` クラスの状態が拾えるようになります。3行目の `group-focus-within:block` がそれです。
https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state
そして、その3行目の `group-focus-within` がどのような状態を拾うのかですが、まず `focus-within` が何なのかを見てみます。
https://tailwindcss.com/docs/hover-focus-and-other-states#focus-within
ここには、このクラスを指定した要素か、その子要素にフォーカスがあるときにスタイルを適用できるようになると解説されています。
それが `group-focus-within` になると、 `group` を指定した要素か、その子要素にフォーカスがあるときにスタイルが適用できるようになるのです。
今回2つの `button` がありますが、 どちらの `button` も `<div class="group">` の子要素なので、どちらをクリックしても `group-focus-within:block` が適用されます。
イメージとしては、サムネイルにかかっている `button` はモーダルを開くためのボタンですが、モーダル上の画像にかかっている `button` はモーダルを開き直しているボタンとなります。
もし画像にかかっている `button` を `div` に変更したら、画像をクリックしたときにもモーダルが閉じてしまうようになります。それを防ぐために、画像を `button` 要素の下に持ってきて、画像をクリックしたときにも再度モーダルを開くことで、擬似的に画像をクリックしても閉じないモーダルに見せかけているのです。

## まとめ

ちょっと夜中のテンションで書き殴ったものなので、解説が分かりにくいかも知れません。
ただ、意外と tailwindcss だけでモーダルを作った記事というのが見当たらなかったのでこの記事を書きました。 tailwindcss 周りは便利なツールがたくさんあり、それらを使ったモーダルの作り方はあるのですが…。けれども、そうしたツールを導入できなかったり、依存先を増やしたくないという判断だったりで、tailwindcss だけで物事が済んでくれたらと思うことはそれなりにあるのかなぁと思います。
そんな環境にいる方の参考になれば幸いです。