Что такое Box Model в CSS?

JuniorCSS #css #box-model

Вопрос

Из чего состоит блочная модель (box model) в CSS, чем отличаются content-box и border-box, и что такое схлопывание отступов (margin collapsing)?

Короткий ответ

Каждый элемент в CSS — это прямоугольник, состоящий из четырёх слоёв: content → padding → border → margin. Свойство box-sizing определяет, входят ли padding и border в заданную ширину элемента. Вертикальные внешние отступы соседних блоков могут схлопываться в один.

Подробный ответ

Блочная модель — фундаментальный механизм рендеринга в CSS. У каждого элемента есть:

  • content — область с содержимым (текст, изображение), размер задаётся width/height.
  • padding — внутренний отступ между содержимым и границей, закрашивается фоном элемента.
  • border — граница вокруг padding.
  • margin — внешний отступ, разделяет элемент с соседями, прозрачен и не закрашивается фоном.

box-sizing определяет, как считается итоговый размер элемента:

  • content-box (по умолчанию) — width/height задают размер только области содержимого; padding и border добавляются сверху, увеличивая фактический размер блока. Из-за этого сложно предсказать итоговую ширину при добавлении padding.
  • border-box — width/height включают в себя padding и border; content сжимается, чтобы вписаться. Это интуитивнее, поэтому почти все CSS-сбросы (reset/normalize) переключают весь документ на border-box.

Margin collapsing (схлопывание отступов) — вертикальные margin двух соседних блочных элементов (или margin родителя и первого/последнего ребёнка без padding/border/content между ними) не складываются, а схлопываются в один, равный большему из двух. Работает только для вертикальных margin в обычном потоке документа; не происходит, если у элементов overflow отличен от visible, они во flex/grid-контейнере, или между margin есть padding/border/content, разделяющий их.

Пример

/* классический сброс на border-box */
*, *::before, *::after {
  box-sizing: border-box;
}

.card {
  width: 300px;       /* итоговая ширина = 300px, включая padding и border */
  padding: 20px;
  border: 2px solid #333;
  margin: 16px;
}

/* пример схлопывания margin */
.section-a {
  margin-bottom: 40px;
}
.section-b {
  margin-top: 24px;
}
/* итоговый отступ между .section-a и .section-b = 40px (max из 40 и 24), а не 64px */

Дополнительные вопросы

  • В каких случаях margin collapsing не происходит?
  • Как display: flex на родителе влияет на схлопывание отступов у детей?
  • Почему border-box считается более предсказуемым выбором по умолчанию?