2023/04/21

ChatGPTでJSモーダルウインドウプラグインを作った

割と平気でウソもつくけど繰り返しツメ続ければちゃんと使えるコードを提示してくれるChatGPTのおかげで、自分用に作って使っていたちょっとしたDOM操作用のJSプラグインの脱jQuery事業をおおかた完了できた。
しかしモーダルやスライダーとなるとちょっと壁が高い。わざわざ作らなくてもネイティヴJSの定番モーダルプラグインがあったりしないかなと調べてみたら、アクセシビリティへの配慮もばっちりなmicromodal.jsというやつが良いとのこと。だが仕様を確認してみると、表示させるコンテンツの外枠などなどを同じページに書いておく必要があるようで、modaal便利だな~とぬるま湯に浸かっていたジェイクエラーにとっては少々違う感が。
ならば、micromodal.jsを簡単に使えるようにするプラグインを作ればいいじゃないか、と思って挑戦し(てもらい)はじめた結果、mocromodal.jsは関係なく単体で完結するモーダルプラグインを作ることができた。

minifyすればかなり小さくなるし、なかなか明快な構造でモジュール化できたからカスタマイズもしやすいはず。
詳しくは実物をどうぞ。

デモ

実行のしかた

automodal.jsとautomodal.cssの内容をダウンロードしてリンクするなり、インラインで書いてしまうなりしたら、以下の記述でシンプルに実行。(※さっきのURLに直接リンクしないでください、ただの共用レンタルサーバなので)

document.addEventListener("DOMContentLoaded",function(){
  autoModal("対象要素");
});

どこがautoかというと、例えばmodaalだとYouTube動画をモーダル表示したい場合なんかはオプションでタイプの指定が必要だったけど、

  1. 画像1枚かどうか
  2. YouTube動画かどうか
  3. その他ウェブページかどうか(iframeで表示)
  4. インラインコンテンツかどうか

をリンク元のhref=""の値で自動判別するため、タイプの指定が不要だから。
コンテンツの流し込み方に違いがあるほか、それぞれのタイプにあわせてモーダルの一番外側のdiv要素にdata-mm-type="singleImg / YouTube / iframe / inline"のいずれかが付与され、CSSの調整に利用できる。この4つで間に合っていなければfunction generateContentの中身を修正してください。

リンク元のaタグで利用できる属性

<a href="(URL)"
  data-mm-caption="(キャプション)"
  data-mm-alt="(画像1枚の場合のalt属性値)"
  data-mm-group="(この値が同じもの同士がギャラリー形式でスライド切替できる)">

さっきはギャラリー表示のデモがなかったのでここに。

その他のオプション

実行記述の第二引数を

document.addEventListener("DOMContentLoaded",function(){
  autoModal("対象要素","someClass");
});

のようにすると、モーダルの一番外側のdiv要素にその名前のクラスが付与される。YouTubeの縦型動画を載せたいときなど、個別の表示調整が必要な場合に使うと便利。

また、インラインで自由にモーダルコンテンツを組むとき、任意の要素を「閉じるボタン」にしたい場合は、下の例のように当該要素にdata-mm-close属性を持たせればよい。(値は不要)

<button data-mm-close>閉じる</button>

こまかいポイント

  • micromodal.jsを参考にしてアクセシビリティに配慮。モーダルを開くとモーダル内の要素にフォーカスが移り、閉じたらもともとフォーカスが当たっていた要素に戻る。またモーダルが開いているあいだはモーダル外の要素にフォーカスが移動しない。
    ※2023/5/15 tabindex属性による制御をinert属性に変更
  • モーダルを開く前の状態のページで縦スクロールが発生していた場合、モーダルを開いたらうしろのページ本体はスクロールがロックされるが、スクロールバーの幅の分だけペコッと横移動しない。
  • 画像ファイルを一切使用しておらず、CSSを置く階層は自由。かつ入れ子構造も最小限のため、スタイルのカスタマイズも比較的容易。
  • 中央揃えにはflexを利用し、サイズ指定もパーセント指定でおこなっているので、表示後のウインドウサイズ変更やレスポンシブ対応に強い。無駄にデフォルト最大値を決めておらず、できるだけ大きく表示される。

以上、ネイティブJSでおおむねmodaalの基本機能と同じようなことが、さらに楽にできているのでは。
開いたり閉じたりの操作と同時に何かのイベントを仕込む必要があるなら、差し込みやすいようにコメントが書いてあるので、カスタマイズはご自由に。