Модальные окна

Модальные окна используются практически во всех сайтах, мы используем модальные окна от twitter bootstrap (они почти идеальны), но у него есть несколько недостатков которые мы исправим:

  • отсутствие выравнивания вертикально по центру страницы,
  • смещение контента сайта из-за исчезающей полосы прокрутки страницы.

В итоге получился плагин, а ниже описание процесса его создания.

Выравнивание по центру

При неизменной высоте модального окна, можно ограничится CSS: задав position: absolute, смещением на 50% и отрицательный margin-top на половину высоты окна.

Минусы:

  • Размеры окна должны быть известны заранее, что не всегда возможно.
  • Если модальное окно больше высоты окна браузера, то отступ от верхней границы будет излишне большим.

Обходим минусы с помощью JS и без вмешательств в CSS.

В начале проверим, умещается ли модальное окно в браузере, сравнив их размеры по высоте. Если модальное меньше, то вычитаем его высоту из высоты окна браузера и делим на 2. Полученное значение превращает в margin-top, который сместит модальное в центр по вертикали.

Если модальное больше высоты экрана, то стираем добавленный margin-top (если он был установлен ранее), чтобы вступили в силу свойства, установленные в CSS.
Попутно мы столкнулись с проблемой: если вычислять размеры модального при событии show.bs.modal, то результаты будут неверные: так как блок скрытый, его размеры равны нулю. Если делать тоже самое при событии shown.bs.modal, то функция выполнится поздно: окно в начале появится вверху экрана, а затем резко переместится в центр.

Чтобы обойти проблему, мы добавили в начале функции display: block, для родительского элеменита модального окна, чтобы он стал видимым до вычисления его размеров.

Компенсация сайдбара

На сайте Bootstrap, при открытии примера модального окна, пользователи Windows могут заметить смещение страницы на несколько пикселей вправо. Таже проблема есть на Behance при просмотре работы, но из-за тёмного фон это не бросается в глаза.

 

behance

До и после открытия работы

Это происходит из-за применяемого к body свойства overflow: hidden, скрывающего полосу прокрутки. Если этого не сделать, то открыв модальное окно, останется возможность прокручивать страницу дальше, что несколько странно.

 

ma-ma

Пример на ma-ma.ru в форме «Задать вопрос».

 

Быстрое решение: компенсировать потерю добавлением к body padding-right на ширину полосы прокрутки. Однако, в Windows её ширина равна 17px, в OSX — 15px, но чаще просто отключена и не влияет на ширину вьюпорта.

Думаем. Может магия?

$(window) .width ();
window.innerWidth;

Возьмём ширину браузера и вьюпорта. Разница между — ширина панели скролла. Посмотреть на получаемые значение со скроллбаром и без можно на нашей игровой площадке: http://nopreset.net/playground

Однако, innerWidth не работает в Internet Explorer и не всё так просто.

Думаем дальше. Попутно смотрим на twitter.com, где используется тоже модальное, но проблемы со смещением нет. Пробуем любовно перенести решение и немного упростить.

Для этого при инициализации документа создим div, с абсолютным позиционирование (чтобы не мешался), фиксированными размерами и overflow: scroll. Внутрь него поместим элемент с большей высотой, чем у родителя, чтобы появилась полоса прокрутки. Теперь сравним вычтем из родительского элемента размеры дочернего и получим ширину палени прокрутки.

Стили для создаваемых элементов:

Разница в том, что twitter создаёт в head стили для группы элементов, к которым добавляется padding с компенсацией скроллбара.

Финальный скрипт, вместе с выравниванием:

Хэппиэнд

Скорее всего, наша реализация не идеальная, по этому мы будем рады советам и замечаниям.

  • A11oW

    А где же пример реализации?

    • Сайты с такой модалкой пока в процессе и не увидели свет )

      • desert013

        Вот замудрили

  • Сделал так: body {padding-right:0 !important;}

    При выпадении модального окна body присваивается padding-right:16px, просто обнулил

    bootstrap-3.3.4

  • Sergey Volvich

    все решается правильным размещением модального кода, абитура блин! Блок modal — внутри блока container