← Назад к вопросам
Как поведут себя стыкующиеся Margin-Bottom и Margin-Top?
2.0 Middle🔥 142 комментариев
#HTML и CSS
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Margin Collapse (схлопывание маржинов)
Это одна из самых запутанных концепций CSS. Расскажу точно как это работает.
Что такое margin collapse?
Когда два элемента с вертикальными маржинами стоят рядом, браузер не складывает их просто так. Вместо этого берёт БОЛЬШИЙ из двух маржинов.
<!-- Пример -->
<div class="element1">Элемент 1</div>
<div class="element2">Элемент 2</div>
<style>
.element1 {
margin-bottom: 30px;
}
.element2 {
margin-top: 20px;
}
</style>
<!-- ОЖИДАЕШЬ: 30px + 20px = 50px расстояния
ПОЛУЧАЕШЬ: max(30px, 20px) = 30px расстояния
Маржины СХЛОПЫВАЮТСЯ!
-->
Визуальный пример
┌─────────────────────┐
│ Элемент 1 │
│ margin-bottom: 30px │
└─────────────────────┘
↓ 30px (НЕ 50px!)
↓
┌─────────────────────┐
│ Элемент 2 │
│ margin-top: 20px │
└─────────────────────┘
Когда маржины схлопываются?
Случай 1: Соседние элементы (siblings)
<div class="box1">Box 1</div>
<div class="box2">Box 2</div>
<style>
.box1 { margin-bottom: 40px; }
.box2 { margin-top: 20px; }
</style>
<!-- Расстояние = max(40px, 20px) = 40px -->
Случай 2: Родитель и первый потомок
<div class="parent">
<div class="child">Потомок</div>
</div>
<style>
.parent {
margin-top: 50px;
/* нет padding, border, или content */
}
.child {
margin-top: 30px;
}
</style>
<!-- Маржин ребёнка "протекает" наружу!
Маржин родителя также 50px (не 50+30=80)
ЖДЁШЬ: родитель имеет margin-top 50px,
ребёнок имеет margin-top 30px,
всего 80px от верхнего элемента
ПОЛУЧАЕШЬ: всего max(50px, 30px) = 50px!
Маржин ребёнка "отменяет" маржин родителя
-->
Визуально:
БЕЗ margin collapse (с padding):
┌────────────────────────────────┐
│ PARENT │
│ padding-top: 10px │
│ ┌──────────────────────────┐ │
│ │ CHILD │ │
│ │ margin-top: 30px │ │
│ │ (маржин НЕ протекает) │ │
│ └──────────────────────────┘ │
└────────────────────────────────┘
С margin collapse (БЕЗ padding):
┌────────────────────────────────┐
│ PARENT │ <- margin-top протекает!
│ margin-top: 50px │ <- расстояние = 50px
│ ┌──────────────────────────┐ │
│ │ CHILD │ │
│ │ margin-top: 30px │ │ <- маржин потомка
│ │ (маржин ПРОТЕКАЕТ наружу)│ │ не добавляется
│ └──────────────────────────┘ │
└────────────────────────────────┘
Как предотвратить margin collapse?
Метод 1: Добавь padding родителю
.parent {
margin-top: 50px;
padding-top: 1px; /* даже 1px помогает! */
}
.child {
margin-top: 30px;
}
/* Теперь маржин ребёнка НЕ протекает */
Метод 2: Добавь border родителю
.parent {
margin-top: 50px;
border-top: 1px solid transparent; /* невидимая граница */
}
.child {
margin-top: 30px;
}
/* Теперь маржин ребёнка НЕ протекает */
Метод 3: Добавь overflow родителю
.parent {
margin-top: 50px;
overflow: hidden; /* или auto */
}
.child {
margin-top: 30px;
}
/* Теперь маржин ребёнка НЕ протекает */
Метод 4: Сделай родителя flex/grid
.parent {
margin-top: 50px;
display: flex; /* flex контейнер не схлопывает маржины */
}
.child {
margin-top: 30px;
}
/* Теперь маржин ребёнка НЕ протекает */
Метод 5: Используй gap вместо margin
.parent {
display: flex;
flex-direction: column;
gap: 20px; /* вместо margin между элементами */
}
/* gap НЕ схлопывается */
Практические примеры
Пример 1: Списки
<ul>
<li>Элемент 1</li>
<li>Элемент 2</li>
<li>Элемент 3</li>
</ul>
<style>
li {
margin-bottom: 15px;
}
</style>
<!-- Маржины между элементами схлопываются!
Расстояние между li = 15px (не 30px)
-->
<!-- ПРАВИЛЬНОЕ решение -->
<style>
ul {
display: flex;
flex-direction: column;
gap: 15px; /* используем gap */
}
li {
/* margin-bottom удалить */
}
</style>
Пример 2: Карточка с содержимым
<div class="card">
<h2>Заголовок</h2>
<p>Описание</p>
</div>
<style>
.card {
background: white;
padding: 20px; /* ВАЖНО: padding предотвращает collapse */
}
h2 {
margin-top: 0; /* дополнительная мера безопасности */
margin-bottom: 10px;
}
p {
margin-top: 0; /* дополнительная мера безопасности */
}
</style>
Пример 3: Контейнер и потомки
<div class="container">
<header class="header">Заголовок</header>
<main class="main">Содержимое</main>
</div>
<style>
.container {
margin-top: 30px;
padding-top: 1px; /* предотвращаем collapse */
}
.header {
margin-top: 50px; /* это НЕ добавляется к .container */
}
</style>
Когда margin collapse НЕ работает
Margin collapse НЕ работает в следующих случаях:
/* 1. Flex контейнеры */
.flex-parent {
display: flex; /* маржины НЕ схлопываются */
}
/* 2. Grid контейнеры */
.grid-parent {
display: grid; /* маржины НЕ схлопываются */
}
/* 3. Элементы с position: absolute */
.absolute {
position: absolute; /* маржины НЕ схлопываются */
}
/* 4. Элементы с position: fixed */
.fixed {
position: fixed; /* маржины НЕ схлопываются */
}
/* 5. Элементы с float */
.floated {
float: left; /* маржины НЕ схлопываются */
}
/* 6. Горизонтальные маржины (margin-left, margin-right) */
.horizontal {
margin-left: 20px; /* НИКОГДА не схлопываются */
margin-right: 20px; /* НИКОГДА не схлопываются */
}
Отрицательные маржины
Маржины могут быть и отрицательными:
<div class="box1" style="margin-bottom: -10px;">Box 1</div>
<div class="box2" style="margin-top: 20px;">Box 2</div>
<!-- Маржины ВСЕГДА схлопываются даже если отрицательные!
Результат = max(-10px, 20px) = 20px
Если обе отрицательные:
margin-bottom: -20px;
margin-top: -30px;
Результат = max(-20px, -30px) = -20px (БОЛЬШИЙ из отрицательных)
-->
React компонент с правильными маржинами
// ПЛОХО - ненадёжное расстояние
function CardList() {
return (
<div>
<Card /> {/* margin-bottom: 20px */}
<Card /> {/* margin-top: 20px */}
<Card />
</div>
);
}
/* Расстояние между карточками = 20px (схлопываются!) */
// ХОРОШО - надёжное решение
function CardList() {
return (
<div className="card-list">
<Card />
<Card />
<Card />
</div>
);
}
.card-list {
display: flex;
flex-direction: column;
gap: 20px; /* гарантированное расстояние */
}
// ХОРОШО - с padding родителя
function CardList() {
return (
<div className="card-container">
<Card />
<Card />
<Card />
</div>
);
}
.card-container {
padding: 10px; /* предотвращаем collapse */
}
Итого
Margin collapse - это когда браузер берёт БОЛЬШИЙ из двух соприкасающихся вертикальных маржинов вместо их суммирования.
Когда происходит:
- Соседние элементы (верхний margin одного + нижний margin другого)
- Родитель и первый потомок (если нет padding/border/overflow)
Как избежать:
- Используй gap вместо margin (лучший способ)
- Добавь padding к родителю (даже 1px)
- Добавь border к родителю
- Используй flex или grid контейнеры
- Добавь overflow: hidden
Помни:
- Горизонтальные маржины (left/right) НИКОГДА не схлопываются
- Margin collapse работает ТОЛЬКО для вертикальных маржинов
- Modern подход: используй gap в flex/grid контейнерах
- Legacy подход: управляй margin collapse с padding/border/overflow