Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке злиття відступів у CSS». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Злиття відступів** (margin collapsing) - це поведінка CSS, коли два вертикальних відступи стикаються і береться лише більший, а не їх сума. Виникає між сусідніми блоками, батьком і першим/останнім нащадком, та порожніми елементами. ```css .block-a { margin-bottom: 40px; } .block-b { margin-top: 24px; } /* Проміжок між ними: 40px, не 64px */ ``` **Головне:** Flexbox, Grid і `display: flow-root` вимикають злиття відступів.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Margin collapsing** (злиття відступів) - це поведінка CSS, коли два вертикальних відступи стикаються і замість їх суми береться лише більший. ## Теорія ### TL;DR - Зливаються тільки `margin-top` і `margin-bottom`. Горизонтальні відступи ніколи не зливаються. - Три сценарії: сусідні блоки, батько і перший/останній нащадок, порожні елементи. - Перемагає більший відступ. Якщо обидва рівні, результат дорівнює одному з них. - Flexbox, Grid і `overflow: hidden` вимикають злиття. - Тільки нормальний потік. Абсолютно позиціоновані та плаваючі елементи не зливаються. ### Швидкий приклад ```css .card-top { margin-bottom: 40px; } .card-bottom { margin-top: 24px; } /* Фактичний проміжок між ними: 40px, не 64px */ ``` Браузер бере більше значення. 24px просто зникають. ### Три сценарії злиття **Сусідні блоки** - найпоширеніший випадок. Коли `margin-bottom` одного блока межує з `margin-top` наступного, вони зливаються в один відступ. Саме це дивує розробників вперше, коли вони задають відступи між картками або прев'ю статей. **Батько і перший/останній нащадок** - складніший сценарій. Якщо в батьківського елемента немає `padding-top`, `border-top` і жодного inline-контенту перед першим нащадком, `margin-top` нащадка зливається з `margin-top` батька. Відступ ніби вистрибує з батьківського блока. Те саме відбувається знизу з останнім нащадком. ```html <section> <!-- немає padding або border --> <p style="margin-top: 32px;">Перший абзац</p> </section> ``` Весь section зсувається вниз на 32px. Абзац всередині не рухається відносно section. **Порожні блоки** зливають свій верхній і нижній відступ в один. В сучасному коді це рідко стає проблемою, але пояснює дивні пробіли в старій розмітці. ### Як зупинити злиття Для сценарію батько-нащадок будь-який з цих варіантів на батьківському елементі: - `padding-top` або `padding-bottom` - `border` (навіть `1px solid transparent`) - `overflow: hidden` або `overflow: auto` - `display: flow-root` (найчистіший варіант, без побічних ефектів) - `display: flex` або `display: grid` Для злиття сусідніх блоків рішення знаходиться на рівні контейнера. Перевести обгортку в `display: flex` з `gap` - і відступи більше не зливатимуться. ### Типові помилки Найпоширеніша: розробник додає `margin-top: 40px` до заголовка всередині section, а потім дивується чому весь section зсунувся вниз, а не заголовок. Це злиття батька з нащадком. Одна строчка виправляє: `display: flow-root` на батьківському елементі. Ще часта ситуація: два компоненти з `margin-bottom: 30px` і `margin-top: 30px` відповідно. Розробник очікує 60px між ними, отримує 30px. Нічого не зламалось - злиття працює за специфікацією. Я бачив, як це викликало тривалий дебагінг при передачі дизайну, де відступи збігалися з Figma, але розробник очікував що маржини підсумовуватимуться. Від'ємні відступи мають свої правила. Якщо один відступ `-20px`, а інший `30px`, результат буде `10px` (вони складаються, коли знаки різні). Два від'ємних відступи дають найбільший за модулем від'ємний. ### Follow-up питання **Q:** Чи зливаються відступи всередині flex або grid контейнера? **A:** Ні. Обидва формати створюють новий контекст форматування (block formatting context), який вимикає злиття для прямих нащадків. **Q:** Що відбувається, якщо один відступ від'ємний? **A:** Від'ємний і позитивний відступи складаються. Тобто `30px` і `-10px` дадуть `20px`. Два від'ємних дають найбільший за модулем від'ємний. **Q:** `display: flow-root` кращий за `overflow: hidden` для цього? **A:** Для цієї конкретної задачі - так. `overflow: hidden` обрізає контент, що виходить за межі батька, що зазвичай небажано. `display: flow-root` створює контекст форматування без жодного обрізання. **Q:** Чи можуть горизонтальні відступи зливатись? **A:** Ні. Специфікація CSS описує злиття тільки для вертикальних відступів у нормальному потоці. ## Приклади ### Відступи між сусідами, які не підсумовуються ```html <article class="post">...</article> <article class="post">...</article> ``` ```css .post { margin-top: 32px; margin-bottom: 32px; } /* Проміжок між двома постами: 32px, а не 64px */ ``` Кожен пост оголошує 32px з обох боків, але між будь-якими двома постами тільки 32px загалом, не 64px. Для передбачуваних відступів у карткових layouts краще використовувати `gap` на flex або grid контейнері. ### Маржин нащадка, що вистрибує з батька ```css .hero { background: #f0f0f0; /* Без padding або border */ } .hero h1 { margin-top: 48px; } ``` ```html <section class="hero"> <h1>Вітаємо</h1> </section> ``` `margin-top` у `h1` зливається з `margin-top` section. Весь section зсувається вниз на 48px, а не тільки заголовок. Додати `padding-top: 1px` до `.hero` або виставити `display: flow-root` - і відступ залишиться всередині.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.