Статьи

Понимание контекста блочного форматирования в CSS

Контекст форматирования блока — это часть визуального CSS-рендеринга веб-страницы, в которой расположены блочные блоки. Схема позиционирования, к которой он принадлежит, является нормальным потоком . Согласно W3C :

Поплавки, абсолютно позиционированные элементы, встроенные блоки, ячейки таблиц, заголовки таблиц и элементы с «переполнением», отличным от «видимого» (кроме случаев, когда это значение было передано в область просмотра), устанавливают новые контексты форматирования блоков.

Приведенная выше цитата в значительной степени подводит итог того, как формируется контекст форматирования блока. Но давайте переопределим его так, чтобы его было легче понять. Контекст форматирования блока — это HTML-блок, который удовлетворяет как минимум одному из следующих условий:

  • Значение с float не равно
  • Значение position является ни static ни relative
  • Значением display является table-cell table-caption , inline-block , flex или inline-flex
  • Значение overflow не visible .

Создание контекста форматирования блока

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

Например, посмотрите на следующий HTML:

 <div class="container"> Some Content here </div> 

Новый контекст форматирования блока можно создать, добавив в контейнер любое из необходимых условий CSS, таких как overflow: scroll , overflow: hidden , display: flex , float: left или display: table . Хотя любое из вышеупомянутых условий может создать контекст блочного форматирования, также будут некоторые другие эффекты, такие как:

  • display: table может создавать проблемы в отзывчивости
  • overflow: scroll может показывать нежелательные полосы прокрутки
  • float: left будет перемещать элемент влево, а другие элементы будут обтекать его
  • overflow: hidden будет обрезать элементы, которые переполнены

Поэтому всякий раз, когда мы создаем новый контекст форматирования блока, мы выбираем наилучшее условие на основе наших требований. Для единообразия я использовал overflow: hidden во всех примерах, приведенных в этой статье.

 .container { overflow: hidden; } 

Вы можете свободно играть с объявлениями, отличными от overflow: hidden .

Выравнивание блоков в контексте блочного форматирования

Спецификация W3C гласит:

В контексте форматирования блока левый внешний край каждого блока касается левого края содержащего блока (для форматирования справа налево касание правого края). Это верно даже при наличии float (хотя линейные блоки блока могут уменьшаться из-за float), если только блок не устанавливает новый контекст форматирования блока (в этом случае сам блок может стать более узким из-за float).

выравнивание

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

Контекст форматирования блока вызывает сужение полей

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

Давайте рассмотрим пример, чтобы понять это.

рушится поля

На приведенной выше диаграмме мы рассматриваем созданный контекст форматирования блока, где красное поле ( div ) содержит два зеленых элемента ( p элемента).

 <div class="container"> <p>Sibling 1</p> <p>Sibling 2</p> </div> 

И соответствующий CSS это:

 .container { background-color: red; overflow: hidden; /* creates a block formatting context */ } p { background-color: lightgreen; margin: 10px 0; } 

В идеале поле между двумя братьями и сестрами должно быть суммой полей обоих элементов (20 пикселей), но на самом деле это 10 пикселей. Это известно как сокращение полей . В случае, если поля братьев и сестер различны, тогда преобладает более высокая маржа.

Использование контекста форматирования блока для предотвращения срыва полей

Поначалу это может показаться немного запутанным, поскольку мы обсуждали выше, что контексты форматирования блоков вызывают коллапс полей. Но нужно помнить одну вещь: вертикальные поля между соседними блочными блоками (родными братьями) разрушаются, только если они находятся в одном и том же контексте форматирования блока. Если они принадлежат к различным контекстам форматирования блоков, то поля между ними не будут разрушаться. Таким образом, создав новый контекст форматирования блока, мы можем предотвратить падение полей.

Давайте добавим третьего брата в более раннем примере, поэтому HTML становится:

 <div class="container"> <p>Sibling 1</p> <p>Sibling 2</p> <p>Sibling 3</p> </div> 

С соответствующим CSS:

 .container { background-color: red; overflow: hidden; /* creates a block formatting context */ } p { background-color: lightgreen; margin: 10px 0; } 

Результат будет таким же, как указано выше, то есть произойдет коллапс, и три родных брата будут разделены вертикальным расстоянием 10 пикселей. Это происходит потому, что все три тега p являются частью одного контекста форматирования блока.

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

 <div class="container"> <p>Sibling 1</p> <p>Sibling 2</p> <div class="newBFC"> <p>Sibling 3</p> </div> </div> 

И CSS:

 .container { background-color: red; overflow: hidden; /* creates a block formatting context */ } p { margin: 10px 0; background-color: lightgreen; } .newBFC { overflow: hidden; /* creates new block formatting context */ } 

Теперь будет разница в выводе:

предотвращение обвала маржи

Поскольку вторые и третьи братья и сестры принадлежат к разным контекстам форматирования, между ними не будет разрыва полей, как показано в следующей демонстрации.

Использование контекста форматирования блока для размещения чисел с плавающей запятой

Контекст форматирования блока может содержать числа с плавающей точкой. Много раз мы сталкивались с ситуацией, когда в контейнере всплывали элементы. В этом случае элемент контейнера не имеет высоты, а его плавающие дочерние элементы находятся вне нормального потока страницы. Для решения этой проблемы мы обычно используем четкое исправление , при этом наиболее популярным методом является использование «очищенного» псевдоэлемента. Но мы также можем достичь этого путем определения контекста форматирования блока.

содержащие поплавки

Давайте посмотрим на пример:

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

С помощью CSS:

 .container { background-color: green; } .container div { float: left; background-color: lightgreen; margin: 10px; } 

В приведенном выше случае контейнер не будет иметь никакой высоты и не будет содержать плавающих дочерних элементов. Чтобы решить эту проблему, мы устанавливаем новый контекст форматирования блока внутри контейнера, добавляя overflow: hidden . Модифицированный CSS становится:

 .container { overflow: hidden; /* creates block formatting context */ background-color: green; } .container div { float: left; background-color: lightgreen; margin: 10px; } 

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

Использование контекста форматирования блока для предотвращения переноса текста

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

Предотвращение переноса текста вокруг поплавков

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

Модель поплавка

HTML-код для диаграммы можно принять как:

 <div class="container"> <div class="floated"> Floated div </div> <p> Quae hic ut ab perferendis sit quod architecto, dolor debitis quam rem provident aspernatur tempora expedita. </p> </div> 

Вся черная область на приведенной выше диаграмме обозначает элемент p . Как мы видим, элемент p не смещается, а проходит под плавающим элементом. Строковые блоки элемента p (относящиеся к строкам текста) претерпевают сдвиг. Следовательно, линейные блоки сужаются горизонтально, чтобы освободить место для плавающего элемента.

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

Если мы сможем сдвинуть весь элемент p , то эта проблема переноса будет решена.

Прежде чем перейти к решению, давайте еще раз вспомним, что говорится в спецификации W3C:

В контексте форматирования блока левый внешний край каждого блока касается левого края содержащего блока (для форматирования справа налево касание правого края). Это верно даже при наличии float (хотя линейные блоки блока могут уменьшаться из-за float), если только блок не устанавливает новый контекст форматирования блока (в этом случае сам блок может стать более узким из-за float).

В соответствии с этим, если элемент p устанавливает новый контекст форматирования блока, он больше не будет касаться левого края блока контейнера. Это может быть достигнуто простым добавлением overflow: hidden для элемента p . Таким образом, создание нового контекста форматирования блока решает проблему обтекания текста вокруг плавающего объекта.

Использование контекстов форматирования блоков в многостолбцовых макетах

Если мы создаем многостолбцовый макет, охватывающий всю ширину контейнера, в некоторых браузерах последний столбец иногда будет переходить на следующую строку. Это может произойти из-за того, что браузер округляет ширину столбца, а общая ширина становится больше, чем у контейнера. Однако если мы установим новый контекст форматирования блока в столбце макета, он всегда будет занимать оставшееся пространство, оставшееся после заполнения предыдущих столбцов.

Давайте используем пример многостолбцовой раскладки с 3 колонками:

Вот HTML-код:

 <div class="container"> <div class="column">column 1</div> <div class="column">column 2</div> <div class="column">column 3</div> </div> 

И CSS:

 .column { width: 31.33%; background-color: green; float: left; margin: 0 1%; } /* Establishing a new block formatting context in the last column */ .column:last-child { float: none; overflow: hidden; } 

Результат в демонстрации CodePen:

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

Вывод

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

Если вам есть что добавить, сообщите нам об этом в комментариях. И не забудьте ознакомиться с более подробным обсуждением этой темы в W3C, если хотите углубиться.