DACエンジニアブログ:アドテクゑびす界

DACのエンジニアやマーケター、アナリストが執筆するアドテクの技術系ブログです。

Bootstrapのモーダル機能で多重表示する際に解決しなければならない2つの問題

はじめに

みなさんこんにちは、プロダクト開発本部の亀梨です。 普段はXmediaOneというメディアプランニング・広告運用管理・トラッキング・マーケティング分析を行う 統合プラットフォームの開発・保守を担当しています。

エンジニアの皆さん、デザインってどうしてます?

わたくしはプライベートでとあるWebサイト・Webシステムの開発を行っているのですが、 全体のデザイン・見栄えに関わる部分についてはサイトの性質上(あまり凝ったデザインを作る必要が無い)及びコストの都合上(実装時間の短縮化)、 Bootstrap3を使用してUIを実装しています。

Bootstrapを使うメリット

Bootstrapを使用すると、

  • 一定のデザイン品質を担保できる
  • モバイルファースト(レスポンシブデザインに対応しPC, タブレット, スマートフォンのマルチデバイス表示に対応)
  • 高速開発(デザインの実装を容易にすることでエンジニアは機能開発に多くの時間を確保することができる)

という利点があるため採用しています。

ただし、Bootstrapは打ち出の小槌ではない

上記の理由はあるものの、便利な半面、要求に対して全て答えてくれるというものではなく、 実装したいUIと微妙に仕様・挙動が違う箇所が出てきた場合は適宜調整が必要となります。 今回はわたくしがBootstrapを利用していて実際に遭遇した諸問題について紹介したいと思います。

登録画面をBootstrap3のモーダル機能で実装した時に遭遇した問題の話

Webサイト・システムでの問い合わせフォームや何らかの登録機能を実装する際、 多くの場合は入力画面→確認画面→登録完了画面というふうに複数の画面を遷移する必要があるかと思います。

こういった画面の場合、1ページごとに画面をサーバーにリクエストしてページを取得して表示する遷移をするのは時間がかかり不便なことから 現在はページ遷移を伴わずに、ページ上にウィンドウをオーバーレイ表示させる「モーダルウィンドウ」が主流となっているかと思います。

モーダルウィンドウの例はこちら

Bootstrapを用いるとこのモーダルウィンドウを簡単に実装することができるのですが、 先ほどのケースのように入力画面→確認画面...といったようにページ上に複数のモーダルウィンドウを重ねて表示する場合には 2つの問題が生じることがわかりました。

問題1. 背景(オーバーレイ)とモーダルウィンドウが順に重なってくれない

モーダルウィンドウは元のページとの間にオーバーレイと呼ばれる黒半透明の背景を表示しますが、 2つのモーダルを重ねるときは元のページ→オーバーレイ1→モーダル画面1→オーバーレイ2→モーダル画面2と表示してほしいのに Bootstrap3のモーダルをそのまま実装すると、元のページ→オーバーレイ1→オーバーレイ2→モーダル画面1→モーダル画面2となってしまいます。

こちらを参照

そのため、JavaScriptでこのオーバーレイとモーダルが順に重なるよう調整して上げる必要があります。

(function () {
  // Bootstrap3:modal不具合対応
    // 1. モーダル多層表示時に、オーバレイ->モーダル->オーバーレイ->モーダル->オーバーレイ...と交互に重なるようCSS:z-index値調整
  document.getElementById('registArea').addEventListener('click', function(event) {
    if (event.target.getAttribute('data-toggle') == 'modal') {
      window.setTimeout(function () { // オーバーレイ要素が</body>直前に追加されるのを待つ
        // Bootstrap3モーダル要素CSS:z-index初期値を設定
        var defaultZindexValOfOverlay = 1040;
        var defaultZindexValOfModal = 1050;

        // イベント編集に関わるモーダル要素を取得
        var overlay     = document.querySelectorAll('.modal-backdrop');       // オーバーレイ要素は増減する
        var modalWindow = document.querySelectorAll('#registArea .modal'); // モーダル画面要素は増減しない

        if (overlay.length >= 2) { // 多層表示時に限り各モーダル要素のCSS:z-index値を調整
          for (var i = 0; i < modalWindow.length; i++) {
            var addValue = i == 0 ? 0 : 10 * (1 + i);

            // 要素の増減有無に応じたz-indexの設定をする必要がある
            if (i < overlay.length) { overlay[i].style.zIndex = defaultZindexValOfOverlay + addValue; }
            if (modalWindow[i].classList.contains('in')) { modalWindow[i].style.zIndex = defaultZindexValOfModal + addValue; }
          }
        }
      }, 200); // モーダル要素が表示(classに in が追加される)されるのをこのミリ秒まで待つ必要がある
    }
  }, false);
})();

オーバーレイとモーダルの重なりはCSSのz-index値によって設定されますが、 この値を上記のように各要素に順番に設定してあげることで解決します。

解決した画面はこちらを参照

はい、ということで1つ目解決です。

問題2. 確認モーダル閉じた際に入力モーダルがスクロール不可になる

次の問題は、入力モーダル画面→確認モーダル画面と遷移した後入力内容を修正するために確認モーダル画面を閉じて入力モーダル画面に戻ると スクロールができない状態になってします。

こちらを参照

こちらは確認モーダル画面を閉じる際に、bodyに設定しているスクロールに必要なクラスを削除してしまうことが原因のため、 確認モーダル画面を閉じる際に再度クラスを付与して上げる必要があります。

  // 2. 確認モーダル閉じた際に入力モーダルがスクロール不可になる問題を解決
  $('#confirmModal').on('hidden.bs.modal', function () {
    $('body').addClass('modal-open');
  });

解決した画面はこちらを参照

以上です。

ということで、現時点で見つかっている問題は以上で、それ以外は快適に使用しています。 日本語のリファレンスも充実していますので参照あれ。

Bootstrapは便利に使いながらも、カスタマイズしたい場合は適宜調整しながら開発を進めていければと思います。 それではまた~。