Re: [CSS21] Issues with inline formatting model (particularly 10.8)

Anton Prowse wrote:

> 10.6.1 (Inline, non-replaced elements):
> 
>   # The 'height' property does not apply. The height of the content area
>   # should be based on the font, but this specification does not specify
>   # how. [...]
> 
>   # [...] But only the 'line-height' is used when calculating the height
>   # of the line box.
> 
> 10.8 (Line height calculations):[1]
> 
>   # [...]. The height of a line box is determined as follows:
>   # 1. The height of each inline box in the line box is calculated (see
>   #   "Calculating heights and margins" and the 'line-height' property).
> 
> Issue 13:
> 
> The 'line-height' property explicitly /doesn't/ determine the height of
> any inline box, and the height of an inline box explicitly /doesn't/
> determine the height of the line box.  Rather, it's the 'line-height'
> property of the inline box which helps to determine the line box height.
> 
> Hence 10.8, list item 1 should actually say something like
> 
>   | The 'line-height' of each inline box in the line box is calculated
> 
> and link 'line-height' to the property definition.

My rationale was incorrect here because the spec was unclear to me in
its use of the term "height of an inline box".  (However, now that I've
untangled what it wants to say, I believe that Issue 13 still stands in
a modified form, and several new issues arise; see below.)

It's well-known that the content area height of inline boxes is not used
in the calculation of line box height.  What is less clear from the spec
is that the term "height" is defined for an inline box (a fact which is
more surprising than it might seem; see my discussion of box height,
below) and that this "height" is what the 'line-height' property determines.

Interestingly, the spec is itself reluctant to commit to the idea of
defining and referring to "inline box height" – which implies and
determines physical vertical boundaries of the inline box – when flowing
content into line boxes.  It often prefers indirection instead, by
referencing the 'line-height' property.  This creates its own editorial
issues, such as employing the term "line-height" to mean a physical
position within a box (Issue 3b in [2,3]).

This post proceeds to present:
 - a discussion of box height in CSS21;
 - an analysis of how inline box height is defined and used in
           10.8;
 - a discussion of the surrounding editorial issues;
 - a presentation of an alternative construction which provides a
           readier description of the inline formatting model;
 - a brief look at the motivation behind the existing model.


Height of a box
-----------------

With the exception of the description of inline formatting, the spec
actually avoids referring to a box's "height", preferring instead to
talk about content area height (for instance) where necessary.  (Where
there are exceptions, they appear to be accidental since content area
height is what is being described.)

As a result, box dimensions are not clearly defined.

Chapter 8 is vague about whether a box contains its margin area:

   # Each box has a content area (e.g., text, an image, etc.) and
   # optional surrounding padding, border, and margin areas

although the use of the word "has" perhaps indicates that it does.

On the other hand, 9.4.1 states that

   # In a block formatting context, boxes are laid out one after the
   # other, vertically, beginning at the top of a containing block. The
   # vertical distance between two sibling boxes is determined by the
   # 'margin' properties. Vertical margins between adjacent block boxes
   # in a block formatting context collapse.

which supports the idea that the extents of a block-level box are the
border edges.  (cf. Ch.17 where the height of a table is defined to be
its border area height.)

Chapter 12 makes just one casual reference to the "height" of a box, in
the definition of the 'outside' value of the 'list-style-position'
property:[4]

   # outside
   #   The marker box is outside the principal block box. [...].  The
   #   size or contents of the marker box may affect the height of the
   #   principal block box and/or the height of its first line box, and
   #   in some cases may cause the creation of a new line box. [...].

This is probably talking about content area height anyway.

No other chapter refers to the "height" of a box.

(Importantly, note that none of this is related to the 'height'
property, which explicitly relates to the /content area/ height of a
box, not the "height" of the box itself.)


Height of an inline-level box
-----------------------------

The "height" of an inline-level box is referred to in just a handful of
places, all in 10.8 (apart from a couple of sentences in 10.6 concerning
replaced and inline-block elements).  A reliance on the corresponding
box dimensions is evident in various other places in 10.8.

   # The height of a line box is determined as follows:
   #   1. The height of each inline box in the line box is calculated
   #   2. [...]
   #   3. The line box height is the distance between the uppermost box
   #      top and the lowermost box bottom.
...
   # When the 'line-height' value is less than the content height, the
   # final inline box height will be less than the font size and the
   # rendered glyphs will "bleed" outside the box.

   # Although margins, borders, and padding of non-replaced elements do
   # not enter into the line box calculation, they are still rendered
   # around inline boxes. This means that if the height specified by
   # 'line-height' is less than the content height of contained boxes,
   # backgrounds and colors of padding and borders may "bleed" into
   # adjoining line boxes.

(cf. 10.6.1:
    # The vertical padding, border and margin of an inline, non-replaced
    # box start at the top and bottom of the content area, not the
    # 'line-height'.
which is the subject of Issue 3b in [2,3].)
...
   # On an inline-level element, 'line-height' specifies the height that
   # is used in the calculation of the line box height (except for inline
   # replaced elements, where the height of the box is given by the
   # 'height' property).
...
   # <length>
   #   The specified length is used in the calculation of the line box
   #   height. [...]
...
   # text-top
   #   Align the top of the box with the top of the parent's content area
   #  (see 10.6.1).
   # text-bottom
   #   Align the bottom of the box with the bottom of the parent's
   #   content area (see 10.6.1).
...
   # [...].  The top of the aligned subtree is the highest of the tops of
   # the boxes in the subtree, and the bottom is analogous.
   #
   # top
   #   Align the top of the aligned subtree with the top of the line box.
   # bottom
   #   Align the bottom of the aligned subtree with the bottom of the
   #   line box.


Relevant editorial issues
-------------------------

These issues assume that the spec wishes to commit to the idea of
inline-level box height being defined (and thus determined by the
'line-height' property) and used for line box height calculation.


Issue 13, revisited:

> 10.8 (Line height calculations):[1]
>
>   # [...]. The height of a line box is determined as follows:
>   # 1. The height of each inline box in the line box is calculated (see
>   #   "Calculating heights and margins" and the 'line-height' property).

The reference to the "Calculating heights and margins" part of the spec
should be removed, since that section concerns itself only with /content
area/ height.


Issue 14:

To *ensure* that the "Calculating heights and margins" part of the spec
concerns itself only with content area height and doesn't stray into
tangential matters, the following sentences should be moved from that
section down to 10.8.

10.6.1 (Inline, non-replaced elements):
   # The vertical padding, border and margin of an inline, non-replaced
   # box start at the top and bottom of the content area, not the
   # 'line-height'. But only the 'line-height' is used when calculating
   # the height of the line box.

(Also cf. Issue 3b [2,3].)

10.6.2 (replaced inline/inline-block elements):
   # For 'inline' and 'inline-block' elements, the margin box is used
   # when calculating the height of the line box.

10.6.6 (non-replaced inline-block elements):
   # For 'inline-block' elements, the margin box is used when calculating
   # the height of the line box.


Issue 15:

10.6.2 (replaced inline/inline-block elements):
   # For 'inline' and 'inline-block' elements, the margin box is used
   # when calculating the height of the line box.

10.6.6 (non-replaced inline-block elements):
   # For 'inline-block' elements, the margin box is used when calculating
   # the height of the line box.

In both these cases,
s/line box/inline(-level) box/
since there's no need to be indirect here. (We know the line box height
depends on the inline(-level) box height.)

[See [5] for the ongoing discussion of whether inline box or
inline-level box is appropriate, especially in relation to inline-block.]


Issue 16:

10.8.1 says:
   # On a block-level, table-cell, table-caption or inline-block element
   # whose content is composed of inline-level elements, 'line-height'
   # specifies the minimal height of line boxes within the element. [...]

   # On an inline-level element, 'line-height' specifies the height that
   # is used in the calculation of the line box height (except for inline
   # replaced elements, where the height of the box is given by the
   # 'height' property).

I don't follow the inline-block bit at all: does "whose content is
composed of inline-level elements" qualify inline-block, or all the
element types listed?  Why is this case noteworthy?  What if the content
isn't composed like that?  Also, shouldn't inline-table be mentioned
here, or should we really not be highlighting inline-block and
inline-table at all and instead talk about inline-level block containers
(see [5])?  See also [6; Issue 2].

On an inline-block (and inline-table), does 'line-height' apply to the
"inside" or the "outside", or both?  That is, does it determine the
height of the box or the minimum height of line boxes inside the box, or
both?


Issue 17:

There appears to be a contradiction between 10.8.1:

   # On an inline-level element, 'line-height' specifies the height that
   # is used in the calculation of the line box height (except for inline
   # replaced elements, where the height of the box is given by the
   # 'height' property).

and 10.6.2 / 10.6.6:
   # For 'inline' [replaced] and 'inline-block' [replaced] elements, the
   # margin box is used when calculating the height of the line box.

   # For 'inline-block' [non-replaced] elements, the margin box is used
   # when calculating the height of the line box.

For inline replaced elements, is it the 'height' property or the margin
box which determines the height of the inline-level box?

For inline-block elements, is it the 'line-height' property or the
margin box which determines the height of the inline-level box?

However, this issue might become clearer once some light has been shed
on Issue 16 above.


Issue 18:

   # User agents center glyphs vertically in an inline box, adding
   # half-leading on the top and bottom. [...]

   # When the 'line-height' value is less than the content height, the
   # final inline box height will be less than the font size and the
   # rendered glyphs will "bleed" outside the box. [...]

Assuming that leading is the mechanism which determines where the
vertical extents of the inline-level box lie relative to the content
area (meaning that the vertical center of the inline-level box is
incident with the vertical center of the content area; see also [7]),
then leading may be negative.  This is implied in the text, but I think
it should be mentioned explicitly, perhaps as a note.  (cf. 9.5.2:
clearance).


Issue 19:

10.6.1:
   # The height of the content area should be based on the font, but this
   # specification does not specify how.

For added emphasis, I'd like to see a note in 10.6.1 that the content
area height of an inline box doesn't depend on its descendant boxes
(neither in terms of their glyphs, font or line-height) but only on its
own glyphs and font.(*)  This is a potential gotcha.

(*) Here, for simplicity, I'm ignoring inline-level content other than text.


Alternative construction for line box height calculation
--------------------------------------------------------

Ch.10 wants to define the "height" of an inline box to be something
unrelated to its box model.  We've seen that at least this doesn't
contradict anything elsewhere in the spec.

Still, I'm not sure that this is the clearest construction to use.  This
part of the spec is notoriously difficult for people to understand, but
my feeling now is that this is less to do with conceptual difficulty and
more to do with a poor choice of construction (aided by numerous
editorial bugs and several technical issues).  Under the current model,
even the content area of an inline box can "bleed out" of its own
"boundary", which is quite some gotcha for those without detailed
knowledge of this section!

If I were writing a guide to the inline formatting model, I would use
the following construction for 10.8.

   | Vertical alignment of inline boxes and determination of line box
   | height is performed, not using the inline boxes themselves, but
   | rather using a "guide box" to represent each inline box.  The height
   | of each guide box is determined only by the value of the line-height
   | property on the inline box.  Leading is realized as spacing applied
   | to the content box to center the inline box's content area within
   | its guide box; the guide box may be shorter than the content area
   | and so leading may be negative. (Cf. [2].)

It differs from the existing construction only in the provision of extra
guide boxes instead of reliance in an unintuitive definition of inline
box height, but the advantage is that these tangible boxes cannot be
confused with glyph boxes or box model areas, which makes line height
calculation and vertical alignment considerably easier to grasp.  (It
also means that there's no need to attempt to define the "height" of an
inline box, which is consistent with the perhaps intentional vagueness
elsewhere in the spec.)


Motivation behind the current inline formatting model
-----------------------------------------------------

'line-height' property:
   # Generally, when there is only one value of 'line-height' for all
   # inline boxes in a paragraph (and no tall images), the above will
   # ensure that baselines of successive lines are exactly 'line-height'
   # apart. This is important when columns of text in different fonts
   # have to be aligned, for example in a table.

Interestingly, this result might /not/ be achieved if the vertical
alignment depends on the font baseline and baseline is in a different
"position" in the different fonts, or if the method used for calculating
the height of the content area in 10.6.1 is not based on the em box.
But the general desire for baselines of successive lines to be exactly
'line-height' apart in the most simple situations is sound, and
achievable with the existing model.

If 'line-height' were not to apply to inline elements, the model would
produce very intuitive results since there could be no bleeding of
glyphs.  But, assuming that bleeding is desirable, the existing model
is merely one of various possible ways to achieve it.  Yet the chosen
model has some peculiar features.  One interesting fact, for example, is
that the bottom half of the content area can never bleed out of the top
of the line box in which it sits, and the top half can never bleed out
of the bottom; we observe this in the follow test case which is pretty
much the quintessential test case for the model and routinely results in
bafflement for those who lack a deep understanding of how it works.

<div style="line-height:20px; width:280px">
 text text text text text text text text text text text text
 <span style="line-height:inherit; font-size:140px">text</span>
 text text text text text text text text text text text text
</div>

Why does the line box containing the span increase but still allow a
seemingly rather small amount of the tops of the span's glyphs to bleed
out?  It's only obvious when you know how, and I don't think anyone
could call it intuitive!


> [1] http://www.w3.org/TR/CSS21/visudet.html#line-height
[2] http://lists.w3.org/Archives/Public/www-style/2009Mar/0004.html
[3] http://lists.w3.org/Archives/Public/www-style/2009May/0191.html
[4] http://www.w3.org/TR/CSS2/generate.html#propdef-list-style-position
[5] http://lists.w3.org/Archives/Public/www-style/2010Jul/0383.html
[6] http://lists.w3.org/Archives/Public/www-style/2009Oct/0080.html
[7] http://lists.w3.org/Archives/Public/www-style/2010Jul/0457.html

Cheers,
Anton Prowse
http://dev.moonhenge.net

Received on Saturday, 31 July 2010 15:51:54 UTC