← Назад к вопросам

Что такое схлопывание margin?

1.0 Junior🔥 162 комментариев
#HTML и CSS

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое схлопывание margin (margin collapsing)

Margin collapsing (схлопывание отступов) — это CSS-поведение, при котором вертикальные margin'ы соседних элементов объединяются в один больший margin вместо того, чтобы складываться. Это распространенная причина непредсказуемого макета на веб-страницах.

Основная идея

Вместо того чтобы margin'ы складывались обычным способом, браузер выбирает БОЛЬШИЙ из двух margin'ов и использует его:

// Если элемент А имеет margin-bottom: 20px
// И элемент Б имеет margin-top: 30px
//
// ОЖИДАЕМ: расстояние между ними = 20px + 30px = 50px
// НА САМОМ ДЕЛЕ: расстояние = MAX(20px, 30px) = 30px

Условия для схлопывания

Маржины схлопываются только в следующих случаях:

1. Вертикальные margin'ы (margin-top и margin-bottom)

/* Вертикальные margin'ы СХЛОПЫВАЮТСЯ */
.box {
  margin-bottom: 30px;
}
.next-box {
  margin-top: 20px;
}
/* Результат: 30px, не 50px */

/* Горизонтальные margin'ы НЕ схлопываются */
.box {
  margin-right: 30px;
}
.next-box {
  margin-left: 20px;
}
/* Результат: 50px */

2. Элементы должны быть в нормальном потоке (не flex, не grid, не absolute)

/* СХЛОПЫВАЮТСЯ */
.container {
  display: block; /* или не указано */
}

/* НЕ СХЛОПЫВАЮТСЯ */
.container {
  display: flex;     /* или grid, inline-flex */
  position: absolute; /* или float */
}

3. Блочные элементы (display: block)

/* СХЛОПЫВАЮТСЯ */
div, p, h1 { display: block; }

/* НЕ СХЛОПЫВАЮТСЯ */
.inline { display: inline; }
.inline-block { display: inline-block; }

Случаи схлопывания

Случай 1: Соседние блочные элементы

<style>
  .box {
    width: 100px;
    height: 100px;
    background: red;
  }
  
  .box1 { margin-bottom: 50px; }
  .box2 { margin-top: 30px; }
</style>

<div class="box box1"></div>
<div class="box box2"></div>

<!-- Расстояние между ними: 50px, не 80px -->

Случай 2: Родитель и первый/последний ребенок

<style>
  .parent {
    background: blue;
    /* margin-top НЕ УКАЗАН */
  }
  
  .child {
    margin-top: 50px;
  }
</style>

<div class="parent">
  <div class="child">Контент</div>
</div>

<!-- margin первого ребенка схлопывается с margin родителя!
     Расстояние между parent и элементом ДО parent = 50px,
     а не 0px + 50px = 50px внутри
-->

Случай 3: Пустые элементы

<style>
  .empty {
    margin-top: 30px;
    margin-bottom: 40px;
  }
  
  .next {
    margin-top: 20px;
  }
</style>

<div class="empty"></div>
<div class="next">Контент</div>

<!-- Margin пустого элемента схлопывается и получается: MAX(40px, 20px) = 40px -->

Визуальный пример

<style>
  body { margin: 0; }
  
  h1 {
    margin-bottom: 100px;
    background: lightblue;
  }
  
  p {
    margin-top: 50px;
    background: lightgreen;
  }
</style>

<h1>Заголовок</h1>
<p>Параграф</p>

<!-- Ожидаем 150px расстояния, но получаем только 100px! -->

Как избежать схлопывания

Решение 1: Использовать padding вместо margin

/* Плохо: margin схлопывается */
.parent {
  margin-top: 20px;
}

/* Хорошо: padding не схлопывается */
.parent {
  padding-top: 20px;
}

Решение 2: Использовать border или padding

.parent {
  /* Эта граница предотвращает схлопывание */
  border-top: 1px solid transparent;
  /* или */
  padding-top: 0.1px; /* минимальный padding */
}

.child {
  margin-top: 50px; /* Теперь не схлопывается */
}

Решение 3: Использовать overflow

.parent {
  overflow: hidden; /* или auto, или any value except visible */
}

.child {
  margin-top: 50px; /* Теперь не схлопывается */
}

Решение 4: Использовать display: flex или grid

/* Flex контейнер игнорирует margin collapsing */
.parent {
  display: flex;
  flex-direction: column;
}

.child {
  margin-top: 50px; /* Работает как ожидается */
}

Решение 5: Использовать gap (современный способ)

.container {
  display: flex;
  flex-direction: column;
  gap: 50px; /* Вместо margin'ов */
}

.item {
  /* margin не нужен */
}

Практический пример: типичная ошибка

<style>
  body { margin: 0; }
  
  .header {
    background: navy;
    color: white;
    padding: 20px;
  }
  
  .content {
    margin-top: 30px; /* Не сработает как ожидается! */
    padding: 20px;
  }
</style>

<div class="header">Header</div>
<div class="content">Content</div>

<!-- Header и Content прилипнут друг к другу
     потому что margin-top у content схлопывается с body margin (0) -->

Margin collapsing при пустых элементах

<style>
  .box1 { margin-bottom: 50px; }
  .spacer { margin: 100px; } /* Пустой элемент */
  .box2 { margin-top: 30px; }
</style>

<div class="box1"></div>
<div class="spacer"></div>
<div class="box2"></div>

<!-- Расстояние: MAX(50px, 100px, 30px) = 100px -->

Отрицательные margin'ы

<style>
  .box1 { margin-bottom: 50px; }
  .box2 { margin-top: -20px; }
</style>

<div class="box1"></div>
<div class="box2"></div>

<!-- Результат: 50px + (-20px) = 30px -->
<!-- При схлопывании: MAX(50px, -20px) = 50px -->

Когда это полезно

Марж-коллапсинг может быть полезен для создания согласованных расстояний:

<style>
  p { margin: 1em 0; }
</style>

<p>Параграф 1</p>
<p>Параграф 2</p>
<p>Параграф 3</p>

<!-- Расстояние между параграфами всегда 1em,
     потому что margin'ы схлопываются -->

Инструменты для диагностики

В Chrome DevTools:

  1. Откройте Elements
  2. Выберите элемент
  3. Посмотрите в Styles на margin (красная область)
  4. Посмотрите на Box Model
  5. Если margin'ы перекрываются, это margin collapsing

Лучшие практики

  1. Последовательно используйте один подход: либо margin-bottom на родителе, либо margin-top на ребенке, не оба
  2. Используйте padding для внутренних расстояний
  3. Используйте gap для контейнеров flex/grid — современный способ
  4. Документируйте проблемные области — оставляйте комментарий если используете padding для избежания collapsing

Заключение

Марж-коллапсинг — это CSS-поведение, которое часто путает разработчиков. Понимание того, когда и почему оно происходит, критически важно для правильного создания макетов. Современный подход (flex, grid, gap) избегает этих проблем полностью.