https://ics.media/entry/220620/

ダイアログやハンバーガーメニューといったユーザーインタフェース(UI)は、多くのウェブサイトで利用されており頻繁に見かけます。どこでも見かけることから「簡単に作成できる」と思われがちですが、意外と実装が難しいUIです。たとえば、エンジニアでなくとも、以下のような現象に気付いたことはないでしょうか?

▼裏側がスクロールできてしまう例

▼裏側がキーボード操作できてしまう例

これらを解決するためには、手軽な正攻法はなく、複雑なJavaScriptの制御が必要になります。本記事では、ダイアログやハンバーガーメニュー等のモーダル系のUIに存在する気付きづらい問題点と、解決方法を紹介します。ダイアログとハンバーガーメニューはそれぞれ役割の異なるUIですが、画面全域を覆うUIという意味において同種の問題が発生するので、本記事ではあわせて説明します。

よくありがちなHTMLの実装を紹介

問題点を示すために、シンプルなHTMLの作例を用意しました。ダイアログとハンバーガーメニューのデモです。それぞれのボタンをクリックすると画面全域を覆うUIが出現し、[閉じる]ボタンをクリックすることで閉じられます。

▼モーダルダイアログの表示

▼ハンバーガーメニューの表示

CSSとJSの制御として、要素に.is-showというCSSクラスを付与することで表示させています。

▼モーダルダイアログのコード例

// DOM要素の参照を取得
const modalOpenButton = document.querySelector('#js-modal-button');
const modalCloseButton = document.querySelector('#js-modal-close');
const modalOverlay = document.querySelector('#js-modal-overlay');
const modalContent = document.querySelector('#js-modal');

// 開くボタンがクリックされたらモーダルを開く
modalOpenButton.addEventListener('click', () => {
  modalContent.classList.add('is-show');
  document.body.classList.add('is-scrollLock');
});
// 閉じるボタンまたはモーダルの背景がクリックされたらモーダルを閉じる
const closableElement = [modalCloseButton, modalOverlay];
closableElement.forEach((element) => {
  element.addEventListener('click', () => {
    modalContent.classList.remove('is-show');
    document.body.classList.remove('is-scrollLock');
  });
});

モーダルの表示中は<body>要素にスタイルoverflow: hiddenを設定し、マウスホイールやタッチ操作によるスクロールを無効化しています。

一見、問題なく動作しているように見えますが、以下の2つの課題があります。先ほどの作例をブラウザで開きながら問題点を確認していきましょう。