margin задаёт отступ снаружи рамки элемента, до соседей - его сокращённая запись работает так же, как у padding (см. предыдущий урок), но у margin есть два отличия: он может быть отрицательным, а вертикальные margin соседних блочных элементов не складываются, а схлопываются - берётся большее из двух значений.
В этом уроке
Попробуй прямо сейчас: посмотри на зазор между блоками - он равен 30px (большему значению), а не 50px (сумме). Смени margin-top у .b на 40px - зазор станет 40px.
Как задать margin: та же запись, что у padding, но можно в минус
margin понимает ту же сокращённую запись, что и padding: одно значение - на все стороны, два - верх/низ и право/лево, три и четыре - по тому же принципу (см. предыдущий урок). Главное отличие: margin разрешает отрицательные значения, а padding - нет. Отрицательный margin сдвигает элемент в обратную сторону, как бы "вытягивая" его за пределы обычного места.
margin-top: -10px; - элемент сдвинется на 10px вверх относительно своего обычного положения.
padding: -10px; в попытке добиться того же эффекта - padding отрицательным быть не может, значение просто проигнорируется (см. урок про padding).
margin: auto и центрирование блока по горизонтали
Значение auto у margin-left и margin-right (или сокращённо margin: 0 auto) - классический способ отцентрировать блочный элемент по горизонтали. Браузер сам поровну распределяет свободное место слева и справа. Но это работает только если у элемента явно задана ширина (width) - без неё блочному элементу просто нечего центрировать, он и так растягивается на всю доступную ширину.
width: 300px; margin: 0 auto; - блок шириной 300px окажется точно по центру родителя.
margin: 0 auto; без width - у обычного блочного элемента (div) нет эффекта, он и без того занимает всю ширину родителя.
Схлопывание margin: почему соседние отступы не складываются
Когда margin-bottom одного блочного элемента соприкасается с margin-top следующего (без border, padding или контента между ними), они не складываются, а схлопываются - в итоге получается ОДИН отступ, равный БОЛЬШЕМУ из двух значений. Это касается только вертикальных отступов между обычными блочными соседями - горизонтальные margin (слева/справа) никогда не схлопываются, они всегда просто складываются, как ожидалось бы интуитивно.
margin-bottom: 30px; у первого блока и margin-top: 20px; у второго - реальный зазор между ними будет 30px, а не 50px.
Расчёт на то, что отступы сложатся (30+20=50px) - для вертикальных margin соседних блоков это не так, они схлопываются в максимум.
Частые ошибки новичков
| Ошибка | Что происходит | Как исправить |
|---|---|---|
| Ожидают, что соседние вертикальные margin сложатся (например 30px + 20px = 50px) | На самом деле получится 30px - большее из двух значений, а не сумма | Закладывать в расчёты именно бОльшее из двух значений margin, а не сумму |
| Пытаются центрировать блок через margin: auto, не задав ему явную ширину | Без width блочный элемент и так занимает всю ширину родителя - центрировать нечего | Обязательно задать width (или max-width) вместе с margin: 0 auto |
| Ожидают схлопывания и для горизонтальных margin (слева/справа) | Горизонтальные margin никогда не схлопываются, они всегда складываются | Закладывать сумму, а не максимум, для margin-left и margin-right |
| Удивляются, что вертикальные margin внутри flex-контейнера ведут себя иначе | Элементы flex (и grid) контейнера никогда не схлопывают margin между собой, даже по вертикали | Учитывать, что схлопывание - поведение обычных блочных элементов, а не универсальное правило CSS |
Шпаргалка
| Что нужно | Как сделать |
|---|---|
| Одинаковый отступ со всех сторон | margin: 20px; |
| Отступ только с одной стороны | margin-left: 20px; |
| Отрицательный отступ (сдвиг элемента) | margin-top: -10px; |
| Центрировать блок с заданной шириной | width: 300px; margin: 0 auto; |
| Зазор между соседними блоками (вертикаль) | больше из двух margin, а не сумма (схлопывание) |
| Зазор между соседними блоками (горизонталь) | сумма двух margin - схлопывания нет |
Коротко: отвечаем на вопросы
Как бороться со схлопыванием (сливанием) margin, если оно мешает вёрстке?
Проще всего добавить между блоками хоть немного border или padding - тогда margin уже не будут "соприкасаться" напрямую и схлопывание не сработает. Ещё один рабочий вариант - перевести родителя на display: flex или grid: у элементов внутри такой раскладки margin между собой никогда не схлопываются.
Почему margin: 0 auto не центрирует мой блок?
Самая частая причина - у элемента не задана явная ширина (width или max-width). Без неё блочный элемент и так растягивается на всю ширину родителя, и центрировать буквально нечего. Добавление конкретного width обычно сразу решает проблему.