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:
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.
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).
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 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?]
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.)
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.]
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).
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:
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.]
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):
[NOTE: Why isn't there a loose type for the middle of the line
box? Is that what the proprietary align=absmiddle
does?]
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.
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
(if direction
is ltr
) or
right
(if direction
is
rtl
).
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.
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 | ||
Layout, with font boxes | ||
Layout, with font boxes (green) and inline boxes (red) | ||
Layout, with font boxes (green), inline boxes (red), and line boxes (purple) |
I do not guarantee that these lists are complete.
line-height
property no longer has any
direct effect on block-level elements. However, the original
intent (I think) of the spec is incorporated into the new idea of
anonymous inlines.
vertical-align
property on a block-level element
no longer affects anonymous inline boxes within it.
top
and bottom
values for vertical align as I
described before, and made suggestion on handling
ambiguous cases.
inline-table
and inline-block
should be treated as
replaced elements within the inline box model (although
they have their own inline box models within them).
text-align
.
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.
(Back to CSS, David Baron)
LDB, dbaron@dbaron.org, 2000-01-09, 2000-01-12, 2000-01-13