Центрирование по вертикали

Оцените материал
(0 голосов)

Проблема

44 года назад мы высадили человека на Луне, но до сих пор не можем центрировать объекты по вертикали в CSS.

Центрировать элементы по горизонтали в CSS невероятно просто: если это строковый элемент, то мы применяем  text-align: center к его предку, а если это блочный элемент, то мы применяем  margin: auto к нему самому. Но одной мысли о том, чтобы центрировать элемент по вертикали, достаточно, чтобы по спине пробежали холодные мурашки. С годами центрирование по вертикали превратилось в «святой грааль» CSS и «семейную шутку» разработчиков внешних интерфейсов. И это понятно, ведь здесь налицо все необходимые причины:

  • это то, что требуется разработчикам очень часто;
  • это звучит чрезвычайно просто в теории;

на практике это было невероятно сложно, особенно для элементов с переменными габаритными размерами. Разработчики внешних интерфейсов уже исчерпали свою фантазию в попытках придумать новые выходы из этого тупика, и большинство придуманных ими решений ужасающе грязные. В этом секрете мы исследуем некоторые из лучших современных техник, позволяющих реализовать вертикальное центрирование в любых ситуациях. Обратите внимание, что несколько существующих по-
пулярных техник здесь не упоминаются по разным причинам:

  • метод с табличным макетом (использующий режимы отображения таблиц) не включен, так как требует нескольких лишних элементов HTML;
  • метод со строковым блоком не включен, так как, на мой вкус, он слишкомгрязный.

Если не указано иное, мы будем использовать следующую разметку прямо внутри элемента  <body> , хотя решения, которые мы собираемся изучить, должны работать вне зависимости от выбранного вами контейнера:
HTML
<main>
<h1>Am I centered yet?</h1>
<p>Center me, please!</p>
</main>
Мы также применим несколько простейших правил CSS для оформления фона, забивки и т. п., чтобы наша отправная точка выглядела как на рисунке.


Решение с абсолютным позиционированием

Одна из ранних техник вертикального центрирования требовала фиксированных значений ширины и высоты:

main {
position: absolute;
top: 50%;
left: 50%;
margin-top: -3em; /* 6/2 = 3 */
margin-left: -9em; /* 18/2 = 9 */
width: 18em;
height: 6em;
}

По сути, здесь мы помещаем верхний левый угол элемента в центр окна просмотра (или ближайшего по расположению предка), а благодаря отрицательным значениям полей, равным половине ширины и высоты элемента, перемещаем его вверх и влево, так, чтобы центр элемента совпал с центром просмотрового окна. С помощью  calc() это решение можно сделать на два объявления проще:

main {
position: absolute;
top: calc(50% - 3em);
left: calc(50% - 9em);
width: 18em;
height: 6em;
}

Очевидно, что самая большая проблема этой техники в том, что она зависит от фиксированных габаритных размеров, тогда как нам часто требуется центрировать элементы, размеры которых определяются их содержимым. Если бы только мы могли использовать процентные значения, разрешающиеся в габаритные размеры элемента, наша проблема была бы решена. К сожалению, для большинства свойств CSS (включая  margin ) процентные значения разрешаются относительно габаритных размеров родительского элемента. Как это часто бывает с CSS, решения приходят из самых неожиданных мест.

В данном случае нам могут помочь трансформации CSS. Когда мы используем процентные значения в трансформациях  translate() , мы перемещаем элементы относительно их собственных ширины и высоты — а это в точности то, что нам нужно! Таким образом, мы можем заменить отрицательные
смещения, жестко кодирующие габаритные размеры наших элементов, трансформациями CSS, основанными на процентных значениях. Это позволит нам избавиться от жестко закодированных значений:

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


Результат вы можете видеть на рисунке, но там нет ничего удивительного: контейнер идеально выровнен по центру, как и ожидалось. Разумеется, ни одна техника не идеальна, и у этой также есть несколько недостатков:
‰

во многих ситуациях абсолютное позиционирование применять невозможно, так как оно способнорадикально изменить весь макет целиком;
‰если центрируемый элемент выше своего просмотрового окна, то он обрезается сверху.

Справиться с этим можно несколькими способами, но все они невероятно грязные; ‰ в некоторых браузерах это может привести к тому, что элементы выглядят слегка нечеткими, так как позиционируются с точностью до половины пиксела. Это можно исправить, применив  transform-style: preserve-3d, (о трансформациях в css читайте здесь)  но это грязный трюк, и невозможно гарантировать, что он продолжит работать в будущем.

ПОПРОБУЙТЕ САМИ!

http://play.csssecrets.io/vertical-centering-vh

Решение с единицами измерения просмотрового окна

Даже если бы мы хотели избежать абсолютного позиционирования, мы все так же можем использовать трюк с трансформацией  translate() , для того чтобы перемещать элемент на половину его ширины и высоты. Но как в этом случае задать изначальное смещение на 50% от верхнего левого угла контейнера, не используя  left и  top ? Первой мыслью могло бы быть использование процентных значений со свойством  margin , например так:

main {
width: 18em;
padding: 1em 1.5em;
margin: 50% auto 0;
transform: translateY(-50%);
}

Однако, как вы видите на рисунке, это дает несколько странный результат.


Причина в том, что процентные значения в свойстве  margin вычисляются относительно ширины его родительского элемента. Да, даже проценты для margin-top и  margin-bottom!

К счастью, если мы пытаемся центрировать элемент относительно окна просмотра, у нас еще есть надежда. В спецификации CSS Values and Units Level 3 определяется семейство новых единиц измерения — значений, завязанных на размер просмотрового окна: ‰ vw относится к ширине просмотрового окна.
Вопреки ожиданиям,  1vw обозначает 1% ширины просмотрового окна, а не 100%;
‰ аналогично  vw ,  1vh представляет 1% высоты просмотрового окна;
‰ 1vmin эквивалентно  1vw , если ширина просмотрового окна меньше его высоты;

 в противном случае это значение эквивалентно  1vh;
‰ 1vmax эквивалентно  1vw , если ширина просмотрового окна больше его высоты; в противном случае это значение эквивалентно  1vh.
В нашей ситуации для задания ширины полей нам требуется  vh:
main {
width: 18em;
padding: 1em 1.5em;
margin: 50vh auto 0;
transform: translateY(-50%);
}
Как подтверждает рисунок , это решение работаетбезупречно.

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

ПОПРОБУЙТЕ САМИ!

http://play.csssecrets.io/vertical-centering-vh

Решение с гибким полем

Это, несомненно, наилучшее из доступных решений, так как гибкое поле (спецификация Flexbox,) о флексбоксах я писал здесь  разработано специально для помощи в подобных ситуациях. Единственная причина, почему мы все еще рассматриваем другие решения, заключается в том, что прочие методы лучше поддерживаются браузерами, хотя и у гибкого поля достаточно хорошая поддержка современными браузерами. Все, что нам требуется, — это два объявления:  display: flex на родительском элементе относительно центрируемого (в нашем примере это элемент  <body> ) и уже знакомый нам  margin: auto на дочернем, который мы центрируем (в нашем примере это  <main> ):
body {
display: flex;
min-height: 100vh;
margin: 0;
}
main {
margin: auto;
}

Обратите внимание, что при использовании гибкого поля  margin: auto выравнивает элемент по центру не только по горизонтали, но и по вертикали. Также обратите внимание, что нам даже не пришлось задавать ширину (хотя при желании мы могли бы это сделать): присвоенная ширина эквивалентна  max-content. (Помните ключевые слова для определения размера изнутри, о которых я рассказывал в секрете «Определение размера изнутри»?).

Если гибкое поле не поддерживается, то результат выглядит в точности так же, как наша отправная точка на  (если задано конкретное значение ширины), что вполне допустимо, даже если желаемого вертикального центрирования мы не добились. Еще одно преимущество гибкого поля заключается в том, что с помощью него можно вертикально центрировать анонимные контейнеры (то есть текст безо всякой обертки). Например, если бы мы использовали такую разметку:
HTML
<main>Center me, please!</main>
то могли бы задать фиксированные значения для main и выровнять текст по центру прямо внутри этого тега, используя свойства  align-items и  justify-content, которые были добавлены в спецификации
Flexbox:

main {
display: flex;
align-items: center;
justify-content: center;
width: 18em;
height: 10em;
}


ПОПРОБУЙТЕ САМИ!
http://play.csssecrets.io/vertical-centering

БУДУЩЕЕ.  ВЫРОВНЯТЬ ВСЕ!

Как уже запланировано в спецификации CSS Box Alignment Level 3  в будущем нам не придется использовать другой режим разметки для обеспечения возможности вертикального центрирования. Мы сможем делать это, используя простую строку кода:
align-self: center;
Она будет работать независимо от того, какие другие свойства определены для элемента. Кажется, что это слишком хорошо, для того чтобы быть правдой, но совсем скоро вы сможете использовать это решение в любимом

Видеоурок: как выровнять элемент по вертикали

Десерт на сегодня - видео, сделанное фанатами по мотивам игры "Far Cry" в реальной жизни:

Прочитано 147 раз Последнее изменение Суббота, 10 июня 2017 12:43
Другие материалы в этой категории:
Понравилась запись? Подпишитесь на обновления по почте:

Оставить комментарий

Убедитесь, что вы вводите (*) необходимую информацию, где нужно
HTML-коды запрещены

Поиск по сайту

Google+