Kurs HTML

6.6. Nakładanie się marginesów (Margin Collapsing)

Strona główna > Kurs CSS > Rozdział 6: Model Pudełkowy (Box Model) > Nakładanie się marginesów (Margin Collapsing)

Wprowadzenie: Tajemnica pionowych marginesów

Nakładanie się marginesów (margin collapsing) to specyficzne zachowanie w CSS, które dotyczy **wyłącznie marginesów pionowych** (margin-top i margin-bottom) sąsiadujących ze sobą elementów blokowych w normalnym przepływie dokumentu.

Zamiast sumować się, dwa lub więcej sąsiadujących marginesów pionowych **łączą się (nakładają) w jeden margines**, którego rozmiar jest równy **największemu** z nakładających się marginesów.

Zrozumienie tego mechanizmu jest kluczowe, aby uniknąć niespodzianek w pionowych odstępach między elementami.

Uwaga: Margin collapsing dotyczy tylko marginesów pionowych. Marginesy poziome (margin-left, margin-right) nigdy się nie nakładają – zawsze się sumują.

Kiedy występuje nakładanie się marginesów?

Margin collapsing występuje w trzech głównych sytuacjach:

1. Sąsiadujące rodzeństwo (Adjacent Siblings)

Jest to najczęstszy przypadek. Kiedy dwa elementy blokowe następują bezpośrednio po sobie w kodzie HTML (są rodzeństwem), dolny margines (margin-bottom) pierwszego elementu nakłada się z górnym marginesem (margin-top) drugiego elementu.

Ostateczny odstęp między nimi będzie równy większemu z tych dwóch marginesów.

<div class="box1">Box 1</div>
<div class="box2">Box 2</div>
.box1 {
  margin-bottom: 20px;
  background: lightcoral;
}
.box2 {
  margin-top: 30px;
  background: lightblue;
}
/* Odstęp między box1 i box2 wyniesie 30px (max(20px, 30px)), a nie 50px! */

Jeśli jeden z marginesów jest ujemny, są one sumowane algebraicznie, a następnie wybierana jest największa wartość (np. margin-bottom: 20px; i margin-top: -10px; da odstęp 10px; margin-bottom: -20px; i margin-top: -30px; da odstęp -30px).

2. Rodzic i pierwsze/ostatnie dziecko (Parent and First/Last Child)

Jeśli **nie ma** paddingu, obramowania, treści inline ani prześwitu (clearance) między górnym marginesem (margin-top) elementu blokowego rodzica a górnym marginesem (margin-top) jego pierwszego dziecka (które też jest blokowe), to te dwa marginesy się nałożą.

Podobnie, jeśli **nie ma** paddingu, obramowania, treści inline, jawnie ustawionej wysokości (height lub min-height) ani prześwitu między dolnym marginesem (margin-bottom) rodzica a dolnym marginesem (margin-bottom) jego ostatniego dziecka, te marginesy również się nałożą.

<div class="parent">
  <div class="child">Child</div>
</div>
.parent {
  margin-top: 50px;
  background: lightyellow;
  /* Brak border, padding, treści inline przed dzieckiem */
}
.child {
  margin-top: 30px;
  background: lightgreen;
}
/* Górny margines .parent (50px) nałoży się z górnym marginesem .child (30px). */
/* Efektywnie, .parent będzie miał 50px marginesu od góry, a .child nie będzie miał */
/* dodatkowego marginesu wewnątrz rodzica. */

Ten przypadek często powoduje konfuzję, gdy próbujemy dodać margines górny do pierwszego dziecka, a zamiast tego "wypycha" on rodzica.

3. Puste bloki (Empty Blocks)

Jeśli element blokowy nie ma ustawionego paddingu, obramowania, treści inline, wysokości (height lub min-height) ani prześwitu, jego górny margines (margin-top) nałoży się z jego dolnym marginesem (margin-bottom).

<div class="before">Before</div>
<div class="empty"></div>
<div class="after">After</div>
.before { margin-bottom: 10px; background: pink; }
.empty {
  margin-top: 20px;
  margin-bottom: 30px;
  /* Brak treści, paddingu, border, height */
}
.after { margin-top: 15px; background: cyan; }

/* Margines .empty (max(20px, 30px) = 30px) nałoży się z: */
/* - dolnym marginesem .before (10px) -> max(30px, 10px) = 30px */
/* - górnym marginesem .after (15px) -> max(30px, 15px) = 30px */
/* Ostateczny odstęp między .before i .after wyniesie 30px. */

Kiedy marginesy się NIE nakładają?

Istnieje kilka sytuacji, w których margin collapsing **nie występuje**:

  • Marginesy poziome: Nigdy się nie nakładają.
  • Elementy pozycjonowane absolutnie lub fixed: Ich marginesy nie nakładają się z niczym.
  • Elementy pływające (floated): Ich marginesy nie nakładają się z niczym.
  • Elementy z display: inline-block;: Ich marginesy nie nakładają się z niczym (ponieważ nie są w pełni elementami blokowymi w normalnym przepływie).
  • Elementy będące kontenerami Flexbox lub Grid: Marginesy ich dzieci nie nakładają się z marginesami kontenera.
  • Elementy z overflow innym niż visible: Marginesy ich dzieci nie nakładają się z marginesami kontenera.
  • Elementy z obramowaniem (border) lub wypełnieniem (padding): Marginesy rodzica i dziecka są oddzielone przez border/padding, więc się nie nakładają.
  • Elementy z prześwitem (clearance): Jeśli element ma ustawione clear, jego górny margines nie nałoży się z dolnym marginesem elementów pływających powyżej.
  • Górny margines elementu root (<html>): Nigdy się nie nakłada.

Jak radzić sobie z Margin Collapsing?

Zamiast walczyć z margin collapsing, często lepiej jest zrozumieć, kiedy występuje i projektować layout w sposób, który go uwzględnia lub unika w kontrolowany sposób.

  • Spójne marginesy: Używaj głównie margin-bottom (lub margin-top) dla sąsiadujących elementów, zamiast mieszać oba. Np. ustawiaj odstęp tylko pod paragrafami.
  • Padding/Border dla rodzica: Aby zapobiec nakładaniu się marginesu rodzica i pierwszego/ostatniego dziecka, dodaj rodzicowi niewielki padding-top/padding-bottom (nawet 1px) lub border-top/border-bottom.
  • Nowe konteksty formatowania: Użycie overflow: hidden; (lub auto, scroll), display: flow-root;, display: inline-block;, Flexbox lub Grid na rodzicu zapobiega nakładaniu się marginesów między rodzicem a dziećmi.
  • Użycie paddingu zamiast marginesu: Czasami zamiast dodawać margin-top pierwszemu dziecku, lepiej dodać padding-top rodzicowi.

Zadania praktyczne

Zadanie 1 (z rozwiązaniem)

Masz dwa paragrafy. Pierwszy ma margin-bottom: 15px;, a drugi margin-top: 25px;. Jaki będzie rzeczywisty odstęp między nimi?

Rozwiązanie:

Marginesy pionowe sąsiadującego rodzeństwa nałożą się. Rzeczywisty odstęp będzie równy większemu z marginesów, czyli 25px (max(15px, 25px)).

Zadanie 2 (do samodzielnego wykonania)

Stwórz element div z klasą .outer i nadaj mu margin-top: 40px; oraz tło. Wewnątrz niego umieść element div z klasą .inner i nadaj mu margin-top: 30px; oraz inne tło. Zaobserwuj w narzędziach deweloperskich, jak marginesy się nakładają. Następnie dodaj padding-top: 1px; do elementu .outer i zobacz, jak to zmienia sytuację.

Zadanie 3 (do samodzielnego wykonania)

Stwórz trzy elementy div jeden pod drugim. Środkowy element ma być pusty (bez treści, paddingu, border, height). Nadaj pierwszemu margin-bottom: 10px;, środkowemu margin-top: 20px; margin-bottom: 20px;, a trzeciemu margin-top: 15px;. Jaki będzie odstęp między pierwszym a trzecim elementem?

FAQ - Najczęściej zadawane pytania

Czy margin collapsing to błąd w CSS?

Nie, jest to celowe zachowanie zdefiniowane w specyfikacji CSS. Ma ono na celu zapewnienie spójnych odstępów między akapitami i innymi blokami tekstu, nawet jeśli mają one zdefiniowane zarówno górne, jak i dolne marginesy. Może jednak być mylące dla początkujących.

Czy marginesy elementów inline-block się nakładają?

Nie, marginesy pionowe elementów z display: inline-block; nie podlegają mechanizmowi nakładania się.

Czy Flexbox lub Grid eliminują problem nakładania się marginesów?

Tak, wewnątrz kontenera Flexbox lub Grid marginesy pionowe elementów potomnych nie nakładają się ani ze sobą, ani z marginesami kontenera. To jedna z zalet używania tych nowoczesnych metod layoutu.

Jak wizualnie sprawdzić, czy marginesy się nałożyły?

Narzędzia deweloperskie przeglądarek (np. w Chrome, Firefox) zazwyczaj wizualizują model pudełkowy, w tym marginesy. Można tam zaobserwować, jak marginesy sąsiadujących elementów łączą się w jeden większy margines.