Visual formatting model
The visual formatting model used in RCSS is almost identical to that of CSS, and it is recommended you read that for a detailed explanation of how RmlUi builds and places element boxes. A short summary can be found below.
The differences between CSS and RCSS are:
- The dimensions of the viewport are defined as the dimensions of the context the document is being rendered in.
- The document element (the root) is always absolutely positioned, and can be positioned within its context using
top
,right
,bottom
andleft
. - There are no default styles in RCSS, including for built-in elements such as scrollbars and form controls. Please see the style guide for how to style and size these elements.
- Generated content is not yet supported.
Introduction to the visual formatting model
During document layout, each element generates zero or more boxes. How these boxes are sized and laid out within their document is governed by:
- The box type (either block, for boxes generally laid out top-to-bottom, or inline, for boxes laid out along a line).
- The box size; this could either be derived from intrinsic dimensions for elements such as images and form controls, or specified directly through RCSS properties, or determined by the contents of the box.
- Relationships of the box to other boxes in the document tree, such as floating boxes.
Containing blocks
Every box has a ‘containing block’, a rectangular box with a fixed width and height. The dimensions of this box are used to evaluate such things as relative widths and margins. In general, a box will establish the containing block for its descendant elements, depending on the box’s type.
A box is not necessarily constrained by the dimensions of its containing block, it may overflow along the x- or y-axes.
The containing block of the root document element is set by the dimensions of the document’s context. The document element will generally establish a containing block for its descendants. However, it if does not have a fixed height, the height of the context will be used.
Controlling box generation
Block level elements and block boxes
Block-level elements are those that are formatted as blocks, flowing visually down the document from top to bottom (such as paragraphs). Elements with a display
of block
acts as a block container for its children, as do any absolute
or fixed
positioned elements and floating elements.
Block-level elements generate exactly one block box that itself contains only block boxes. If any inline elements are inside this block box, an anonymous block box is created (one not representing any specific element) to hold and place the inline content. The anonymous block box is positioned with the original block box just like any other block box.
So, while processing the following RML fragment (assuming div
and p
elements are block, and img
elements are inline):
<div>
<div>
</div>
<p>
<img />
</p>
</div>
the first div
would generate a block box. This box would establish the containing block for its descendants. The second div
would generate a block box using the first’s containing block, as would the p
element. The img
element would be placed inside an anonymous block box, which would be positioned within the p
tag and generated with its containing block.
Inline-level elements and inline boxes
Inline-level elements are those elements that do not generate blocks of content, but flow their content into lines contained by a block box. Elements with a display
property of inline
or inline-block
generate inline boxes.
Loose text within elements also generates inline boxes.
The ‘display’ property
display
Value: | inline | block | inline-block | flow-root | flex | inline-flex | table | inline-table | table-row-group | table-row | table-column-group | table-column | table-cell | none |
Initial: | inline |
Applies to: | all elements |
Inherited: | no |
Percentages: | N/A |
The values have the following meanings:
block
- This element generates a block box.
inline
- This element generates one or more inline boxes.
inline-block
- This element generates a block container for its descendants, but participates in inline layout itself. This is similar to the behavior of replaced elements (those with intrinsic widths).
flow-root
- This element generates a block box, and always establishes a new block formatting context. This is useful for example to ensure floated children are completely contained within this element.
flex, inline-flex
- This element generates a flex container, and all its children are formatted as flex items, see flexbox layout for details.
table, inline-table, table-row-group, table-row, table-column-group, table-column, table-cell
- These values are used for defining and structuring tables.
none
- This element (including all descendants) generates no boxes, and is not displayed. This implies that the element will not affect layout. The
visibility
property can be used to make an element affect layout but not be rendered.
These values all correspond to the ones available for the CSS display property.
Positioning schemes
RCSS can position elements according to three schemes:
- Normal flow, which includes placement of block boxes, the flowing of inline boxes and relative positioning of either.
- Floats. Floating elements are placed as normal, then shifted as far to the left or right as possible within their containing block. Inline content is then flowed around floating boxes.
- Absolute positioning. Elements that are positioned with
absolute
orfixed
are removed from the normal flow (therefore having no impact on the layout of other elements) and placed at an explicit location relative to their containing block.
Choosing a positioning scheme: ‘position’ property
position
Value: | static | relative | absolute | fixed |
Initial: | static |
Applies to: | all elements |
Inherited: | no |
Percentages: | N/A |
The values have the following meanings:
static
- The element generates boxes that are positioned according to normal flow.
relative
- The element generates boxes that are positioned according to normal flow, but then offset according to the values of the
top
,right
,bottom
andleft
properties. Other elements are positioned as though the box was in its original location. absolute
- The element generates a block box that is removed from normal flow. The
top
,right
,bottom
andleft
properties will position the box relative to the edges of its containing block. fixed
- The element is positioned like an
absolute
box, but will not scroll along with other content if it is within an overflowing box.
Note that, a limitation in RmlUi is that positioned elements (i.e. any value other than static
) do not affect when clipping is applied to the element. For example, an element with overflow: hidden
will not clip an absolutely positioned child, unless its in-flow content overflows. Instead, one can use the clip: always
property together with overflow: hidden
to force clipping to occur.
Box offsets: ‘top’, ‘right’, ‘bottom’, ‘left’
top
, bottom
Value: | auto | <length> | <percentage> |
Initial: | auto |
Applies to: | positioned elements |
Inherited: | no |
Percentages: | relative to the height of the containing block |
left
, right
Value: | auto | <length> | <percentage> |
Initial: | auto |
Applies to: | positioned elements |
Inherited: | no |
Percentages: | relative to the width of the containing block |
The values have the following meanings:
auto
- Behavior depends on other related properties. For absolutely positioned elements, may adjust position or size to align the box with the containing block.
<length>
- The edge is offset a fixed distance from the reference edge.
<percentage>
- The edge is offset from the reference edge a distance relative to the dimensions of the containing block.
Normal flow
Block formatting
Certain elements establish a new block formatting context for their content, including the document element, floats, absolutely positioned elements, scroll containers, and elements with display: flow-root
.
In a block formatting context, boxes are laid out vertically one after the other. The bottom edge of a block box will touch the top edge of the block box following it. The left edge of a block box will touch the left edge of its containing block. Block elements do not themselves flow around floating elements, but their inline content will.
Inline formatting
Inline boxes are positioned horizontally on a line, one after the other, from the top of the containing block. Horizontal padding, borders and margins are respected when positioning the boxes. Inline boxes on a single line are said to be laid out in a line box.
Each line box is generally the same width as its containing block, with its left edge touching the left edge of the containing block and its right edge touching the right edge of the containing block. However, floating elements may force a line box to be shorter along one or both of its edges. The height of a line box is governed by the height of the box’s inline content. Inline boxes are positioned vertically within the line box using the vertical-align
property.
If inline boxes cannot fit horizontally onto a single line box, they are flowed into new vertically-stacked line boxes.
The text-align
property governs how the excess horizontal space between the widths of the inline boxes and the width of the line box is distributed.
Inline boxes may be split across several line boxes. When this occurs, any horizontal margins, borders and padding will only be present at the beginning and end of the inline box, not on each line.
Relative positioning
Once a block or inline box has been positioned, it can be moved from its location if its position
is set to relative
. It is offset from its position using the top
, right
, bottom
and left
properties. Note that it affects the positioning of further elements from its original location, not its new one.
Floats
A float is a box that is shifted horizontally to the left or right edge of its containing block. They do not affect placement of further block boxes, however line boxes will be shortened to avoid running over them. In this way, inline content will be flowed around them. Block boxes can be forced vertically past floating boxes using the clear
property.
Floated elements only affect the placement of other elements within the same block formatting context.
See the CSS2 documentation on floating elements for a description on the full float model, and interesting uses of floats.
Positioning the float: the ‘float’ property
float
Value: | left | right | none |
Initial: | none |
Applies to: | all |
Inherited: | no |
Percentages: | N/A |
The values of this property have the following meanings:
left
- The element generates a block box that is floated to the left.
right
- The element generates a block box that is floated to the right.
none
- The element’s boxes are not floated.
Controlling flow next to floats: the ‘clear’ property
clear
Value: | left | right | both | none |
Initial: | none |
Applies to: | block-level elements |
Inherited: | no |
Percentages: | N/A |
The values of this property have the following meanings:
left
- The box’s position is pushed far enough vertically so its top edge is below the bottom edge of all previously placed left-floating elements.
right
- The box’s position is pushed far enough vertically so its top edge is below the bottom edge of all previously placed right-floating elements.
both
- The box’s position is pushed far enough vertically so its top edge is below the bottom edge of all previously placed floating elements.
none
- The box’s position is placed irrespective of floating elements.
Floating boxes themselves can be cleared.
Absolute positioning
An absolutely positioned box (one with a position
of absolute
or fixed
) is explicitly offset from the edges of its containing block. Floating boxes are ignored when laying out its inline content.
Note that in RCSS, fixed
positioned boxes are not placed relative to the viewport, but identically to absolute
boxes.
Layered presentation
Each box has a stacking level within a single stacking context. Boxes within a stacking context are rendered in stacking level order, from lowest to highest (so boxes with the highest stacking level will appear on top). All the boxes within a single stacking context are rendered at once; they will not intermingle rendering with the members of another stacking context.
The root element of a document establishes a stacking context for its descendants. Other elements within a document may establish local stacking contexts of their own. An element which does so has two stacking levels; one within the stacking context it is a member of (given by the z-index
property) and another inside the stacking context it establishes (always ‘0’).
Specifying the stacking level: the ‘z-index’ property
z-index
Value: | <number> | auto |
Initial: | auto |
Applies to: | all elements |
Inherited: | no |
Percentages: | N/A |
Values have the following meanings:
<number>
- The number is the stack level within the current stacking context. It also establishes a local stacking context in which its own stack level is ‘0’.
auto
- The stack level of the box is the same as its parent’s. It does not establish a local stacking context.
Note that in RCSS any element can have the z-index property, not just positioned elements.