簡単に作れる!showModal()メソッドを使ってモーダルを実装しよう

こんにちは、ユアサです。
今回は誰でも簡単にモーダルが作れるようになるshowModal()メソッドを使って、実用的なモーダルを実装してみたいと思います。

割とやっていたモーダルの実装方法

モーダルの要素を用意するのは大前提ですが、そこから開くためのボタンを設置して、そのボタンが押されたらモーダルの要素を表示、今度はモーダル内の閉じるボタンや背景をクリックするとモーダルを閉じる、といった流れになるようJSを記述していました。

デフォルトでモーダルが非表示の状態じゃないといけないのでまずdisplay: none;にしようか?アニメーションも効かせたいからopacityで調整して、背景色も敷いて、z-indexで重なり順を調整して、モーダル自身の位置を固定して・・・・・・・と、モーダル一つ実装するのに考えることが多い気がします。

自作でなくても誰かが公開してくれているプラグインを使えば楽ではあるのですが、スタイルを細かく調整する際にプラグイン標準のCSSとぶつかってそれを考慮してまた調整・・・というのが個人的にはどうも苦手で、同じように感じる方もそう少なくないはずです(と思いたいです)。

自分のような面倒くさがりには『簡単に実装できてスタイル調整も管理も楽でありたい』という我儘な欲があるわけですが、これを比較的叶えてくれるのがshowModal()メソッドです。

メソッドの使い方

難しいことは何もありません。超簡単。
モダールを開くボタンとdialogタグを作成し、dialogタグ内にモーダル内で表示させたい要素を記述します。あとはJSで開くボタンをクリックした際の挙動を書きます。

See the Pen modal_dialog_01 by felly (@felly00505) on CodePen.

上記コードが最低限の記述になりますが、開くボタンのaddEventListener()メソッド内に記述されているshowModal()メソッドでdialogタグをモーダルダイアログとして表示させています。

「open」ボタンで開くと分かるかと思いますが、CSSを何も記述していないどころか、背景用の要素すら用意していないのに背景色も敷かれています。これはモーダルダイアログ表示の際にデフォルトで付与されている擬似要素::backdropが背景に広がっているためです。

モーダルダイアログの擬似要素 ::backdrop

この擬似要素::backdrop::before::after同様にCSSでスタイルを調整できます。例えば::backdropの背景色をもう少し濃くしたい場合は

See the Pen modal_dialog_02 by felly (@felly00505) on CodePen.

といった具合に指定できます。
このようにモーダルとしてのスタイル・機能は最低限用意されている上、CSSでスタイルを上書きして調整もできるので、HTMLで背景用の空要素を用意したりCSSを一から書いたりする必要がなく便利です。

開閉できるようにする

モーダルを開いたら当然閉じるボタンも必要です。こちらも簡単で、close()メソッドでモーダルダイアログを閉じることができます。

See the Pen modal_dialog_03 by felly (@felly00505) on CodePen.

上記コードまででモーダルの開閉ができるようになりました。基本動作はこれで一通りできましたね!

さて閉じるボタンを実装できましたが、どうせなら背景をクリックした際にも閉じる動作を追加したいですね。

See the Pen modal_dialog_04 by felly (@felly00505) on CodePen.

こちらは流石に背景用の要素を追加して、その要素の上にトップレイヤーとして重ねるコンテナ要素でモーダル内のコンテンツを囲う必要があります。ですがこれで背景クリック後の動作も実装できました。

・・・と思っていたのですが、背景用の空要素を用意しなくても『クリックされた箇所がモーダル外であれば閉じる』という解釈であれば、空要素もコンテンツを囲うコンテナ要素も必要なくなるそうです。なるほど、工夫の仕方でHTMLも改善できるわけですね。

↓上記の内容を参考にさせていただいた記事はこちら

pote-chil.com

実際に反映してみたコードは以下の通りです。

See the Pen modal_dialog_04-fixed by felly (@felly00505) on CodePen.

アニメーションをつける

どうせモーダルを作るならフェードイン・フェードアウトするようなアニメーションもあるとなお良いですよね。一度モーダルダイアログの標準のスタイルを確認しましょう。

dialogタグの標準のスタイル

display: none;が付与されているので、これを考慮した上で調整する必要がありそうです。とりあえず作ってみます。

See the Pen modal_dialog_05 by felly (@felly00505) on CodePen.

transition: 0.15s;でアニメーションの速度を指定し、モーダルダイアログ自体をopacity: 0;を付与して透明に、「open」ボタンがクリックされた際にdialogタグにis-openクラスを付与することによってopacity: 1;を付与して不透明にするようにしました。

実際に挙動を見ていただければ分かりますが、アニメーションは開く際は問題ありませんが閉じる時に効きませんね。transitionプロパティはdisplay: none;の時には作用しないので、閉じる時にdialogタグがdisplay: none;になる以前にアニメーションを発火させる必要があります。
display: none;の要素はそもそもそこに無い判定なので、無いものをアニメーションさせることはできないよ、という原理になるかと思います)

つまり動作の順番としては

  1. 「close」ボタンを押す
  2. アニメーションを発火(opacity: 1; → opacity: 0;)
  3. close()メソッド実行

となります。
今回の場合、transition: 0.15s;、つまりアニメーション速度が0.15秒と指定されているので、modal.close()を0.15秒分ずらせば上手くいきそうです。setTimeOut()メソッドを使ってこれを実装します。

See the Pen modal_dialog_05-fixed by felly (@felly00505) on CodePen.

閉じる際もフェードアウトしていますね!これでアニメーションの方も問題なさそうです。

最後に

showModal()を使って簡単に実用的なモーダルを実装してみました。
今回はあくまでもモーダルダイアログとしての基本的なところをおさえておくことにフォーカスしていたので、form要素でモーダルの値を渡したりopen属性の有無の判定などの話は一旦省きました。(この辺の話は仕様などのディープな話もあるようなので、自分が把握しきれていないという理由もありますが)

モーダルが簡単に作れてスタイル調整も楽なのは個人的にやりやすいなーと感じたので記事にまとめましたが、実際に手を動かして触ってみてより実感しました。良いですねこれ。
最後まで読んでいただきありがとうございました!