More Precise Definitions of Intrinsic Widths and Table Layout (Proposal)

24 September 2015

This version:
http://dbaron.org/css/intrinsic/20150924
Latest version:
http://dbaron.org/css/intrinsic/
Previous versions:
Author:
L. David Baron (dbaron@dbaron.org), Mozilla

Status of this Document

This document is work in progress towards a proposal by the author for future additions to CSS specifications. It is intended that each rule in this specification is compatible with what at least some existing implementations do. Since it is an attempt to define more precisely the behavior of features that already exist, it is hoped that it is already suitable for implementation, with the caveat that behavior eventually specified may differ from this proposal, perhaps significantly enough to make work spent implementing this draft a waste of time.

Comments on this draft should be sent to the public mailing list www-style@w3.org (Archive) or to the author.

This document should eventually be merged with the css3-tables-algorithms written by a group at Microsoft. They are intended to cover roughly the same space, though they both are incomplete and thus cover different, though substantially overlapping, subparts of it. They describe a number of things in different ways, though. Unfortunately, neither document has been actively maintained for quite a few years.

Abstract

In [CSS2], the rules for computing the dimensions of a table or the distribution of column widths within the table were left undefined (for the case when table-layout is auto, the default value), although a non-normative algorithm was presented that depended on two intrinsic widths of a piece of content. No other reference was made to intrinsic widths.

In [CSS21], the rules for computing widths of absolutely positioned elements and floating elements were modified so that they also depend on two intrinsic widths of the content, and rules for elements with display: inline-block (a new feature) were added that also used these two intrinsic widths (and a common set of rules, called "shrink-to-fit", for using those widths).

This document provides more precise definitions of how these intrinsic widths are computed and used, and more precise definitions of width calculations in table layout. It also proposes new values for some properties that allow authors to choose between the major variations of intrinsic sizing, rather than having only one of the choices accessible through the 'width: auto' (which one varies depending on 'display', 'position', and 'float').

This document uses the terms max-content width and min-content width to describe the two intrinsic widths. The following table compares this to the terminology used elsewhere:

This proposal Previous versions of this proposal CSS 2.1 visual formatting model CSS 2 auto table layout
max-content width intrinsic preferred width preferred width "maximum" cell width (similar)
min-content width intrinsic minimum width preferred minimum width minimum content width (similar)

Conceptually, the max-content width is intended to be the largest width that the content can usefully fill. For example, for an unstyled block of text, the max-content width is the width of the text when laid out end-to-end (on one line).

Likewise, the min-content width is intended to be the smallest width that the content can fit in without unintended overflow. For example, for an unstyled block of text, the min-content width is the width of the longest word (unbreakable unit) in the text.

This specification also defines the outer min-content width and the outer max-content width of boxes. These are values derived from the intrinsic widths, but modified by considering the computed values of the width, min-width, max-width, box-sizing, padding-left, border-left-width, margin-left, padding-right, border-right-width, margin-right, and other properties. These outer intrinsic widths are then an important part of the definition of the parent box's intrinsic widths.

Definitions

A cell is said to originate in a column if, when the 'direction' of the table is 'ltr' ('rtl'), the column is the leftmost (rightmost) column that the cell spans. (Cells with a 'column-span' of '1' are considered to originate in their only column.)

A column has originating cells if there is a cell that originates in that column.

The function min() is defined as the function that returns the smallest of its arguments, and the function max() is defined as the function that returns the largest of its arguments. When one of those arguments is an 'auto' value for 'width', it must be treated as 0 when in max() and (positively) infinite when in min(). Likewise, a 'none' value for 'max-width' must be treated as (positively) infinite.

Intrinsic widths of non-table boxes

For inline elements, intrinsic widths are defined to be the corresponding intrinsic width of a hypothetical anonymous block placed around the inline element. (This definition exists so that it is defined. However, it is not intended to be used for anything.)

The min-content width of a block, inline-block, or table cell, is defined to be the largest of the following:

The max-content width of a block, inline-block, or table cell, is defined to be the largest of the following:

The handling of floats within the definition of max-content width of blocks is not yet written properly. I need to write the handling of clear, and perhaps some other additions.

Note that the current behavior of Web browsers for handling intrinsic widths of blocks containing floats is not very interoperable.

This manner of specifying (and implementing) intrinsic width calculations makes it impossible to specify (or implement) ideal behavior for max-content width of blocks containing floats. The goal of this specification is simply to define an approximation that is good enough, and can be interoperably implemented.

Note that the properties 'width', 'min-width', and 'max-width' do not affect the intrinsic widths of the elements on which they are specified. However, they can affect the intrinsic widths of the parent element in many cases, through their effect on the outer intrinsic widths. This allows declarations like the following to be useful:

  width: 5em;
  min-width: min-content;

and also allows some formatting objects (such as flexible boxes) to use formatting rules in which these properties on children do not effect the intrinsic widths of the parent.

Absolutely positioned elements never contribute to containing block's intrinsic widths.

These rules only describe max-content and min-content widths. The parallel rules for heights are quite complicated. Such rules are necessary for mixed vertical and horizontal text, for a flexible box model, and side table captions.

Outer intrinsic widths

This needs to account for the 'box-sizing' property.

The following definitions are defined in terms of the values of properties; when not otherwise specified, the values used are the computed values. However, percentages on the following properties are treated instead as though they were the following:

width
auto
min-width
0
max-width
none

Adjusting an intrinsic width for the content edge, padding edge, or border edge of a box to add horizontal padding (if content edge), border (if content edge or padding edge), and margin is defined to consist of the following steps:

  1. Add any computed values of padding-left (when applicable), padding-right (when applicable), border-left-width (when applicable), border-right-width (when applicable), margin-left, and margin-right that are lengths.
  2. If and only if the intrinsic width being adjusted is a max-content width, divide by the larger of 0 or 1 minus the sum of any computed values of padding-left (when applicable), padding-right (when applicable), margin-left, and margin-right that are percentages. Note that this may yield an infinite result, but undefined results (zero divided by zero) must be treated as zero.

Note that the handling of percentage padding and margin is not very interoperable in today's browsers.

some of the "m + b + p" also need to include scrollbars, but we don't always know when the scrollbars are present. Figure out what needs to happen here. There may also be interesting interactions between the 'overflow' property and percentage widths or heights.

This specification defines the terms outer min-content width and outer max-content width for the intrinsic width values that are used as part of the computation of the parent box's intrinsic widths.

The outer min-content width of blocks and inline-blocks is defined to be the following:

The outer max-content width of blocks and inline-blocks is defined to be the following:

Intrinsic widths of inline formatting contexts

Define min-content width of an inline formatting context. Break line at every point. Don't forget all text-indent, word-spacing, letter-spacing, m/b/p on inlines, etc. when doing this breaking. Also whitespace trimming.

Define max-content width of an inline formatting context. Ditto.

Automatic Table Layout

The following rules define behavior of tables with table-layout: auto that is undefined in CSS2.1.

Note that the results produced by these rules do not change if the order of rows in a table is changed (assuming appropriate rearrangement of row-spanning cells). This is true of most, but not all, current implementations of CSS2 table layout. These rules do produce variation under reordering of columns (assuming appropriate rearrangement of column-spanning cells) in one circumstance: when columns have percentage widths that add to more than 100%.

The following terms are parameters of tables or table cells. These parameters encapsulate the differences between tables with different values of border-collapse (separate or collapse) so that the remaining subsections of this section do not need to refer to them differently.

cell intrinsic offsets

The cell intrinsic offsets is a term to capture the parts of padding and border of a table cell that are relevant to intrinsic width calculation. It is a set of computed values for border-left-width, padding-left, padding-right, and border-right-width (along with zero values for margin-left and margin-right) defined as follows:

table intrinsic offsets

The table intrinsic offsets is a term to capture the parts of the padding and border of a table that are relevant to intrinsic width calculation. It is a set of computed values for border-left-width, padding-left, padding-right, and border-right-width (along with zero values for margin-left and margin-right) defined as follows:

The margins are not included in the table intrinsic offsets because handling of margins depends on the 'caption-side' property. But doesn't that break handling of percentage padding?

total horizontal border spacing
The total horizontal border spacing is defined for each table:

The outer min-content and max-content widths are defined for table cells, columns, and column groups. The 'width', 'min-width', and 'max-width' values used in these definitions are those defined above:

The percentage contribution of a table cell, column, or column group is defined in terms of the computed values of 'width', 'max-width', and 'min-width' that have computed values that are percentages. It is max(percentage 'min-width', min(percentage 'width', percentage 'max-width')). If the computed values are not percentages, then 0% is used for 'width' or 'min-width', and an infinite percentage is used for 'max-width'.

These definitions need to account for the 'box-sizing' property.

Intrinsic widths of columns

This subsection defines terms for various parameters associated with each column of a table. These parameters are used in the following two subsections as part of the rules for computing intrinsic widths of tables and computing the column widths of a table.

The spanning and non-spanning intrinsic widths are intermediate values that are used only within this section. The rationale for having these separate definitions of spanning and non-spanning widths is to make the layout of tables invariant under reordering of the rows. This invariant is maintained by most, but not all, current Web browser implementations. Rewrite!

This needs to account for character-alignment of cells ('<string>' values of the 'text-align' property). This requires (based on the 9 March 2011 editor's draft of css3-text) separately tracking max-content widths for the part of the column before the center of the alignment string and and the part of the column after the center of the alignment string. For tracking min-content widths, there are two options: either not track them, or track three values: two values as for max-content widths for any cells that do not have break points in them, and a fourth value for any cells that do have break points in them (and to which character alignment is therefore not mandatory).

The handling of the 'max-width' property on cells, columns, and column groups with this algorithm is very poor. It ought to have an effect stronger than the one it has on the outer intrinsic widths of the element on which it is specified. It probably ought to be a separate parameter of the column (though how it interacts with the min-content width would need to be defined).

The way this describes distribution of widths from column-spanning cells is wrong. For min-content and max-content widths it should refer to the rules for distributing excess width to columns for intrinsic width calculation, and for percentages it needs to ensure that it doesn't distribute widths to columns that do not have originating cells.

intermediate min-content width for span 1

the largest of:

intermediate max-content width for span 1

the largest of:

intermediate intrinsic percentage width for span 1

the largest of the percentage contributions of each cell in the column whose 'column-span' property has a computed value of '1', of the column (if any), and of the column group (if any)

intermediate min-content width for span N (N > 1)

the largest of the intermediate min-content width for span N-1 and the contributions of the cells in the column whose 'column-span' property has computed value N, where the contribution of a cell is the result of taking the following steps:

  1. Define the baseline (min-content / max-content) width as the sum of the intermediate (min-content / max-content) widths for span N-1 of all columns that the cell spans.
  2. Define the baseline border spacing as the sum of the and the horizontal border-spacing for any columns spanned by the cell, other than the one in which the cell originates, in which cells originate.
  3. The contribution of the cell is the sum of:
    • the min-content width of the column for span N-1
    • the product of:
      • the ratio of:
        • the intermediate max-content width for span N-1 of the column minus the intermediate min-content width for span N-1 of the column, to
        • the baseline max-content width minus the baseline min-content width
        or zero if this ratio is undefined, and
      • the outer min-content width of the cell minus the baseline min-content width and the baseline border spacing, clamped to be at least 0 and at most the difference between the baseline max-content width and the baseline min-content width
    • the product of:
      • the ratio of the intermediate max-content width for span N-1 of the column to the baseline max-content width
      • the outer min-content width of the cell minus the baseline max-content width and baseline border spacing, or 0 if this is negative
intermediate max-content width for span N (N > 1)

the largest of the intermediate max-content width for span N-1 and the contributions of the cells in the column whose 'column-span' property has computed value N, where the contribution of a cell is the result of taking the following steps:

  1. Define the baseline max-content width as the sum of the intermediate max-content widths for span N-1 of all columns that the cell spans.
  2. Define the baseline border spacing as the sum of the and the horizontal border-spacing for any columns spanned by the cell, other than the one in which the cell originates, in which cells originate.
  3. The contribution of the cell is the sum of:
    • the max-content width of the column for span N-1
    • the product of:
      • the ratio of the intermediate max-content width for span N-1 of the column to the baseline max-content width
      • the outer max-content width of the cell minus the baseline max-content width and the baseline border spacing, or 0 if this is negative
intermediate intrinsic percentage width for span N (N > 1)

If the intermediate intrinsic percentage width for span N-1 is greater than 0%, then the intermediate intrinsic percentage width for span N is the same as the intermediate intrinsic percentage width for span N-1.

Otherwise, it is the largest of the contributions of the cells in the column whose 'column-span' property has computed value N, where the contribution of a cell is the result of taking the following steps:

  1. Start with the percentage contribution of the cell.
  2. Subtract the intermediate intrinsic percentage width for span N-1 of all columns that the cell spans. If this gives a negative result, change it to 0%.
  3. Multiply by the ratio of
    1. the column's non-spanning max-content width to
    2. the sum of the non-spanning max-content widths of all columns spanned by the cell that have an intermediate intrinsic percentage width for span N-1 equal to 0%.
    However, if this ratio is undefined because the denominator is zero, instead use the 1 divided by the number of columns spanned by the cell that have an intermediate intrinsic percentage width for span N-1 equal to zero.
min-content width

the intermediate min-content width for span N, where N is the number of columns in the table

max-content width

the intermediate max-content width for span N, where N is the number of columns in the table

intrinsic percentage width

the smaller of:

The clamping of the total of the intrinsic percentage widths of columns to a maximum of 100% means that the table layout algorithm is not invariant under switching of columns.

constrainedness

A column is constrained if the column group (if any), the column (if any), or any of the non-column-spanning cells in the column has a computed 'width' that is not 'auto', and is not a percentage. Do we need intermediate constrainedness? It's easier to implement that way, but does it actually make any difference?

Is 0% really treated like 0 rather than like a percentage value? (e.g., if it's the only non-spanning percentage in a column that has a spanning cell with a percentage width?)

Intrinsic widths of auto layout tables

This specification currently defines the intrinsic widths of tables (including inline-tables) as a parameter of the table excluding its caption, but the outer intrinsic widths of tables as a parameter of the table including its caption. This distinction is needed because the intrinsic widths exclusive of the caption are critical to the final table layout algorithm. However, it may be better to have a separate term for these parameters rather than overloading these existing terms by adding this strange distinction.

The min-content width of a table or inline table is the sum of the min-content widths of the columns and the total horizontal border spacing of the table.

The max-content width of a table or inline table is the sum of the total horizontal border spacing of the table and the largest of:

  1. the sum of the max-content widths of the columns
  2. the small percentage contribution of each of the columns, where the small percentage contribution of a column is defined as the ratio of
    1. the column's max-content width to
    2. its intrinsic percentage width (where 100% == 1.0)
    This ensures that cells, columns, or column groups with small percentage widths have those percentage widths satisfied when possible.
  3. the large percentage contribution of the table, which is the ratio of
    1. the sum of the max-content widths of all the columns whose intrinsic percentage width is zero to
    2. 100% (1.0) minus the sum of the intrinsic percentage widths of the columns,
    unless the denominator of that ratio is 0, in which case it is 0 if the numerator is also 0, and an infinitely large number if the numerator is nonzero This ensures that cells, columns, or column groups with large percentage widths have those percentage widths satisfied when possible. It would be nice to prove that there's no need to iterate over the columns separately. I think this is true because in such cases the small percentage effect would win.

Computing column widths

When a table is laid out at a given used width, the used width of each column must be determined as follows.

Define the assignable width as the used width of the table minus the total horizontal border spacing.

Define the min-content guess as the set of column width assignments where each column is assigned its min-content width.

Define the min-content-percentage guess as the set of column width assignments where:

Define the min-content-specified guess as the set of column width assignments where:

Define the max-content guess as the set of column width assignments where:

Note that the assignable width is greater than or equal to the table width using the min-content guess, and that the widths for each column in the four guesses (min-content guess, min-content-percentage guess, min-content-specified guess, and max-content guess) are in nondecreasing order.

If the assignable width is less than or equal to the max-content guess, the used widths of the columns must be the linear combination (with weights adding to 1) of the two guesses whose width sums bound the available width.

Otherwise, the used widths of the columns are the result of starting from the max-content guess and distributing the excess width among the columns of the table according to the rules for distributing excess width to columns for used width calculation.

Distributing excess width to columns

The rules for distributing excess width to columns can be invoked in two ways: for distributing the excess width of a table to its columns during the computation of the used widths of those columns (for used width calculation), or for distributing the excess max-content or min-content width of a column-spanning cell to the max-content or min-content widths of the columns it spans (for intrinsic width calculation). The rules for these two cases are largely the same, but there are slight differences. The remainder of this section uses the term distributed width to refer to the one of these widths that is being distributed, and the excess width is used to refer to the amount by which the width being distributed exceeds the sum of the distributed widths of the columns it is being distributed to.

If there are non-constrained columns that have originating cells with intrinsic percentage width of 0% and with nonzero max-content width (columns allowed to grow by this rule), the distributed widths of the columns allowed to grow by this rule are increased in proportion to max-content width so the total increase adds to the excess width.

Otherwise, if there are non-constrained columns that have originating cells with intrinsic percentage width of 0% (columns allowed to grow by this rule, which thanks to the previous rule must have zero max-content width), the distributed widths of the columns allowed to grow by this rule are increased by equal amounts so the total increase adds to the excess width.

Otherwise, if there are (constrained) columns with intrinsic percentage width of 0% and with nonzero max-content width (columns allowed to grow by this rule, which, due to other rules, must have originating cells), the distributed widths of the columns allowed to grow by this rule are increased in proportion to max-content width so the total increase adds to the excess width.

Otherwise, if there are columns with intrinsic percentage width greater than 0% (columns allowed to grow by this rule, which, due to other rules, must have originating cells), the distributed widths of the columns allowed to grow by this rule are increased in proportion to intrinsic percentage width so the total increase adds to the excess width.

Otherwise, the distributed widths of all columns that have originating cells are increased by equal amounts so the total increase adds to the excess width.

What if no columns have originating cells? Should the originating cells condition in the previous paragraph just be removed, or should, there be an additional "Otherwise" here?

Fixed Table Layout

Intrinsic widths of fixed layout tables

The min-content width of a fixed layout table is defined to be the total horizontal border spacing of the table plus the specified non-percentage widths on any columns and the specified non-percentage widths (adjusted by the cell intrinsic offsets, and divided by the number of spanned columns) on any cells in the first row of any columns whose width is 'auto'.

This algorithm doesn't work very well if a cell in the first row spans some columns with specified widths and some without.

Should a percentage width cell spanning columns with unspecified width cause the border-spacing that it spans to be subtracted from the min-content width?

The max-content width of a fixed layout table is defined to be infinitely large. This is compatible with existing implementations but not particularly useful. If it were changed, the rules for the computation of the width of a table would need to be changed to ignore it for fixed layout tables.

Outer intrinsic widths of tables

Does this all make sense for table-layout:fixed?

The outer min-content width of the non-caption part of tables and inline tables is defined to be max('min-width', the min-content width of the table, min('width', 'max-width')) adjusted by the table intrinsic offset.

The outer min-content width of tables and inline-tables with 'caption-side: top' or 'caption-side: bottom' is defined to be the larger of:

Define the outer min-content width of tables and inline-tables with 'caption-side: left' or 'caption-side: right'.

The outer max-content width of the non-caption part of tables and inline tables is defined to be max('min-width', min-content, min('width', 'max-width', max-content)) adjusted by the table intrinsic offset.

The outer max-content width of tables and inline-tables with 'caption-side: top' or 'caption-side: bottom' is defined to be the larger of:

Define the outer max-content width of tables and inline-tables with 'caption-side: left' or 'caption-side: right'.

Computing cell widths

Define how to compute used cell widths from column widths, column-span, border-spacing, and border and padding properties.

Computing table widths

Define how the used width of a table is computed from the available width, its intrinsic widths, and the computed values of the width properties. This gets complicated with side captions, and with the differences in offsets between border models. But ignoring those, the basic idea is the same as the shrink-to-fit width that CSS2.1 defines for floating, non-replaced elements or for absolutely positioned, non-replaced elements, except that a specified width is just a lower bound.

Proposal for new keywords for intrinsic sizes

This section proposes adding four new values to the 'width', 'max-width', 'min-width', 'height', 'max-height', and 'min-height' properties. The following definitions apply to 'width', 'max-width', and 'min-width' when the inline progression direction is horizontal (the only possibility in CSS Level 2) and to 'height', 'max-height', and 'min-height' when the inline progression direction is vertical (possible starting in CSS Level 3):

max-content
the max-content width/height
min-content
the min-content width/height
available
the containing block width/height minus horizontal margin, border, and padding Do I need to mention scrollbar widths?
fit-content
For 'width'/'height', the expression max('min-content', min('max-content', 'fill')). For 'max-width'/'max-height', a synonym for 'max-content'. For 'min-width'/'min-height', a synonym for 'min-content'.

When the inline progression direction is horizontal (vertical), then all four of these values act like 'auto' for 'width' ('height'), like 'none' for 'max-width' ('max-height'), and like '0' for 'min-width' ('min-height').

As for 'width: auto' and 'max-width: none', changing the value of 'box-sizing' must not change the behavior of these values.

Note that 'width: fit-content' is the same as 'width: auto' for floats and tables, and 'width: available' is the same as 'width: auto' for blocks in the normal flow.

When computing outer intrinsic widths, the 'available' value on all properties and the 'fit-content' value on the 'width' property must behave exactly like the default value for the property ('width: auto', 'max-width: none', 'min-width: 0').

On table columns and table column groups, all values must behave like the default value of the property ('width: auto', 'max-width: none', 'min-width: 0').

These values were implemented in Mozilla, with -moz- prefixes, in bug 311415 (with different names) and bug 402706 (to update the names to the above, with -moz- prefixes).

Tests

Some testcases are available at http://dbaron.org/css/test/intrinsic/, but more need to be developed. The examples at http://dbaron.org/css/test/2004/intrinsic/ and http://dbaron.org/css/test/2006/intrinsic-examples/ were also useful in developing this specification.

Tests for the new values for 'width', 'max-width', and 'min-width' are available in the Mozilla source tree in the filenames width-special-values-* and box-sizing-* in the directory layout/reftests/box-properties. The file reftest.list in that directory gives the pass conditions.

Changes since version dated 29 August 2006 (i.e., in version dated 01 November 2006)

Changes since version dated 01 November 2006 (i.e., in version dated 09 May 2007)

Changes since version dated 09 May 2007 (i.e., in version dated 11 May 2007)

Changes since version dated 11 May 2007 (i.e., in version dated 13 May 2007)

Changes since version dated 13 May 2007 (i.e., in the version dated 14 May 2007)

Changes since version dated 14 May 2007

Changes since version dated 14 November 2007

Changes since version dated 09 March 2011

Changes since version dated 21 March 2012

Changes since version dated 02 January 2013

Informative references

[CSS2]
Bert Bos, Håkon Wium Lie, Chris Lilley, Ian Jacobs. Cascading Style Sheets, level 2. 12 May 1998. W3C Recommendation. URL: http://www.w3.org/TR/1998/REC-CSS2-19980512/
[CSS21]
Bert Bos, Tantek Çelik, Ian Hickson, Håkon Wium Lie. Cascading Style Sheets, level 2 revision 1. 11 April 2006. W3C Working Draft. URL: http://www.w3.org/TR/2006/WD-CSS21-20060411/