Выравнивание модального окна по центру

Мой первый пост.
Центрирование блока относительно другого блока относительно часто-попадающаяся задача, это очередное ее решение. Для меня оно стало самым универсальным и покрывающим все кейсы, с которыми я когда-либо сталкивался.

Формулировка
Центрировать модальное окно по горизонтали и вертикали.

Условия
  • Габариты модалки могут быть указаны в любых единицах измерения. Или же могут быть не указаны вовсе.
  • Отзывчивость. При ресайзе окна, модалка подстраивается под текущий размер.
  • Если модалка сверстана так, что у нее еcть min-height/min-width, то при ресайзе окна до меньших размеров должен появляться скролл.
  • IE 9+.
  • Позиционирование должны быть реализовано на CSS, без применения JS.

Как это делалось раньше?
Если габариты модального окна заданы, то все просто:

<div class="fixed-overlay">
    <div class="modal">
        <div class="modal_container">    
        </div>
    </div>
</div>

* {
    box-sizing: border-box;
}

.fixed-overlay {
    position: fixed;
    overflow: auto;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0,0,0,0.5);
}

.modal {
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -100px;
    margin-top: -75px;
}

.modal_container {
    background-color: #fff;
    width: 200px;
    height: 150px;
}

Работает прекрасно, нареканий нет. Но нам такой способ не подходит, ибо мы не хотим зависеть от размеров модального окна.

Первый способ, который удовлетворяет всем перечисленным требованиям я увидел у Jabher. Речь идет об использовании свойства transform и его значения translate вместо margin. Вот как это работает:

.modal {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

.modal_container {
    padding: 20px;
    background-color: #fff;
    color: #000;
}

Магия! Теперь мы не зависим от габаритов .modal_container. Все потому что translate отталкивается от размеров элемента, к которому применятся свойство. Напомню, что процентные значения свойства margin будут вычисляться относительно размеров родителя, что нам явно не подходит.

Теперь о минусах. Используя свойство transform, мы столкнемся с субпиксельным рендерингом. Проще говоря, контент при ресайзе начнет замыливаться, результат выглядит скверно, особенно это заметно при рендере текста и тонких линий, вроде однопиксельных бордеров. Я не смог найти решений этой проблемы, если у вас они есть — пожалуйста, поделитесь в комментариях.

Тадаам


Не так давно я нашел изумительный по своей простоте способ. На помощь спешат инлайн блоки. Их легко центрировать по-горизонтали, навесив text-align: center на родителя. Немного подумав, я вспомнил про замечательное свойство vertical-align. Как оно работает? Если этому свойству задать значение middle, то элементы с этим свойством будут центрироваться по-вертикали друг относительно друга. А это значит, что помимо элемента .modal, в .fixed-overlay должен быть еще кто-то, кто поможет нашей модалке встать по-центру окна. Высота этого кого-то должна быть равна высоте .fixed-overlay. На роль этого помощника напрашивается псевдоэлемент:

<div class="fixed-overlay fixed-overlay__modal">
    <div class="modal">
        <div class="modal_container">    
        </div>
    </div>
</div>

.fixed-overlay__modal {
    text-align: center;
    white-space: nowrap;
}

.fixed-overlay__modal::after {
    display: inline-block;
    vertical-align: middle;
    width: 0;
    height: 100%;
    content: '';
}

.modal {
    display: inline-block;
    vertical-align: middle;
}

.modal_container {
    margin: 50px;
    padding: 20px;
    min-width: 200px;
    text-align: left;
    white-space: normal;
    background-color: #fff;    
    color: #000;
}

Пример: jsfiddle.net/yvp0jdnw

Буду рад любой критике, это мой первый опыт написания статей.
Поделиться публикацией
Похожие публикации
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 28
  • +2
    Как насчет блокировки вертикального скролла основной страницы?
    • 0
      Возможно, я вас неправильно понял, но это обычно в обработчике, который окно открывает и закрывает, делается. Или все же нет?
      • +2
        Этот обработчик будет всего лишь ставить/снимать HTML-класс на, скажем, ``.

        Всё остальное должно быть реализовано на CSS, являющемся частью вашего компонента «модалка» (бр-р-р, ну и словечко).
      • +2
        Обычно в таких случаях на body вешают класс типа body__no-scroll и дают ему overflow: hidden.
      • 0
        Здорово, классный способ! А как у него с поддержкой браузерами?
        • 0
          PaulZi ответил. Если дополнить хаками для древних IE, то до 6-й версии можно обеспечить совместимость.
        • 0
          Чем не подошел flexbox?
          • +2
            Flexbox — IE10+, я полагаю. Приведённое же решение с доработками даже в IE6 сработает.

            А вообще автор переизобрёл давно известный метод. Ещё со строчными блоками надо помнить о пробелах. Так, в примере правый отступ на 5 пикселей (возможны погрешности) больше левого.
            • 0
              Да, через час после публикации нашел статью habrahabr.ru/post/238449/
              • 0
                Как раз дополнил статью вариантом с использованием flexbox.
              • 0
                По поводу отступа — я решаю проблему, минифицируя шаблон, забыл упомянуть об этом в статье
            • +5
              Этот способ очень бородатый и работает даже с ie6 с хаками display:inline; zoom: 1; (может и раньше).
              • +1
                Вам привет из 2012-го. Советую внимательнее пользоваться поиском.
                • 0
                  Где-то на хабре видел, до сих пор пользуюсь.

                  .modal{
                    position: absolute;
                    top: 0;
                    bottom: 0;
                    right: 0;
                    left: 0;
                    margin: auto;
                  }
                  


                  Дешево и сердито.
                  • +2
                    Как и метод в начале поста работает только, если у .modal есть размер. Иначе оно просто растянется по всей области.
                    • –3
                      А у модального окна в любом случае должен быть размер.

                      Изначально модальные окна используются в диалогах и сообщениях. Растягивающиеся модальные окна, IMHO, делать не имеет смысла. Если окно должно уметь менять размер, возникает два вопроса:

                      — Позиционирование. Вряд ли будет удобно работать с модальным окном, прибитым к краю экрана
                      — Необходимость использования JavaScript или CSS3 для реализации ресайза. И если первое будет работать с IE, то второе не будет работать точно (до «десятки»).

                      А теперь просто задайте вопрос: зачем громоздить горы кода чисто для окошка с сообщением или простой формочки? Так что согласен с предыдущим комментатором. Кстати, я в своей практике использовал отрицательный margin. А тут всё ещё проще.
                      • +2
                        Так штука не просто в каком-то размере, а явно заданном в CSS. Иначе, если, скажем, не указана высота, то оно будет на всю высоту экрана. А если задана, может вылезти длинный текст или будут большие пустоты. А тексты на разных языках могут иметь очень разные длины. Если хачить с замером высоты через JS, то это уже не чистое решение на CSS.
                        • 0
                          В формочке добавиться одно новое поле — лезть в код и изменять высоту.
                          В формочке в зависимости о выбранного элемента появляется ещё одно поле — кроме отображения поля ещё и окну менять высоту.
                          В модальном окне изменился текст сообщения — лезть в код и изменять высоту.
                          Формочка не влазит на экран по высоте экрана в модальном окне — высчитывать высоту контента окна и добавлять скроллбар так как расширения монитора у всех разное.
                          Поступило задание адаптировать сайт для сматфонов / таблеток — лезть в код и переделывать все окна.

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

                          Решения для демонстрации за 5 минут:
                          IE10+ jsfiddle.net/serdidg/zyzvsk9d/9/
                          IE9 + jsfiddle.net/serdidg/zyzvsk9d/10/
                    • НЛО прилетело и опубликовало эту надпись здесь
                      • 0
                        Есть еще один отличный способ, при условии, что вы поддерживаете только ie9+

                        .modal-wrapper
                        position: fixed
                        top: 0
                        left: 0
                        right: 0
                        bottom: 0
                        display: flex
                        // далее выравниваем любое окно внутри по центру контейнера
                        justify-content: center
                        align-items: center

                        .modal-window
                        // простой див или display: block
                        // зачастую даже не нужно писать никакие стили для позиционирования окна

                        готов порассуждать на эту тему, мы используем в нескольких проектах и довольны результатом.
                      • –1
                        Не нравятся проверенные методы? Хотете больше багов? К успеху идёте.
                        Вот вы использовали translate(50%).
                        И попали на dropshado.ws/post/12243351506/subpixel-positioning-with-css-transforms-and-type в хроме.
                        И что дальше делать?
                        • +1
                          Если бы вы дочитали до конца, то вероятно, вопросов бы не было. По-моему, автор предложил очень таки годное решение.
                          • 0
                            Решение работает до ие8 включительно и действительно является проверенным, сам данным подходом пользовался очень долгое время.
                            Как вариант — простейшая имплементация модального окна, гибкая альтернатива с библиотекой анимации Гринсок:
                            jsfiddle.net/y6snnwua/
                          • –1
                            Это не худшее на что можно попасть. Если в таком центрированном блоке будут некоторые элементы, позицию которых просчитывает js, будут не верные координаты. Например если нужно реализовать внутри drag and drop, или всплывающие тултипы, которые вставляются в DOM вне блока.
                            • +1
                              Для меня это худшее.
                              Некоторые программисты забывают для чего они делают сайты.
                              Сайты делаются для пользователей. Не для того, чтобы кодить, или было удобно кодить, или чтобы использовать новые фичи, или чтобы он быстро работал, это всё второстепенно.

                              Неважно какой попап, тултипы, дизайн, вёрстка, node.js с ангулароми и другими свистелками и перделками, если при это у юзера расблюрен текст.

                              Это из наболевшего.
                              • 0
                                То есть вы за дедовские методы или что?
                                Я юзал трансформации для позиционирования до тех пор, пока не увидел, что они блюрят содержимое блока. Мне кажется, что в статье об это написано максимально прозрачно.
                                Некоторые программисты забывают для чего они делают сайты.

                                Технологии развиваются, появляются новые стандарты. Если есть новое решение проблемы, почему бы его не опробовать? Я с вами полностью согласен в том плане, что конечный результат — это качественно выполненная работа, которой будет приятно пользоваться конечному потребителю. Но это не значит, что мы должны юзать только старые и проверенные методы.

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое