Margin collapse muammosi va yechimi

~15 daq · CSS · Box Model va Matn

Muammodan boshlaylik

Ikki holat, ikkalasi ham "CSS buzilgan" deb o'ylatadi:

1. Ikki paragraf:

p {
  margin-top: 20px;
  margin-bottom: 30px;
}

Paragraflar orasidagi bo'shliq 20 + 30 = 50px bo'lishi kerak. DevTools da o'lchaysiz — 30px.

2. Kartochka ichidagi sarlavhaga margin-top: 40px berdingiz. Sarlavha kartochka ichida pastga tushmadi — butun kartochka 40px pastga surildi, sarlavha esa uning yuqori chetiga yopishib qoldi.

Bu xato emas. Bu — margin collapse (marginlar "qo'shilib ketishi"): CSS ning ataylab qilingan, lekin eng ko'p chalkashlik keltiradigan qoidalaridan biri.


Qoida: vertikal marginlar qo'shilmaydi — kattasi qoladi

Ikki vertikal margin to'qnashganda ular qo'shilmaydi. Natijada kattasi qoladi:

┌──────────────┐
│  1-paragraf  │
└──────────────┘
   margin-bottom: 30px  ┐
                        ├─ to'qnashadi → 30px (kattasi), 50px emas
   margin-top: 20px     ┘
┌──────────────┐
│  2-paragraf  │
└──────────────┘
Margin lar Natija
30px va 20px 30px
20px va 20px 20px
30px va −10px 20px (manfiy bo'lsa — qo'shiladi)
−10px va −20px −20px (ikkalasi manfiy — eng kichigi)

[!INFO] Margin collapse faqat vertikal (tepa va past) marginlarda bo'ladi. Gorizontal (chap va o'ng) marginlar hech qachon qo'shilib ketmaydi — ular har doim yig'iladi.


Uch holat

1. Qo'shni elementlar

Yuqoridagi paragraflar misoli. Bu holat foydali: matn sahifasida har bir element "men atrofimda kamida 30px bo'shliq bo'lsin" deydi, va qo'shnilar bo'shliqni ikki baravar oshirib yubormaydi.

2. Ota va birinchi/oxirgi bola

<div class="card">
  <h2>Sarlavha</h2>
</div>
.card {
  background: #f1f5f9;
}

.card h2 {
  margin-top: 40px;
}

Ota (.card) va uning birinchi bolasi (h2) orasida hech narsa yo'q — padding ham, border ham, matn ham. Shuning uchun bolaning margin-top i otaning chetidan "sizib chiqadi" va otaning o'z margini bilan birlashadi. Natija: butun .card 40px pastga suriladi — darsning boshidagi 2-holat.

Kutilgan:                         Haqiqatda:

┌─ .card ─────────┐                 ↕ 40px (kartochka tashqarisida!)
│  ↕ 40px         │               ┌─ .card ─────────┐
│  Sarlavha       │               │  Sarlavha       │
└─────────────────┘               └─────────────────┘

Oxirgi bolaning margin-bottom i bilan ham xuddi shunday.

3. Bo'sh element

Balandligi, padding i, border i va kontenti yo'q element — uning o'z margin-top va margin-bottom i bir-biri bilan birlashadi. Kamdan-kam uchraydi.


Yechimlar

Collapse faqat marginlar bevosita to'qnashganda bo'ladi. Ular orasiga biror narsa qo'ysangiz — to'xtaydi.

Ota-bola holati uchun

/* 1. Margin o'rniga otaga padding */
.card {
  padding-top: 40px;
}

/* 2. Otaga padding yoki border — hatto 1px ham yetarli */
.card {
  padding: 24px;
}

/* 3. Yangi formatlash konteksti */
.card {
  display: flow-root;
}

display: flow-root — aynan shu maqsad uchun yaratilgan: elementni "mustaqil" qiladi, bolalarining margini undan sizib chiqmaydi. Ko'rinishga boshqa hech narsa ta'sir qilmaydi.

Flexbox va Grid — collapse yo'q

.card {
  display: flex;
  flex-direction: column;
}

Flex va Grid konteynerlar ichida margin collapse umuman bo'lmaydi. Bu ularning ko'p sabablardan biri, nima uchun zamonaviy layout lar asosan shular bilan quriladi (3–4-bo'limlar).

Qo'shnilar uchun — bir tomonlama margin

Eng sodda va eng tushunarli usul: marginni faqat bir yo'nalishda bering:

/* ❌ ikki tomonlama — collapse va chalkashlik */
.card {
  margin-top: 20px;
  margin-bottom: 20px;
}

/* ✅ faqat pastdan */
.card {
  margin-bottom: 20px;
}

Yoki zamonaviyroq — "lobotomized owl" selektori (4-dars kombinatorlari):

.stack > * + * {
  margin-top: 16px;
}

".stack ning har bir bolasi, agar undan oldin boshqa bola bo'lsa — tepadan 16px". Birinchi elementdan oldin bo'shliq yo'q, qolganlari orasida — teng. Collapse ga joy qolmaydi.

Eng yaxshisi — gap

.stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

gap — faqat elementlar orasida, chetlarda emas, collapse yo'q, hisoblash yo'q. Komponentlar ichida bo'shliq uchun bugungi eng yaxshi tanlov (14-dars).


Collapse bo'lmaydigan holatlar

Margin collapse bo'lmaydi, agar:

  • Marginlar gorizontal bo'lsa
  • Element flex yoki grid item bo'lsa
  • Element position: absolute yoki fixed bo'lsa
  • Element float bo'lsa
  • Element display: inline-block bo'lsa
  • Ota display: flow-root, overflow: hidden/auto yoki padding/border ga ega bo'lsa (ota-bola holati uchun)

Nima uchun shunday?

Nima uchun CSS marginlarni "yutib yuboradigan" qilib loyihalangan — bu xato emasmi?

Yo'q — bu matnli hujjatlar uchun loyihalangan va u yerda juda mantiqiy. Tasavvur qiling: sarlavha "mendan keyin 24px bo'shliq bo'lsin" deydi, paragraf esa "mendan oldin 16px". Ular yonma-yon kelganda 40px bo'shliq hujjatni tarqoq qiladi — tipografik qoidalar bo'yicha bo'shliq kattasi bo'lishi kerak: 24px. Margin collapse aynan shuni qiladi, va maqola, blog, hujjat sahifalarida avtomatik chiroyli ritm beradi. Muammo faqat CSS "hujjat" emas, "ilova interfeysi" quradigan bo'lganda paydo bo'ldi — kartochkalar, panellar. Shuning uchun komponentlar uchun Flexbox, Grid va gap ga o'tish tavsiya etiladi: u yerda bunday qoida yo'q.


Xulosa

Eslab qoling:

  • Ikki vertikal margin to'qnashsa — qo'shilmaydi, kattasi qoladi
  • Gorizontal marginlar hech qachon collapse bo'lmaydi
  • Uch holat: qo'shni elementlar; ota va birinchi/oxirgi bola; bo'sh element
  • Ota-bola: otaga padding/border yoki display: flow-root
  • Flex va Grid ichida collapse yo'q
  • Bir tomonlama margin (margin-bottom) yoki .stack > * + *
  • Eng yaxshisi — display: flex/grid + gap

Keyingi dars

10-dars: Overflow — visible, hidden, scroll, auto