bootstrapのモーダルを複数開いたときの問題と対処法

bootstrapのモーダルは複数重ねて開いたときにいくつか細かい問題が発生する。 versionは3系。

2つめのモーダルの背景(.modal-backdrop)より1つめのモーダルが上に表示されてしまう

標準の挙動

背景(.modal-backdrop)はmodalごとに、bodyにappendされる(z-indexは.modalのz-index設定値 - 10)

z-indexのスタック文脈について詳しい記事

z-index再入門 - z-indexの仕組み | CodeGrid

問題点

モーダルの数、重なりに関係なく .modal.modal-backgroupより上に表示される。

対処法

.modal.modal-backdropのz-indexをstackされている要素を考慮するようにhackする

$(document).on('show.bs.modal', '.modal', function () {
    var zIndex = 1040 + (10 * $('.modal:visible').length);
    $(this).css('z-index', zIndex);
    setTimeout(function() {
        $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack');
    }, 0);
});

bodyスクロールの調整

標準の挙動

body.modal-openoverflow:hidden を指定することで、モーダルが開いているときの、body要素のscrollを無効化している

問題点

.modal-open はbodyに対して設定しているので、モーダルが複数ある場合は考慮されていない。 なので、2つめのモーダルを閉じたときに body.modal-open が外れてしまい、まだ開いているモーダルがあるのにbodyのスクロールが有効になってしまう。

対処法

モーダルを閉じた後のeventで、まだ開かれているモーダルがあるときは、再度 body.modal-openをつける

$(document).on('hidden.bs.modal', '.modal', function () {
    $('.modal:visible').length && $(document.body).addClass('modal-open');
});

right paddingの調整

標準の挙動

モーダルを開く際に、bodyに縦スクロールが発生している場合、.modal.modal-dialogではない)に対してスクロールバーの幅分paddingRightを指定する。 結果モーダルはスクロールバーの幅分を除いた表示領域内でセンタリングされる。

問題点

2つめのモーダルを開く際はbodyに overflow: hidden が指定されているため(body.moda-openによって)スクロールバーが発生していない判定になり、paddingRightが設定されない。 結果、2つめのモーダルが若干右にずれる形になる。

また、1つめのモーダルで縦スクロールが発生している場合、1つめのモーダルはスクロールバー幅分を除いた領域でセンタリングされるが、2つめのモーダルはスクロール幅分を考慮しない領域でセンタリングされるので、2つめが若干右にずれる。

対処法

うーむ。。

参考

stackoverflow.com

app.codegrid.net