dialog タグを利用して、マルチプラットフォーム対応で、良い感じなモーダルUIを作る


[![Image from Gyazo](https://i.gyazo.com/25024f0e73afffbe91ebe7105f64456a.gif)](https://gyazo.com/25024f0e73afffbe91ebe7105f64456a)

:::message
これは[TSUKURUBA Advent Calendar 2022](https://adventar.org/calendars/8189) の3日目の記事です
:::

Zennのみなさん、こんにちは！
[株式会社TSUKURUBA](https://tsukuruba.com/)で、Web フロントエンドエンジニアをしている[kii](https://twitter.com/kiichi_sugihara)です
新卒で入社してもう１年半ほど経ちました。時間の進みを感じます🍂

※この記事は、[Zennで書いた記事](https://zenn.dev/kii/articles/modal-with-dialog-tag-for-multi-platform)の転載記事です✍
- 、事例ないので、Sample code用意した割に、あまり読まれていなくて悲しかったので...


# はじめに

2022年3月、[Safari(15.4)](https://webkit.org/blog/12445/new-webkit-features-in-safari-15-4/)にも待望の`<dialog>`タグがやってきて、
モダンブラウザでは、Web標準の技術を用いて、**簡単に良いモーダルUI**を作れるようになる！と期待が高まったんじゃないでしょうか？


ただ現実的には、プロダクトやサイトの**対応ブラウザバージョン**を考慮すると、利用を躊躇してしまい、頑張ってJavaScriptを書いたり、既存のモーダルライブラリを利用して対応することも多いはず...😢

私も2022年5月に、Web Appのモーダルを新しく作ることになったのですが、
複数の実装方法で比較検討してみた所、
**`<dialog>`タグを利用**して、マルチプラットフォーム対応で良い感じのモーダルUIが作れそうだと分かりました💡
実際にプロダクト開発に利用した所上手くいったので、その知見を共有したいと思います📝

## 🚩 記事の目的

`<dialog>`タグを利用した**良い感じのモーダルUI**が作れる🧩

**良い感じのモーダルUI**

- マルチプラットフォーム対応📱🖥
- モーダルを操作している時に、背景がスクロールしない🖱
- 各インターフェースで操作しやすい⌨️

**スコープ外のこと**


- モーダルUI実装の方法比較検討
  - 対応ブラウザや既存システムの性質によりけりなので、今回は省きます
  - [Scrapboxに軽く書いている](https://scrapbox.io/kii-cafe/Modal_%E3%83%A2%E3%83%BC%E3%83%80%E3%83%AB_UI#624a3473c4b14e000016d8ab)ので参考までにどうぞ。この記事の反応良ければ頑張ってまとめるかも...
- dialogタグの細かい利用方法
  - わかりやすい神記事があるので、そちら見てください(自分も熟読しました)
  - [Building a dialog component](https://web.dev/building-a-dialog-component/)

## 🏃‍♂️ 3行まとめ

- マルチプラットフォーム用に、[dialog-polyfill](https://github.com/GoogleChrome/dialog-polyfill)を利用🤝
- 後ろがスクロールしないようにするために、[body-scroll-lock](https://github.com/willmcpo/body-scroll-lock)を利用🖱👆🏽
- [Code Example](https://stackblitz.com/edit/multi-dialog-sample?file=scripts/dialog.js)を用意したので、forkして遊んでみてください⚽️

# 📄今回、作りたいモーダルUIの要件定義

はじめに、今回作りたいモーダルUIの要件を整理します。

## マルチプラットフォーム対応📱🖥

自身が提供するサービスの**対応ブラウザ全て**で、**機能的、視覚的に問題なく利用**出来る。
自身が提供するサービスの対応ブラウザは、各社それぞれ基準があると思います。
2022年現在だと、`dialog`要素に対応していないブラウザ(Safari iOS ver15.3以前など)を使っているユーザーが一定数いるので、`dialog`要素単体で実装することは難しそうです😢

[![Image from Gyazo](https://i.gyazo.com/6d09fe4929930522f83069aa9814fad2.png)](https://gyazo.com/6d09fe4929930522f83069aa9814fad2)
> 参考: https://caniuse.com/dialog


## モーダルを操作している時に、背景がスクロールしない🖱👆🏽

[![Image from Gyazo](https://i.gyazo.com/0140a3612ff4547564c049ebadeeaf6b.gif)](https://gyazo.com/0140a3612ff4547564c049ebadeeaf6b)
> Dialog外の背景部分もスクロールで動いてしまっているgif

現在の`dialog`タグを利用しただけだと、dialog内でスクロールした際、**dialog外もスクロール**されてしまいます。

これだと、画面全体を覆うUIを作った際、謎に画面がスクロールされている現象に直面します。困りますね😥

## 各インターフェースで操作しやすい⌨️🖱📱

キーボード⌨️、マウス🖱、タッチ📱で操作出来る。
WebAppを利用しているユーザーは、**様々な環境下で利用**しています。それぞれのユーザーに正しく体験を提供したい所です。

特に、**キーボード⌨️時のフォーカス**がモーダルUI実装時に見逃されがちな割に、体験を悪化させるので、以下の点に注意したいです。

- モーダルを開いた際、フォーカスをモーダルに「閉じ込め」て、**Tab移動がモーダル内だけ**で行われる
- モーダルを閉じたら、**フォーカスがモーダルを開くボタンにフォーカスが移動**する

# 🪄実現のための工夫

## マルチプラットフォーム対応にするため、Polyfillを利用🎁

https://github.com/GoogleChrome/dialog-polyfill

`dialog`要素に対応していないブラウザ(Safari iOS ver15.3以前など)に対応するために、polyfillで挟んでサポートします。

幸い、Chromeチーム製の[dialog-polyfill](https://github.com/GoogleChrome/dialog-polyfill)があるので、そちらを利用します。最終リリース日が、2021年1月であることが気になりますが、自分が気になる各ブラウザで動作確認した所、特に問題なかったので利用しました。

## モーダルUIの裏側をスクロールしないようにするために、[body-scroll-lock](https://github.com/willmcpo/body-scroll-lock)を利用🖱

https://github.com/willmcpo/body-scroll-lock

`dialog`タグや[dialog-polyfill](https://github.com/GoogleChrome/dialog-polyfill)では、裏側のスクロール周りの扱いについてサポートされていないため、別途対応が必要です。

スクラッチでサポートするか何かしらのライブラリを利用する必要があります。
そんな時に、[body-scroll-lock](https://github.com/willmcpo/body-scroll-lock)を利用します。

依存パッケージ無しで、2021年6月更新ですが一定利用されており、自身でスクラッチで記述するよりメンテが楽そうです。
もし、パッケージを利用したくない場合は、大したcode量じゃないので、[body-scroll-lock](https://github.com/willmcpo/body-scroll-lock)のコードをコピペして調整するのもいいかもしれません。

## キーボード操作のための、フォーカスの位置調整⌨️

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog

https://github.com/GoogleChrome/dialog-polyfill


こちらの要件は、新しい`<dialog>`の利用と[dialog-polyfill](https://github.com/GoogleChrome/dialog-polyfill)で、ある程度カバー出来ました。(なんて便利なんでしょう✨)

# ⚽️Code Example

https://stackblitz.com/edit/multi-dialog-sample?file=scripts/dialog.js

今回の説明したものを含めたシンプルな例を作りました。参考にしたり、forkして遊んでみてください🙏
案外、実装が簡単なことが分かると思います！

また、記事化出来なかった注意点も、codeのコメントで残しています。特に**iOS限定のバグ対処やその他体験改善の工夫**を盛り込んでいます📝
(時間あれば、もっと見た目綺麗にして、記事に説明増やしたかった...🥺)
気になる所あれば、コメント下さい〜

# おわりに

今回の実装方法だと、
- モーダルUIライブラリのお作法を気にせず**Web標準のAPI使って、カスタマイズしやすい点**、
- ユーザーの利用ブラウザのバージョンが上がったり、dialogタグの機能が拡張されると、**ライブラリを剥がしてScriptのSizeを軽く出来る**点、

が良いなと思っています!
今回の紹介で、`dialog`要素を利用して、簡単に良い感じのモーダルUIが作れたら、嬉しいです。

おわり

<details>
<summary>参考リンク群と補足</summary>


[Building a dialog component](https://web.dev/building-a-dialog-component/)

[![Image from Gyazo](https://i.gyazo.com/e5e737d2e48b4e28f962d0f86a96224a.gif)](https://gyazo.com/e5e737d2e48b4e28f962d0f86a96224a)

- [Adam Argyle](https://twitter.com/argyleink)さんが書いた神記事
- `dialog`タグを利用して、凄く良い体験のモーダルUI作って紹介してくれています
- 概念ごとに紹介してくれていて、とても分かりやすいです✨まず、見て各概念理解するのオススメします！

[モーダルUIの調査メモ by kii](https://scrapbox.io/kii-cafe/Modal_%E3%83%A2%E3%83%BC%E3%83%80%E3%83%AB_UI)

- 一度、↑で紹介していますが、私がモーダルUI実装するにあたり、メモしていたノートです
- 他の実装方法とか気になればどうぞ

[実際作ったcowcamoのモーダルUI by kii](https://cowcamo.jp/search/form)

[![Image from Gyazo](https://i.gyazo.com/b1bbc706d04bbd76b6306e9c34dda8a9.gif)](https://gyazo.com/b1bbc706d04bbd76b6306e9c34dda8a9)


- 実際に、私が作ったUIもこっそり共有しておきます。今後も更新すると思うので、真のExampleですね
- 正直にいうと、直したい箇所たくさんあります...
- 何か意見あれば、こっそり教えて下さい🙏お手柔らかに🥺
- 東京付近住んでいるなら、cowcamoをぜひ、利用してみてくださいね🏡(宣伝)
  - [Web](https://cowcamo.jp/)
  - [iOS](https://apps.apple.com/jp/app/apple-store/id1282237769)
  - [Android](https://play.google.com/store/apps/details?id=com.tsukuruba.cowcamo.z&pli=1)

</details>