David's Inline Box Model

This is an explanation and a proposal for clarification and modification of the CSS2 inline box model. It is more than just an explanation of CSS2's model, since it incorporates a number of changes that I have proposed.

This document is needs some more illustrated examples. Hopefully I'll make some soon.

This document makes no attempt (yet) to cover the formatting of marker boxes or compact elements or deal with bidirectionality.

Previous versions:


Inline elements

There are two types of inline elements: replaced inline elements and non-replaced inline elements. In general, non-replaced elements are those whose content is contained in the document, whereas replaced-elements are those whose content is outside of the document. For example, in the code:

Visit the <a href="http://www.w3.org/">World
Wide Web Consortium</a> to learn about...

the content of the a element is "World Wide Web Consortium". Replaced elements are those where the content comes from some external source, for example, an object or img element.

However, as far as the inline box model is concerned, the definitions are as described above except that elements with display types inline-table and inline-block (the latter is a proposed type for CSS3 to accommodate form elements) are considered replaced elements.

Box properties on inline elements

Replaced inline elements

The box properties (margin, padding, and border properties) on inline replaced elements are handled just like box properties on block-level elements. The content height and width are determined by the height and width properties (which may be auto), and the padding, border, and margin are placed outside of the content. For inline replaced elements, the only edge relevant to the inline box model is the margin edge (the outside edge of the margin).

Non-replaced inline elements

Inline non-replaced elements are treated quite differently. The content width of an inline non-replaced element is the width required by its content (which is affected by the font properties and also word-spacing, letter-spacing, which in turn are affected by whether text-align is justify or not). The width property has no effect. The horizontal margin, border, and padding are placed to the left of the beginning of the inline element and to the right of the end, but have no effect at line breaks.

Heights of inline elements are more complicated. For the purposes of the box properties, the font height is used. The vertical padding and border are placed outside the font edge. If the inline element is broken over lines, they occur on every line. However, they have no effect on the layout of the inline elements. (Since the vertical box properties have no effect on the layout of the elements, the vertical margin properties have no effect at all.) The logical height of an inline element will be discussed later.

The line-height property

The line-height property specifies the logical height of an inline element. This is the height used in the vertical alignment of inline elements and the construction of line boxes. [NOTE: Should it instead be said that (line-height - font-size) is the leading? This makes a difference when multiple fonts are mixed because the first font does not have sufficient characters. I think it would be far superior since it would prevent potential overlap or narrowing of spaces between lines because of one or two glyphs. But is it too complex? It also makes a difference when the font height is not the font-size.]

The line-height property takes four types of values (other than inherit): normal, <length>, <number>, and <percentage>, as described in CSS2. <length> and <percentage> values have computed values that are lengths, and therefore the computed values inherit as lengths. Therefore, they are dangerous on any element whose descendants have a different font size. <number> and normal values have computed values that are scaling factors, and therefore inherit as scaling factors that are multiplied by the font-size when used in calculations. They are therefore safe. [NOTE: Should normal be considered to be a computed value so that it can vary by font, using information provided in the font metrics?] [NOTE: Should percentages and scaling factors be based on the computed font size, the actual font size (of the first font in the font set or a combination?), or the actual max-ascent to max-descent (of the first...?), i.e., the font height?]

Computing the heights and edges of a non-replaced inline box

There are five important horizontal lines in the box generated by a non-replaced inline element: the logical top, the font top, the baseline, the font bottom, and the logical bottom. This section explains how to compute the relative positions of these five lines. The distance from the font top to the font bottom (i.e., between the font edges) is called the font height, and the distance from the logical top to the logical bottom (i.e., between the logical edges) is called the logical height. (The logical height is given by the line-height property.)

Image showing the five lines of an inline box
An inline box.

Many non-replaced inline elements contain text. In some cases that text is a child of the inline element itself, whereas in others, the text is contained within other descendant inline boxes. (In a DOM sense, the former case is when the text nodes are children of the inline box and the latter is when the text nodes are descendants but not children.) When the inline element has text nodes as children, the metrics of all the fonts used to set the child text nodes determine the font height and font edges of the inline box, as described below. (Note that multiple fonts are used only when the first font in the font set does not contain all the glyphs needed.) When the inline element does not have text nodes as children, the metrics of the first font in the font set (i.e., the first font that would be tested for the presence of a character) are used instead.

The metrics of every font specify a baseline, a max-ascent (largest distance a character extends above the baseline), and a max-descent (largest distance a character extends below the baseline). [NOTE: Are the latter two the correct terms? Note also that I'm basing this section on my (possibly incorrect) assumption that if a font that claims to be 12pt has a max-ascent to max-descent of 14pt, the font metrics say where the glyphs go in a 14pt box but not in a 12pt box.] The font bottom of an inline box is below the baseline, separated from the baseline by the largest max-descent of the relevant fonts. (The relevant fonts, as noted above, are either those actually used or the first font in the font set.) The font top of an inline box is above the baseline, separated from the baseline by the largest max-ascent of the relevant fonts. [NOTE: Note that some people (a minority), myself included, believe that the distance between the max-ascent and max-descent for any given font should be the font-size. However, many interfaces for using scalable fonts do not behave this way.]

Image showing a font box with two fonts
Construction of the font box when two fonts are present.

The difference between the logical height and the font height is called the leading. (The leading is negative when the font height is larger than the logical height.) This leading is distributed equally on both sides of the font height. That is, the logical top and the logical bottom are placed so that the midpoint (midline?) between them is the same is the midpoint (midline?) between the font top and the font bottom. Half the leading is called the half-leading. The logical top is above the font top by a distance of the half-leading, and the logical bottom is below the font bottom by the same distance. (If the half-leading is negative, then the above/below relationships are reversed.)

Note that anonymous inline boxes are no exception to these rules. They have a baseline, and their font edges are determined by only the fonts used for the anonymous text within them (or the first font in the font set), not the text contained within inline elements that they contain. Note also that their logical height is determined by the line-height property (of the element corresponding to the parent block box) just as the logical height of inline boxes is determined by the line-height property (of the element corresponding to the box itself).

The vertical-align property

There are two types of values (excluding inherit) for the vertical-align property: anchored and loose. The anchored vertical alignment types specify a vertical-alignment for an inline box relative to its parent inline box. The loose vertical alignment types specify a vertical alignment within the line box. Note that the vertical alignment of anonymous inline boxes cannot be specified by the vertical-align property on their parent block, since a vertical-align on an anonymous inline box (i.e., a root inline box) would be meaningless. [NOTE: It's actually not meaningless in all cases, but only top and bottom would be useful.]

The anchored vertical-alignment types are as follows:

baseline
Align the baseline (or bottom outer edge, if replaced) of the box with the baseline of the parent box.
middle
Align the midpoint of the box (which is the same for both the logical edges or font edges) with the point in the parent one-half the x-height of the parent's font above the baseline. [NOTE: Should the first font in the parent's font set always be used? Is that the definition of an ex? Should this be defined in terms of an ex?] [NOTE: Which edge is used for finding the midpoint of a replaced element? I would think the margin edge.]
sub
Align the baseline (or bottom outer edge, if replaced) of the box with the proper subscript baseline of the parent box. This subscript baseline may be determined from the font metrics of the parent's font. [NOTE: Is the first font in the font set used? What if that font isn't used for the subscript? ...for the surrounding text?]
super
Align the baseline (or bottom outer edge, if replaced) of the box with the proper superscript baseline of the parent box. This superscript baseline may be determined from the font metrics of the parent's font. [NOTE: Is the first font in the font set used? What if that font isn't used for the superscript? ...for the surrounding text?]
text-top
Align the logical top of the box (or top outer edge, if replaced) with the font top of the parent box.
text-bottom
Align the logical bottom of the box (or bottom outer edge, if replaced) with the font bottom of the parent box.
<length>
Align the baseline (or bottom outer edge, if replaced) of the box with the given length above (or below, if negative) the baseline of the parent box.
<percentage>
Convert the percentage into a length by multiplying by the line-height, and then treat as a <length>. Negative percentages are allowed. [NOTE: If the meaning of line-height is changed as I suggest in a NOTE above, should this be based on the line-height or the height of the line box?]

The loose vertical-alignment types are as follows (terms used will be defined later):

top
Place the loose subtree top (or top outer edge, if replaced) of the box at the top of the line box.
bottom
Place the loose subtree bottom (or bottom outer edge, if replaced) of the box at the bottom of the line box.

[NOTE: Why isn't there a loose type for the middle of the line box? Is that what the proprietary align=absmiddle does?]

The inline formatting context (horizontal), line boxes, and anonymous inline boxes

Block level elements (in which I include elements of display block, list-item, table-cell, inline-block (proposed), and some elements of display compact and run-in) can contain three types of content. They can contain other block-level elements, inline elements, or text. In terms of the DOM, the first two types of children are Element Nodes and the latter type are Text Nodes.

The inline content (inline elements and text) within a block level element is broken into lines using a line-breaking algorithm. [NOTE: Should Unicode be cited?] When doing this, the sizes of words (affected by letter-spacing), whitespace (affected by word-spacing), replaced elements, and horizontal margins, border, and padding must be considered. Lines are typically broken at word-breaks, although breaks may be permitted within words, forced, or prohibited between words. Forced breaks include the beginning or end of a block-level element and any markup or characters that force a line-break.

The content within each line is placed within a line box. Empty line boxes should not be created. [NOTE: Empty needs to be defined. If a box has text or replaced elements, it is not empty, but what about border and padding?] The only child of each line box is an anonymous inline box called the root inline box (of the line). All of the inline boxes and text are placed within this root inline box. Note that the line box is often taller than the root inline box. If an inline element is split between lines, then more than one inline box is used to represent that element. (Note that horizontal box properties still only apply at the beginning and end of the element.)

Anonymous inline boxes (which are all root inline boxes) are considered to have the font-size and line-height properties of their parent block-level element.

When a block-level element or elements are contained within inline elements, a forced break occurs at the beginning of the block-level element(s). A block formatting context begins at the end of the line box preceding the block-level elements, if such a line box exists, and the outer edge of the block-level element is aligned with the bottom of the previous line-box. Otherwise the block-level element is placed according to the rules for block level formatting. At the end of the block level element(s), the top of the following line box (if it exists) is placed at the bottom outer edge of the last block box. If no such line box exists, the rules for block-level formatting are followed.

The width of line boxes is the width of the containing block box minus any space occupied by floats. The line boxes are stacked vertically within the block box with no separation or overlap, beginning at the top inner edge of the block. If the block has a height of auto, the bottom of the last line box determines the bottom inner edge of the block box.

Image showing three line boxes inside a block box (with auto height), and a float
Line boxes within a block box (with auto height).

The inline boxes within a given line box are unlikely to perfectly fill that line box. In most cases, there will be some extra horizontal space that is unfilled. In a few cases (where line breaking is impossible), the content may be wider than the line box. Therefore, the inline content must be horizontally aligned within the line box. The horizontal alignment of the content within the line box is controlled by the text-align property of the parent block-level element, which can take the following values for block-level elements (excluding inherit):

left
Place the left edge of the content of the line box at the left edge of the line box and the space unable to be filled (or the overflow) at the right.
center
Place the center of content of the line box horizontally in the middle of the line box and divide the space unable to be filled (or the overflow) equally between left and right. [NOTE: Is this how overflow should work for centering?]
right
Place the right edge of the content of the line box at the right edge of the line box and the space unable to be filled (or the overflow) at the left.
justify
For line boxes not terminated by a forced break, attempt to remove the unfilled horizontal space by modifying none, any, or all of the letter spacing, word spacing, font stretch, or character widths. If this is not possible or not done, for lines terminated by a forced break, or for lines with overflow, treat the line as if text align were left (if direction is ltr) or right (if direction is rtl).

The construction of line boxes (vertical)

This section is based on a post I made to www-style, but I have improved (I hope!) the terminology.

In this section I will refer to boxes generated by elements that have a loose vertical alignment as loose boxes and those generated by elements that have a anchored vertical alignment as anchored boxes. The root inline box is always a loose box. Each loose box in a line has a loose subtree of boxes. This includes the box itself and all of its descendant boxes except for those that are loose or are descendants of such a descendant loose box.

All the boxes within each loose subtree are related by anchored vertical alignments, and therefore their positions relative to each other are clearly specified. Every loose subtree has a loose subtree top, which is the highest of the logical tops of the boxes in that loose subtree, and a corresponding loose subtree bottom. The distance between them is the loose subtree height.

The height of the line box is the largest of the heights of the loose subtrees within the line box. This tallest loose subtree extends from the top of the line box to the bottom. If this tallest loose subtree is the one corresponding to the root inline box, then all the other loose subtrees are aligned according to the value of the vertical-align property on the element generating the box that is the root of the loose subtree. If this tallest loose subtree is not the one corresponding to the root inline box, then the position of the loose subtree corresponding to the root inline box is undefined, but all the other loose subtrees are aligned (as in the previous case) according to the relevant value of the vertical-align properly. However, it is suggested that the root inline box be aligned as if the relevant vertical-align value were that of the tallest loose subtree in the line.

Examples

The effects of large text

As a simple example, I will show two slightly different cases side by side in a number of states. The only difference between the two cases is the value of the line-height property. Furthermore, the computed value of line-height is the same in both examples on the element on which it is specified, but it differs on the big element (30px and 90px, respectively).

Source Example 1:
<!DOCTYPE HTML PUBLIC
	"-//W3C//DTD HTML 4.0//EN"
	"http://www.w3.org/TR/REC-html40/strict.dtd">
<html>
<head>
	<title></title>
	<style type="text/css">

	p {
		font-family: "Times New Roman",
			"Times Roman", Times, serif;
		font-size: 24px;
		line-height: 30px;
		border: 5px solid #ff8000;
		}

	big {
		font-size: 72px;
		}

	</style>
</head>
<body>

<p>
	This is a paragraph that contains a
	little bit of <big>big text</big>
	somewhere in the middle, to show
	what happens.
</p>


</body>
</html>
Example 2:
<!DOCTYPE HTML PUBLIC
	"-//W3C//DTD HTML 4.0//EN"
	"http://www.w3.org/TR/REC-html40/strict.dtd">
<html>
<head>
	<title></title>
	<style type="text/css">

	p {
		font-family: "Times New Roman",
			"Times Roman", Times, serif;
		font-size: 24px;
		line-height: 1.25;
		border: 5px solid #ff8000;
		}

	big {
		font-size: 72px;
		}

	</style>
</head>
<body>

<p>
	This is a paragraph that contains a
	little bit of <big>big text</big>
	somewhere in the middle, to show
	what happens.
</p>


</body>
</html>
Layout Image of example 1 Image of example 2
Layout, with font boxes Image of example 1 Image of example 2
Layout, with font boxes (green) and inline boxes (red) Image of example 1 Image of example 2
Layout, with font boxes (green), inline boxes (red), and line boxes (purple) Image of example 1 Image of example 2

Changes from the CSS2 inline box model

I do not guarantee that these lists are complete.

Changes

Potentially controversial clarifications

Acknowledgments

Thanks to Ian Hickson for comments on the draft, and to Eric Meyer for asking the question on www-style that prompted me to write this. However, the opinions expressed represent my views only.


Valid HTML 4.0!

(Back to CSS, David Baron)

LDB, dbaron@dbaron.org, 2000-01-09, 2000-01-12, 2000-01-13