Почему "margin: auto" не центрирует элемент по вертикали?
Как вы можете видеть в демонстрации ниже, margin: auto;
центрирует синий div
по горизонтали, но не по вертикали. Почему бы и нет?
.box {
border: 1px solid red;
width: 100px;
height: 100px;
}
.center {
background: blue;
width: 50px;
height: 50px;
margin: auto;
}
<div class="box">
<div class="center"></div>
</div>
Ответы
Ответ 1
Как уже упоминалось, это поведение указано в разделе 10.6.2 в CSS2.1 и остается неизменным от CSS2.
Блок-блоки штабелируются вертикально сверху вниз в нормальном потоке. Кроме того, вертикальные поля могут свернуть и делать это только при определенных обстоятельствах (в вашей демонстрации граница на родительском элементе будет предотвращать любые поля на дочерний элемент от сворачивания с его собственным). Если у вас есть только один такой блок, а высота содержащего блока будет автоматически, то его верхнее и нижнее поля будут равно нулю. Но если у вас более одного блока в одном и том же потоке или даже вне потоковых ящиков, влияющих на расположение полей в потоке (в случае клиренс), как бы вы ожидали, что автоматические поля будут разрешены для тех, кто находится в потоке?
Вот почему автоматическое левое и правое поля также обнуляются для встроенных элементов (включая атомные строки) и плавает (хотя горизонтальные поля никогда не рушится). В строковых шкафах укладывается вдоль линейных блоков и плавает тоже повиноваться уникальные правила компоновки.
Абсолютно позиционированные поля - это разные истории: поскольку они никогда не знают о каких-либо других коробках в том же контексте позиционирования, что и они, авто верхнее и нижнее поля могут рассчитываться для них по отношению к их содержащим блокам, не беспокоясь о каких-либо других случаях, когда-либо мешающих.
Flexbox также представляет собой разную историю: то, что устанавливает гибкую раскладку, отличную от макета блока, состоит в том, что элементы гибкости по определению всегда знают о других элементах гибкости в одном и том же контексте форматирования гибкости, в том числе о том, что их нет. В частности, ни один из них не может перемещаться в контейнер flex, и вы не можете плавать гибкие элементы, чтобы подорвать это (хотя вы все равно можете удалить дочерний элемент от гибкой схемы полностью с абсолютное позиционирование). Маржа ведет себя по-разному с использованием гибких элементов из-за этого. См. Разделы 4.2, 9.5 и 9.6.
Ответ 2
Почему... потому что спецификация W3C говорит об этом.
Если "margin-top" или "margin-bottom" являются "auto", их используемое значение равно 0.
Что касается фактического "почему"... вопрос действительно должен быть рассмотрен там.
Ответ 3
Он не центрирует элемент по вертикали, потому что он является элементом уровня блока в нормальном потоке. Таким образом, применяется следующее правило :
Если margin-top
или margin-bottom
являются auto
, их используемое значение равно 0.
Также стоит отметить, что вышеприведенное правило также относится и к следующим элементам: (см. пункты 10.6.2 и 10.6.3 для получения дополнительной информации и условий).
- Встроенные элементы
- Элементы с замещением на уровне блоков в нормальном потоке
-
inline-block
заменены элементы в нормальном потоке
- Плавающие заменяемые элементы
- Незаменяемые элементы на уровне блоков в нормальном потоке, когда
overflow
вычисляет visible
С учетом сказанного абсолютно исключенные элементы, которые не имеют значений top
, height
и bottom
auto
, являются исключением из этого правила. Следующее относится к пункту 10.6.4:
Если ни один из трех top
, height
и bottom
не равен auto
, и если оба margin-top
и margin-bottom
являются auto
, решают уравнение под дополнительным ограничением, два поля получают равные значения.
См. пример ниже, демонстрирующий, как абсолютно позиционированный элемент вертикально центрируется с помощью margin: auto
. Он работает, потому что ни одно из трех свойств top
, height
и bottom
не имеет значения auto
:
.box {
border: 1px solid red;
width: 100px;
height: 100px;
position: relative;
}
.center {
background: blue;
width: 50px;
height: 50px;
margin: auto;
position: absolute;
top: 0; right: 0;
bottom: 0; left: 0;
}
<div class="box">
<div class="center"></div>
</div>
Ответ 4
Почему не margin:auto
работа по вертикали?
Фактически, это происходит - просто не для каждого display
значения.
Если display
flex
, margin: auto
центрируется как по вертикали, так и по горизонтали.
То же самое относится к display: inline-flex
, display: grid
и display: inline-grid
.
.box {
border: 1px solid red;
width: 100px;
height: 100px;
display: flex; /* new */
}
.center {
background: blue;
width: 50px;
height: 50px;
margin: auto;
}
<div class="box">
<div class="center"></div>
</div>
Ответ 5
Это из-за реальной возможности узнать истинную высоту элемента, в котором вы хотите центрировать вертикально. Чтобы понять это, сначала подумайте о том, как работает автоматическое горизонтальное центрирование. У вас есть div, который вы дали ему ширину (фиксированную или процентную). Ширина может быть рассчитана в определенной степени. Если фиксированная ширина, отлично. Если он гибкий или отзывчивый (в процентах), по крайней мере, у вас есть диапазон, который будет охватывать ширина до того, как он достигнет следующей точки останова. Вы берете эту ширину, минус все, что внутри, и разделяете остаток с обеих сторон.
Теперь, с этой информацией, как браузер мог вычислить бесконечное количество вариаций, в которых ваш div будет расти вертикально? Имейте в виду, что размер элемента, обтекание текста, paddings и отзывчивость также изменят ширину и заставят текст обернуться дальше, и дальше, и на нем.
Это невыполнимая задача? На самом деле, CSS потратил время и силы на это? Наверное, не стоит их времени.
И это в основном ответ, который я рассказываю своим ученикам.
Но... не волнуйся! Bootstrap v4 alpha вычислил вертикальное центрирование!
ИЗМЕНИТЬ
Извините, что отредактировал это поздно, но я подумал, что вы можете захотеть рассмотреть это решение, чтобы центрировать по вертикали, и это довольно просто, используя функцию calc
<div class="foo"></div>
.foo {
background-color: red;
height: 6em;
left: calc(50% - 3em);
position: absolute;
top: calc(50% - 3em);
width: 6em;
}
Смотрите ЗДЕСЬ