- PVSM.RU - https://www.pvsm.ru -
Я думаю, многие из вас, кому приходилось заниматься версткой, сталкивались с необходимостью выравнивать элементы по вертикали и знают, какие сложности возникают при выравнивании элемента по центру.
Да, для вертикального выравнивания в CSS есть специальное свойство vertical-align
с множеством значений [1]. Однако на практике оно работает совсем не так, как ожидается. Давайте попробуем в этом разобраться.
Сравним следующие подходы. Выравнивание с помощью:
line-height
, margin
,transform
,flexbox
.В качестве иллюстрации рассмотрим следующий пример.
Есть два элемента div
, при этом один из них вложен в другой. Дадим им соответствующие классы − outer
и inner
.
<div class=”outer”>
<div class=”inner”></div>
</div>
Задача состоит в том, чтобы выровнять внутренний элемент по центру внешнего элемента.
Для простоты рассмотрим случай, когда размеры внешнего и внутреннего блока известны. Добавим внутреннему элементу правило display: inline-block
, а внешнему − text-align: center
и vertical-align: middle
.
Нпомню, что выравнивание применяется только к элементам, которые имеют режим отображения inline
или inline-block
.
Зададим блокам размеры, а также фоновые цветы, чтобы видеть их границы.
.outer {
width: 200px;
height: 200px;
text-align: center;
vertical-align: middle;
background-color: #ffc;
}
.inner {
display: inline-block;
width: 100px;
height: 100px;
background-color: #fcc;
}
После применения стилей мы увидим, что внутренний блок выровнялся по горизонтали, а по вертикали нет:
http://jsfiddle.net/c1bgfffq/ [2]
Почему так произошло? Дело в том, что свойство vertical-align
влияет на выравнивание самого элемента, а не его содержимого (кроме случаев, когда оно применяется к ячейкам таблицы). Поэтому применение данного свойства к внешнему элементу ничего не дало. Более того, применение этого свойства к внутреннему элементу также ничего не даст, поскольку строчные блоки (inline-block
) выравниваются по вертикали относительно соседних блоков, а в нашем случае у нас один строчный блок.
Для решения данной проблемы существует несколько техник. Ниже подробнее рассмотрим каждую из них.
Первое приходящее на ум решение − заменить внешний блок таблицей из одной ячейки. В этом случае выравнивание будет применяться к содержимому ячейки, то есть к внутреннему блоку.
<table class="outer-wrapper">
<td class="outer">
<div class="inner"></div>
</td>
</table>
http://jsfiddle.net/c1bgfffq/1/ [3]
Очевидный минус данного решения – с точки зрения семантики неправильно применять таблицы для выравнивания. Второй минус в том, что для создания таблицы требуется добавить еще один элемент вокруг внешнего блока.
Первый минус можно частично убрать, заменив теги table
и td
на div
и задав табличный режим отображения в CSS.
<div class="outer-wrapper">
<div class="outer">
<div class="inner"></div>
</div>
</div>
.outer-wrapper {
display: table;
}
.outer {
display: table-cell;
}
Тем не менее внешний блок все равно останется таблицей со всеми вытекающими из этого последствиями.
Если высоты внутреннего и внешнего блока известны, то выравнивание можно задать с помощью вертикальных отступов у внутреннего блока, используя формулу: (Houter – Hinner) / 2.
.outer {
height: 200px;
}
.inner {
height: 100px;
margin: 50px 0;
}
http://jsfiddle.net/c1bgfffq/6/ [4]
Минус решения — оно применимо лишь в ограниченном числе случаев, когда известны высоты обоих блоков.
Если известно, что внутренний блок должен занимать не более одной строки текста, то можно воспользоваться свойством line-height
и задать его равным высоте внешнего блока. Поскольку контент внутреннего блока не должен переноситься на вторую строку, рекомендуется также добавить правила white-space: nowrap
и overflow: hidden
.
.outer {
height: 200px;
line-height: 200px;
}
.inner {
white-space: nowrap;
overflow: hidden;
}
http://jsfiddle.net/c1bgfffq/12/ [5]
Также данную технику можно применять и для выравнивания многострочного текста, если для внутреннего блока переопределить значение line-height
, а также добавить правила display: inline-block
и vertical-align: middle
.
.outer {
height: 200px;
line-height: 200px;
}
.inner {
line-height: normal;
display: inline-block;
vertical-align: middle;
}
http://jsfiddle.net/c1bgfffq/15/ [6]
Минус данного способа заключается в том, что должна быть известна высота внешнего блока.
Данный способ можно применять, когда высота внешнего блока неизвестна, но известна высота внутреннего.
Для этого нужно:
top: 0
и bottom: 0
, в результате чего он растянется на всю высоту внешнего блока;auto
для вертикальных отступов внутреннего блока..outer {
position: relative;
}
.inner {
height: 100px;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
}
http://jsfiddle.net/c1bgfffq/4/ [7]
Суть этой техники заключается в том, что задание высоты для растянутого и абсолютно спозиционированного блока заставляет браузер вычислять вертикальные отступы в равном соотношении, если их значение установлено в auto
.
http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-height [8]
Минус данного способа — должна быть известна высота внутреннего блока.
Этот способ получил широкую известность и применяется очень часто. Как и предыдущий, он применяется, когда высота внешнего блока неизвестна, но известна высота внутреннего.
Нужно задать внешнему блоку относительное позиционирование, а внутреннему − абсолютное. Затем необходимо сдвинуть внутренний блок вниз на половину высоты внешнего блока top: 50%
и поднять вверх на половину собственной высоты margin-top
: -Hinner / 2.
.outer {
position: relative;
}
.inner {
height: 100px;
position: absolute;
top: 50%;
margin-top: -50px;
}
http://jsfiddle.net/c1bgfffq/13/ [9]
Минус данного способа — должна быть известна высота внутреннего блока.
Данный способ похож на предыдущий, но он может быть применен, когда высота внутреннего блока неизвестна. В этом случае вместо задания отрицательного отступа в пикселях можно воспользоваться свойством transform
и поднять внутренний блок вверх с помощью функции translateY
и значения -50%
.
.outer {
position: relative;
}
.inner {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
http://jsfiddle.net/c1bgfffq/9/ [10]
Почему в предыдущем способе нельзя было задать значение в процентах? Так как процентные значения свойства margin
вычисляются относительно родительского элемента, значение в 50% равнялось бы половине высоты внешнего блока, а нам нужно было поднять внутренний блок на половину его собственной высоты. Для этого как раз подходит свойство transform
.
Минус данного способа в ограниченной поддержке [11] свойства transform
старыми версиями браузера IE.
Это наиболее универсальный способ, который может применяться, когда неизвестны высоты обоих блоков.
Суть способа в добавлении внутри внешнего блока строчного блока inline-block
высотой в 100%
и задания ему вертикального выравнивания. В этом случае высота добавленного блока будет равна высоте внешнего блока. Внутренний блок выровняется по вертикали относительно добавленного, а значит, и внешнего блока.
Чтобы не нарушать семантику, строчный блок рекомендуется добавить с помощью псевдоэлемента before
или after
.
.outer:before {
display: inline-block;
height: 100%;
vertical-align: middle;
content: "";
}
.inner {
display: inline-block;
vertical-align: middle;
}
http://jsfiddle.net/c1bgfffq/10/ [12]
Минус данного способа — он не может быть применен, если внутренний блок имеет абсолютное позиционирование.
Самый современный способ вертикального выравнивания это использовать Flexible Box Layout [13] (в народе известен как Flexbox
). Данный модуль позволяет гибко управлять позиционированием элементов на странице, располагая их практически как угодно. Выравнивание по центру для Flexbox − очень простая задача.
Внешнему блоку необходимо задать display: flex
, а внутреннему − margin: auto
. И это все! Красиво, правда?
.outer {
display: flex;
width: 200px;
height: 200px;
}
.inner {
width: 100px;
margin: auto;
}
http://jsfiddle.net/c1bgfffq/14/ [14]
Минус данного способа − Flexbox поддерживается [15] только современными браузерами.
Нужно исходить из постановки задачи:
line-height
. margin-top
. transform
. Flexbox
.Автор: NetСracker
Источник [16]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/html/112590
Ссылки в тексте:
[1] с множеством значений: http://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align
[2] http://jsfiddle.net/c1bgfffq/: http://jsfiddle.net/c1bgfffq/
[3] http://jsfiddle.net/c1bgfffq/1/: http://jsfiddle.net/c1bgfffq/1/
[4] http://jsfiddle.net/c1bgfffq/6/: http://jsfiddle.net/c1bgfffq/6/
[5] http://jsfiddle.net/c1bgfffq/12/: http://jsfiddle.net/c1bgfffq/12/
[6] http://jsfiddle.net/c1bgfffq/15/: http://jsfiddle.net/c1bgfffq/15/
[7] http://jsfiddle.net/c1bgfffq/4/: http://jsfiddle.net/c1bgfffq/4/
[8] http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-height: http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-height
[9] http://jsfiddle.net/c1bgfffq/13/: http://jsfiddle.net/c1bgfffq/13/
[10] http://jsfiddle.net/c1bgfffq/9/: http://jsfiddle.net/c1bgfffq/9/
[11] ограниченной поддержке: http://caniuse.com/#feat=transforms2d
[12] http://jsfiddle.net/c1bgfffq/10/: http://jsfiddle.net/c1bgfffq/10/
[13] Flexible Box Layout: http://www.w3.org/TR/css3-flexbox/
[14] http://jsfiddle.net/c1bgfffq/14/: http://jsfiddle.net/c1bgfffq/14/
[15] поддерживается: http://caniuse.com/#feat=flexbox
[16] Источник: https://habrahabr.ru/post/277433/
Нажмите здесь для печати.