Xiper

Схлопывание margin

Автор: Татьяна Шкабко, Александр Головко Дата публикации:

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

	<div class="parent">
		<h1>Заголовок </h1>
		<p>Абзац</p>
		<p>Абзац</p>
		<ul>
			<li>Первый элемент списка</li>
			<li>.........................</li>
			<li>Последний элемент списка</li>
		</ul>
		<p>Абзац</p>
	</div>
.parent {
	margin: 0 auto;
	width: 500px;
}
h1 {
	margin: 15px 5px;
}
ul {
	margin: 5px;
}
li {
	margin:5px 0;
}
p {
	margin:5px;
}

На первый взгляд может показаться, что все должно выглядеть так, как на рисунке ниже (для удобства блоки раскрашены):

margin не схлопывается Наверное, на странице это будет выглядеть как-то так?

На практике же все получается немного по-другому. Смотрим демо-пример.

Чтобы не мерить линейкой экран, все размеры отступов приведены на рисунке:

margin схлопывается Вот то, что рисует браузер!

Откуда взялся у родительского элемента ненулевой верхний отступ? И вообще отступы у элементов сильно отличаются от ожидаемых. Что же это такое и почему так получается?

Почему отступы разные?

На самом деле никакой мистики нет — отступы отрисовываются именно такими, какими их задали в CSS. Просто произошло схлопывание margin — соприкасающиеся отступы как бы проникают друг в друга.

Заметка. Согласно спецификации CSS2.1 горизонтальные margin никогда не схлопываются. Схлопывание влияет только на вертикальные margin!

Как проявляется схлопывание вертикальных margin

Схлопывание проявляется двумя эффектами:

  1. Схлопываются соседние отступы смежных элементов.

    схлопывание margin Вот так они накладываются

    Вертикальный отступ между элементами равен не сумме двух отступов соседних элементов, а большему из этих отступов.

  2. Схлопываются вертикальные внешние отступы родителя и потомка. Результирующий отступ равен большему из схлопываюшихся margin. Это приводит к тому, что если у дочернего элемента margin больше чем у родителя, то он как бы выталкивает родителя:

    схлопывание margin Margin дочернего элемента увеличивает отступ родителя

    В примере приведенном выше у родительского элемента был верхний маржин 5px, но он схлопнулся с верхним маржином 10px дочернего элемента. В результате получили у верхний результирующий отступ 10px — родитель «провалился» на 5px вниз. Обрати внимание! Отступа между родителем и потомком в такой ситуации не будет.

    Схлопываются как верхний отступ родителя с верхним отступом первого дочернего элемента, так и нижний отступ родителя с нижним отступом последнего дочернего элемента.

Если один из margin отрицательный, а другой положительный, результирующий отступ будет равен их сумме.

Где это можно использовать?

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

p {
	margin:10px 0;
}

Если бы схлопывания не существовало, то отступы между абзацами были бы по 20px, а отступ перед первым абзацем и после последнего — только 10 (т.е. в два раза меньше)! Чтобы отступы были равномерными, пришлось бы дополнительно повозиться.

А так все в порядке, соседние отступы схлопнутся — получаем предсказуемый одинаковый отступ по 10px.

В каких случаях схлопывания не будет?

Схлопывание вертикальных отступов не происходит между:

  • родительским элементом и дочерним элементом, если у родительского элемента с этой стороны есть внутренний отступ (padding) или граница (border);
  • плавающим блоком и любыми другими блоками (в том числе и дочерними блоками);
  • абсолютно спозиционированным блоком и любыми другими блоками (в том числе и дочерними блоками)
  • строчным блоком и любыми другими блоками (в том числе и дочерними блоками);
  • элементом устанавливающим новый контекст форматирования (например, плавающим блоком или блоком с overflow отличным от visible) и его дочерними блоками;
  • корневым элементом и его дочерними блоками.

Как поступать, если схлопывание отступов не нужно?

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

Различные варианты убрать схлопывание смотри в статье Обходим схлопывание margin.

Материалы:

  • W3C:: Box model :: Collapsing margins
  • UEric A. Meyer :: Uncollapsing Margins