Что такое блочная модель CSS и как она работает?

Что такое блочная модель CSS и как она работает?
Содержание:
  1. Как отображаются элементы на странице?
  2. Блочная модель
  3. Альтернативная блочная модель
  4. Блочные элементы
  5. Схлопывание внешних отступов по вертикали
  6. Строчные элементы
  7. Строчно-блочные элементы
  8. Комментарии

В этом статье мы узнаем из чего внешне состоят элементы, и как они отображаются на странице. Изучим как обычную, так и альтернативную блочную модель CSS. Кроме этого рассмотрим основные типы отображений элементов такие как блочный и строчный.

Как отображаются элементы на странице?

Как вы уже знаете, любая веб-страница состоит из элементов. Но как они отображаются на экране?

Веб-страницы визуально представляет собой ничто иное, как набор прямоугольных блоков

Правильно, в виде прямоугольников. В результате, страница представляет собой визуально ничто иное, как просто набор прямоугольных блоков, расположенных рядом, сверху, снизу и внутри друг друга.

Но, браузеру чтобы нарисовать эти прямоугольники, необходимо знать их размеры. Их расчёт выполняется в соответствии с алгоритмом, который в CSS называется блочной моделью (box model).

Блочная модель

Блочная модель CSS описывает устройство внешнего вида элемента и его расположение на странице.

Представить себе эту модель можно в виде прямоугольных коробок вложенных друг в друга по типу матрешки. Самая большая из них – это внешние отступы (margin). Затем идёт рамка (border). Далее – внутренние отступы (padding), и самая последняя из них – это содержимое (content).

Блочная модель CSS

Содержимое – это область, в которой отображается контент элемента. Его размерами при необходимости можно управлять с помощью CSS-свойств width (ширина) и height (высота). Кроме них имеются ещё следующие: min-width (минимальная ширина), max-width (максимальная ширина), min-height (минимальная высота) и max-height (максимальная высота). При этом задавать размеры можно с помощью различных единиц измерения: px, rem, %, vw и так далее.

Ширина и высота контентной области HTML-элемента

Внутренние отступы (padding) распологаются вокруг содержимого в виде пустого пространства. Их можно установить как все сразу с помощью свойства padding, так и по отдельности для разных сторон (padding-left, padding-right, padding-top и padding-bottom). С помощью этих свойств задаётся отступ между содержимым и границей элемента:

CSS
.box {
  padding: 15px; /* со всех сторон */
  padding: 10px 15px; /* 10px – сверху и снизу, 15px – слева и справа */
  padding: 5px 10px 15px; /* 5px – сверху, 10px – слева и справа, 15px – снизу */
  padding: 5px 10px 15px 20px; /* 5px – сверху, 10px – справа, 15px – снизу, 20px – слева */
  padding-top: 5px; /* сверху */
  padding-right: 10px; /* справа */
  padding-bottom: 15px; /* снизу */
  padding-left: 20px; /* слева */
}

Рамка (border) позволяет нам установить цвет, толщину и тип линии границы, которую нужно нарисовать вокруг внутренних отступов (padding). Для этого можно использовать как сокращённое свойство border, так и отдельные: border-width, border-color и border-style.

CSS
.box {
  border: 3px solid #000;
  /* тоже самое только с помощью отдельных свойств */
  border-width: 3px; /* толщина рамки */
  border-style: solid; /* стиль линии */
  border-color: #000; /* цвет */
}

Область элемента заканчивается рамкой и не распространяется за её пределы. Внешний отступ (margin) не участвует напрямую в фактическом расчёте размера элемента и не занимает место внутри него.

В результате общие размеры элемента в CSS складываются из ширины и высоты контентной области, padding и border:

Общая ширина и высота HTML-элемента

Допустим, у нас имеется элемент к которому применены следующие стили:

CSS
.box {
  display: block;
  width: 300px;
  height: 200px;
  margin: 20px;
  padding: 15px;
  border: 5px solid black;
}
Блочная модель CSS на конкретном примере

Таким образом:

  • ширина – 340px, где: 300px (ширина контентной области) + 15px (padding-left) + 15px (padding-right) + 5px (border-left-width) + 5px (border-right-width);
  • высота – 240px, где: 200px (высота контентной области) + 15px (padding-top) + 15px (padding-bottom) + 5px (border-top-width) + 5px (border-bottom-width).
Свойства блочной модели в CSS

Здесь:

  • border-left-width – толщина левой границы рамки;
  • border-right-width – толщина правой границы рамки;
  • border-top-width – толщина верхней границы рамки;
  • border-bottom-width – толщина нижней границы рамки.

Внешний отступ (margin) определяет область вокруг границы элемента и может влиять на его размеры лишь косвенно. Он используется для создания отступов между элементами и управлением их расположением на странице.

Альтернативная блочная модель

Блочную модель, приведённую выше, очень не удобно использовать при веб-разработке. Так как нам проще оперировать общими размерами элементов, а не вычислять их каждый раз, складывая width и height с padding и border.

Поэтому в CSS была добавлена ещё одна блочная модель – альтернативная. В отличие от дефолтной, в ней мы с помощью width и height устанавливаем уже общие размеры элементам, а не контентной области. Ширина и высота контентной области в этом случае вычисляется исходя из общих размеров. То есть: width (height) - border - padding.

Альтернативная блочная модель в CSS

В большинстве случаев веб-разработчики перед началом написания стилей устанавливают сразу всем элементам, в том числе псевдоэлементам ::after и ::before, альтернативный способ расчёта размеров. Для этого они в самом начале CSS-кода прописывают следующее правило:

CSS
*,
*::before,
*::after {
  box-sizing: border-box;
}

Это же правило использует самый популярный в мире CSS-фреймворк Bootstrap для установки всем элементам на странице альтернативный способ расчёта их размеров.

Осуществляется это как вы уже поняли с помощью CSS-свойства box-sizing. Для этого ему в качестве значения нужно указать border-box. По умолчанию данное свойство имеет значение content-box, что соответствует расчёту общей ширины и высоты элемента по дефолтной модели CSS.

Теперь свойства width, height, min-width, min-height, max-width и max-height будут задавать именно общие размеры элементам.

Рассмотрим пример, в котором некоторый контейнер .container содержит два элемента .border-box и .content-box. Этим элементам назначены одинаковые свойства width, height, padding, border и margin. Единственное различие между ними в том, что второму элементу установлен альтернативный способ расчёта ширины с помощью свойства box-sizing:

HTML
<style>
  .border-box, .content-box {
    border: 10px solid #8d6e63;
    background-color: #d7ccc8;
    padding: 25px;
    margin: 50px;
    width: 300px;
    height: 200px;
  }
  
  .border-box {
    box-sizing: border-box;
  }
</style>

<div class="container">
  <div class="content-box"></div>
  <div class="border-box"></div>
</div>

Что нужно прописать для .border-box чтобы его размеры были такими же, как у первого элемента (.content-box)?

Правильно, установить свойствам width и height этого элемента соответственно общую ширину и высоту .content-box:

CSS
.border-box {
  box-sizing: border-box;
  width: 370px;
  height: 270px;
}

Блочные элементы

Сейчас, в HTML5, нет деления элементов на строчные и блочные. При написании HTML-документа, каждый элемент в нём нужно использовать в соответствии с его предназначением (смыслом), а не потому что он по умолчанию выглядет тем или иным образом на экране.

Таким образом, когда сейчас говорят, что элемент является блочным или строчным, то подразумевают под этим именно то, как он отображается на экране. То есть его стилевое оформление в CSS.

Свойством CSS, с помощью которого определяется как элемент будет отображаться на экране, является display.

Упрощённо в CSS можно выделить элементы с блочным (display: block), строчным (display: inline) и строчно-блочным (display: inline-block) отображением.

Элементы с display: block полностью соответствуют блочной модели CSS и ведут себя следующим образом:

  • всегда начинаются с новой строки;
  • по умолчанию занимают всю доступную ширину родительского элемента;
  • CSS-свойства width и height измененяют их размеры;
  • padding, border и margin, установленные для элемента отодвигают от него другие элементы на расстояние, соответствующее их значениям.

Рассмотрим пример. Для этого создадим три элемента <div> со следующими стилями:

HTML
<style>
  .box-1 {
    width: 80px;
    margin: 5px;
    padding: 5px;
    border: 1px solid #8bc34a;
    background-color: #c5e1a5;
  }

  .box-2 {
    width: 70px;
    margin: 5px;
    padding: 5px;
    border: 1px solid #03a9f4;
    background-color: #81d4fa;
  }

  .box-3 {
    margin: 5px;
    padding: 5px;
    border: 1px solid #ba68c8;
    background-color: #e1bee7;
  }
</style>

<body>
  <div class="box-1">80 x auto</div>
  <div class="box-2">70 x auto</div>
  <div class="box-3">auto x auto</div>
Из чего складывается итоговая ширина блока

Элементам <div> мы не стали явно прописывать display: block, так как эти стили <div> имеет уже по умолчанию. Они заданы им на уровне браузера.

Стили для div, прописанные в user agent

Элементам .box-1 и .box-2 мы явно установили ширину, чтобы показать специфику элементов с блочным отображением. То есть, несмотря на то , что после .box-1 достаточно места для .box-2, он разместился на новой строке. В этом суть элементов с display: block, они всегда начинаются с новой строки.

Элементу .box-3 мы не стали явно задавать ширину. В результате, он занял всю доступную ширину области контента родительского элемента. Это поведение элементы с display: block имеет по умолчанию.

Свойство width, в данном случае, имеет своё начальное значение auto. Оно означает, что браузеру необходимо автоматически расчитать ширину элемента исходя из доступной ширины родительского элемента.

При этом это значение не всегда равно 100% даже для элемента, которому установлен box-sizing: border-box. Так как элемент может содержать margin и в этом случае его внешняя ширина (с учётом внешних отступов) превысит доступную ширину контнетной области родительского элемента и выйдет за её пределы:

HTML
<style>
  .row {
    width: 100%;
    margin-left: 50px;
  }
</style>

<div class="container">
  <div class="row"></div>
</div>
Элемент вышел за пределы контентной области рдительского элемента

Здесь показано как .row выйдет за пределы ширины области содержимого .container. Его ширина в этом случае будет 100% + 50px.

Если изменить width: 100% на width: auto для .row, то ширина этого элемента будет вычислена браузером так, чтобы он занял всю доступную ширину родителя. В данном случае это будет 100% - 50px.

По умолчанию высота элемента с display: block вычисляется браузером автоматически исходя из его содержимого таким образом, чтобы показать весь его контент:

CSS
.box {
  padding: 15px;
  border: 1px solid #ffeb3b;
  background-color: #fff59d;
}
Из чего складывается итоговая ширина блока

В этом примере height имеет своё начальное значение auto. При явной установке высоты элементу, содержимое которое не поместилось в его контентную область будет переполнять этот блок и по умолчанию выходить за его пределы:

CSS
.box {
  height: 180px;
  padding: 15px;
  border: 1px solid #ffeb3b;
  background-color: #fff59d;
}
Из чего складывается итоговая ширина блока

Явная установка ширины (width) и высоты (height) не является хорошей практикой, так как это может привести к различным проблемам, особенно при создании адаптивных и отзывчивых веб-дизайнов.

В содержимое элементов с display: block может помещать любые другие элементы.

На элементы с display: block не действуют свойства, предназначенные, например, специально для элементов с display: inline. Например, vertical-align.

Схлопывание внешних отступов по вертикали

Ещё очень важным моментом в CSS является такой алгоритм как схлопывание вертикальных margin. В результате они объединяются в один отступ, размер которого равен наибольшему из них. Горизонтальных margin это не касается.

Схлопывание внешних отступов происходит в следующих случаях:

  • соседних элементов, имеющих одного родителя;
  • родителя и его первого (последнего) дочернего элемента;
  • пустого блока.

Рассмотрим примеры схлопывания вертикальных margin.

1. Два срседних элемента отодвигаются друг от друга по вертикали с помощью margin:

HTML
<style>
  .row {
    min-height: 50px;
    margin-bottom: 15px;
  }
  
  .row-2 {
    min-height: 50px;
    margin-top: 30px;
  } 
</style>

<div class="container">
  <div class="row-1"></div>
  <div class="row-2"></div>
</div>

В результате вертикальное расстояние между .row-1 и .row-2 будет 30px, а не 45px (15px + 30px). Так как в CSS вертикальные margin схлопываются и расстояние между блоками определяется по максимальному значению. В данном случае – это 30px.

Схлопывание вертикальных margin

2. Схлопывание margin родителя и его первого дочернего элемента:

HTML
<style>
  .container {
    min-height: 30px;
    background-color: #673ab7;
  }

  .row {
    margin-top: 20px;
    min-height: 50px;
    background-color: #8bc34a;
  }
</style>

<div class="container"></div>

<div class="container">
  <div class="row"></div>
</div>

В этом примере верхние внешние отступы родителя и его первого дочернего элемента соприкасаются и в результате схлопываются. Это происходит потому у родителя отстутствует верхние border и padding.

Из двух схлопывающихся margin, максимальное значение имеет .row, он равен 20px. У родителя margin явно не задан и, следовательно, он по умолчанию – 0. В итоге, схлопнутый margin будет заканчиваться за пределами родительского элемента и отодвигать от себя вверх другой элемент на 20px. Этот алгоритм ещё называют «выпадением» margin из родительского элемента.

Схлопывание внешних margin родителя и его первого дочернего элемента

3. Схлопывание нижнего и верхнего margin пустого блока .empty:

HTML
<style>
  .row-top {
    margin-bottom: 20px;
    min-height: 15px;
    background-color: #673ab7;
  }

  .empty {
    margin-top: 20px;
    margin-bottom: 20px;
  }

  .row-bottom {
    margin-top: 20px;
    min-height: 15px;
    background-color: #7CB342;
  }
</style>

<div class="container">
  <div class="row-top"></div>
  <div class="empty"></div>
  <div class="row-bottom"></div>
</div>

В этом примере элемент .empty является пустым блоком, так как у него отсутствует то, чтобы разделяло его верхний и нижний margin. У .empty нет border, padding, контента, height или min-height.

В результате у него соприкасаются верхний и нижний margin и они схлопываются.

Схлопывание вертикальных margin пустого блока

Строчные элементы

В отличие от display: block, элементы со строчным отображением (display: inline) соотвествуют блочной модели только частично.

1. Элементы со строчным отображением распологаются последовательно друг за другом в одной строке. То есть на той же строке, что и предыдущий элемент.

Если какой-то текст не помещается на строке, то он переносится на новую. Разделение текста на несколько строк, по умолчанию происходит в месте пробела.

2. Им нельзя напрямую установить ширину (width) и высоту (height), так как их размеры определяются в соотвествии с содержимым. Если эти свойства назначить элементам, то они будут просто проигнорированы.

3. Элементам со строчным отображением можно установить margin, padding и border. Но отодвигать другие элементы с display: inline они будут только по горизонтали. По вертикали это происходить не будет. То есть, например, с margin-top и margin-bottom отодвинуть другие элементы со строчным отображением у нас не получится.

Элементы с display: inline в основном используются для стилизации, помещенного в них текста, или в качестве контейнера для помещения в них других элементов со строчным отоборажением.

По умолчанию в браузере display: inline, например, имеют следующие элементы: <a>, <span>, <em>, <strong> и так далее.

Строчно-блочные элементы

Элементы со строчно-блочным отображением (display: inline-block) сочетают в себе особенности строчных и блочных элементов.

Как это? Очень просто, так как у элемента кроме внешнего отображения имеется ещё внутреннее. В данном случае он внешне будет вести себя как display: inline, а внутренне отображаться как display: block.

То есть его размер также как элемента с display: inline по умолчанию будет определяться в соответствии с его содержимым, он будет распологаться на той же строке и переноситься на новую только по мере необходимости. Но в тоже время он внутренне будет являться блоком и мы можем устанавливать ему width, height, margin, border и padding как элементу с display:block.

По умолчанию в браузере следующие элементы имеют display: inline-block: <button>, <input>, <textarea> и <select>.

В CSS кроме inline, block и inline-block имеется ещё много других способов отображения элементов, но эти являются самыми основными.

Например, для создания разметки сейчас очень часто используют такие значения display как flex, grid, inline-flex и inline-grid.

Эти свойства чем-то похожи на display: inline-block. Они также имеют внутреннее и внешнее отображение. Например, элементы с display: flex и display: inline-flex свои непосредственные дочерние элементы размещают в соотвествии с алгоритмом Flexbox. Это будет их внутреннее отображение. Но, внешне они ведут себя как block или inline.

Точно также работают гриды. Элемент с display: grid внешне ведёт себя как display: block, а display: inline-grid – как display: inline. Но внутренне их отображение соотвествует алгоритму Grid.

Комментарии: 0