Модель визуального форматирования

Модель визуального форматирования CSS - это алгоритм, используемый для обработки документа и его визуального отображения. Это базовая концепция CSS. Модель визуального форматирования задаёт трансформацию каждого элемента в документе и создаёт ноль, одну или несколько боксов, согласно боксовой модели CSS. Расположение (layout) каждого бокса определяется:

  • размерами бокса: точно заданными или заданными ограничениями. Если размеры не заданы, это правило игнорируется;
  • типом бокса: inline, inline-level, atomic inline-level, block box;
  • схемой позиционирования: normal flow, float или absolute;
  • другими элементами дерева: дочерними и соседними;
  • размерами и расположением окна просмотра (viewport);
  • внутренними размерами содержащихся изображений;
  • другой внешней информацией.

Бокс отображается относительно краёв содержащего его блока. Как правило, бокс определяет родительский блок для своих потомков. Однако, стоит заметить, что бокс не ограничен содержащим его блоком. Такое поведение слоёв, выходящих за пределы своих содержащих блоков, называется переполнением (overflow).

Генерация бокса

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

Блочные элементы и блок-боксы

Говорят, что элемент является блочным, когда вычисленное значение его CSS-свойства display равно: block, list-item, или table. Блочный элемент визуально форматируется как блок (например, параграф), предназначенный для вертикальной компоновки (в столбик).

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

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

Элемент блочного уровня так же может быть блоком-контейнером. Блок-контейнер - это блок, который содержит либо только другие элементы блочного уровня, либо создаёт контекст инлайнового форматирования и, таким образом, содержит только инлайновые элементы.

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

Элементы блочного уровня, которые так же являются контейнерами, называются блок-боксами.

Анонимные блок-боксы

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

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

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

Пример 1

Возьмём следующий HTML код (со стилями по умолчанию, то есть элементы <div> и <p> имеют значение display:block:

html
<div>
  Some inline text
  <p>followed by a paragraph</p>
  followed by more inline text.
</div>

Здесь создались два анонимных блока: один для текста перед параграфом (Some inline text), и второй для текста после параграфа (followed by more inline text.).

Выглядеть это будет так:

html
Some inline text
followed by a paragraph
followed by more inline text.

В отличие от параграфа <p>, Web разработчик не может напрямую контролировать стили этих двух анонимных боксов. Те свойства, которые наследуются, берут своё значение от элемента <div>, например color, определяющий цвет текста. А другие значения, ненаследуемые, устанавливаются в значение initial. Например, у них не будет своего свойства background-color, он всегда будет в состоянии "прозрачный" (transparent), значении по умолчанию для этого свойства, и поэтому будет видно тот background, который установлен у элемента <div>. А вот для параграфа <p> можно установить своё свойство цвета фона. Таким образом, эти два анонимных бокса будут иметь один и тот же цвет текста.

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

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

Пример 2

Возьмём следующий HTML код, где установим для элемента <p> значение display:inline и для элемента <span> значение display:block:

html
<p>
  Some <em>inline</em> text <span>followed by a paragraph</span> followed by
  more inline text.
</p>

Создадутся два анонимных блок-бокса, один для текста перед элементом span (Some inline text) и один для текста после него (followed by more inline text), и у нас получится вот такая структура:

Выглядеть она будет так:

html
Some inline text followed by a paragraph followed by more inline text.

Элементы инлайн-уровня и инлайн-боксы

Элементы, которые называются элементами инлайн-уровня - это элементы, у которых вычисленное значение CSS-свойства display установлено в : inline, inline-block или inline-table. Визуально они не представляют собой какие-то отдельные блоки, но они они располагаются в одну линию с другим контентом инлайн-уровня. Например, содержание параграфа, с различным форматированием, таким как подчёркивание или картинка, состоит из элементов инлайн-уровня.

Элементы инлайн-уровня создают боксы инлайн-уровня, которые определены как боксы, участвующие в контексте форматирования инлайн-уровня. Inline boxes are both inline-level boxes and boxes, whose contents participate in their container's inline formatting context. This is the case, for example, for all non-replaced boxes with display:inline. Inline-level boxes, whose contents do not participate in an inline formatting context, are called atomic inline-level boxes. These boxes, generated by replaced inline-level elements or by elements with a calculated display value of inline-block or inline-table, are never split into several boxes, as is possible with inline boxes.

Anonymous inline boxes

As for block boxes, there are a few cases where inline boxes are created automatically by the CSS engine. These inline boxes are also anonymous as they cannot be named by selectors; they inherit the value of all inheritable properties, setting it to initial for all others.

The most common case where an anonymous inline box is created, is when some text is found as a direct child of a block box creating an inline formatting context. In that case, this text is included in the largest possible anonymous inline box. Also, space content, which would be removed by the behavior set in the white-space CSS property, does not generate anonymous inline boxes because they would end empty.

Other types of boxes

Line boxes

Line boxes are generated by the inline formatting context to represent a line of text. Inside a block box, a line box extends from one border of the box to the other. When there are floats, the line box starts at the rightmost border of the left floats and ends at the leftmost border of the right floats.

These boxes are technical, and Web authors do not usually have to bother with them.

Run-in boxes

Run-in boxes, defined using display:run-in, are boxes that are either block boxes or inline boxes, depending on the type of the following box. They can be used to create a title that runs inside its first paragraph when possible.

Model-induced boxes

Besides the inline and block formatting contexts, CSS specifies several additional content models that may be applied to elements. These additional models, used to describe specific layouts, may define additional box types:

  • The table content model may create a table wrapper box and a table box, but also specific boxes like caption boxes.
  • The multi-column content model may create column boxes between the container box and the content*.*
  • The experimental grid, or flex-box content models, also create additional types of boxes.

Positioning schemes

Once boxes are generated, the CSS engine needs to position them on the layout. To do that, it uses one of the following algorithms:

  • The normal flow - positions each box one after the other.
  • The floats algorithm - extracts the box from the normal flow and put it to the side of the containing box.
  • The absolute positioning scheme - positions a box within an absolute coordinate system that is established by its containing element. An absolutely positioned element can cover other elements.

Normal flow

In the normal flow, boxes are laid out one after the other. In a block formatting context, they are laid out vertically; in an inline formatting context, they are laid out horizontally. The normal flow is triggered when the CSS position is set to the value static or relative, and if the CSS float is set to the value none.

Floats

In the float positioning scheme, specific boxes (called floating boxes or simply floats) are positioned at the beginning, or end of the current line. This leads to the property that text (and more generally anything within the normal flow) flows along the edge of the floating boxes, except if told differently by the clear CSS property.

The float positioning scheme for a box is selected, by setting the float CSS property on that box to a value different than none and position to static or relative. If float is set to left, the float is positioned at the beginning of the line box. If set to right, the float is positioned at the end of the line box. In either case, the line box is shrunk to fit alongside the float.

Absolute positioning

In the absolute positioning scheme, boxes are entirely removed from the flow and don't interact with it at all. They are positioned relative to their containing block using the top, bottom, left and right CSS properties.

An element is absolutely positioned if the position is set to absolute or fixed.

With a fixed positioned element, the containing block is the viewport. The position of the element is absolute within the viewport. Scrolling does not change the position of the element.