Что такое Box Model в CSS?
Вопрос
Из чего состоит блочная модель (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считается более предсказуемым выбором по умолчанию?