CSS Table Module Level 3

Editor’s Draft,

This version:
https://drafts.csswg.org/css-tables-3/
Latest published version:
https://www.w3.org/TR/CSS2/tables.html
Issue Tracking:
Inline In Spec
GitHub Issues
Editors:
Francois Remy (Microsoft)
Greg Whitworth (Microsoft)
Former Editors:
Bert Bos (W3C)
David Baron (Mozilla)
Markus Mielke (Microsoft)
Saloni Mira Rai (Microsoft)

Abstract

This CSS module defines a two-dimensional grid-based layout system, optimized for tabular data rendering. In the table layout model, each display node is assigned to an intersection between a set of consecutive rows and a set of consecutive columns, themselves generated from the table structure and sized according to their content.

CSS is a language for describing the rendering of structured documents (such as HTML and XML) on screen, on paper, in speech, etc.

Status of this document

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

GitHub Issues are preferred for discussion of this specification. When filing an issue, please put the text “css-tables-3” in the title, preferably like this: “[css-tables-3] …summary of comment…”. All issues and comments are archived, and there is also a historical archive.

This document was produced by the CSS Working Group (part of the Style Activity).

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 September 2015 W3C Process Document.

1. Introduction

This section is not normative

Many types of information (ex: weather readings collected over the past year) are best visually represented in a two-axis grid where rows represent one item of the list (ex: a date, and the various weather properties measured during that day), and where columns represent the successive values of an items property (ex: the temperatures measured over the past year).

Sometimes, to make the representation easier to understand, some cells of the grid are used to represent a description or summary of their parent row/column, instead of actual data. This happens more frequently for the cells found on the first row and/or column (called headers) or the cells found on the last row and/or column (called footers).

This kind of tabular data representation is usually known as tables. Tables layout can be abused to render other grid-like representations like calendars or timelines, though authors should prefer other layout modes when the information being represented does not make sense as a data table.

The rendering of tables in HTML has been defined for a long time in the HTML specification. However, its interactions with features defined in CSS remained for a long time undefined. The goal of this specification is to define the expected behavior of user agents supporting both HTML tables and CSS.

Please be aware that some behaviors defined in this document will not be the most logical or useful way of solving the problem they aim to solve, but such behaviors are often the result of compatibility requirements and not a deliberate choice of the editors of this specification. Authors wishing to use more complex layouts are encouraged to rely on more modern CSS modules such as CSS Grids.

2. Content Model

2.1. Table Structure

The CSS table model is based on the HTML4 table model, in which the structure of a table closely parallels the visual layout of the table. In this model, a table consists of an optional caption and any number of rows of cells.

In addition, adjacent rows and columns may be grouped structurally and this grouping can be reflected in presentation (e.g., a border may be drawn around a group of rows).

The table model is said to be "row primary" since authors specify rows, not columns, explicitly in the document language. Columns are derived once all the rows have been specified: the first cell of the first row belongs to the first column and as many other columns as spanning requires (and it creates them if needed), and the following cells of that row each belong to the next available column and as many other columns as spanning requires (creating those if needed); the cells of the following rows each belong to the next available column for that row (taking rowspan into account) and as many other columns as spanning requires (creating those if needed). (see §3.3 Dimensioning the row/column grid).

To summarize, an instance of the table model consists of:

Two representations of the structure of a table (tree vs layout)

The CSS model does not require that the document language include elements that correspond to each of these components. For document languages (such as XML applications) that do not have pre-defined table elements, authors must map document language elements to table elements. This is done with the display property.

The following display values assign table formatting rules to an arbitrary element:

table (equivalent to HTML: <table>)
Specifies that an element defines a block-level table: it is a rectangular block that participates in a block formatting context.
inline-table (equivalent to HTML: <table>)
Specifies that an element defines an inline-level table: it is a rectangular block that participates in an inline formatting context).
table-row (equivalent to HTML: <tr>)
Specifies that an element is a row of cells.
table-row-group (equivalent to HTML: <tbody>)
Specifies that an element groups some amount of rows.
table-header-group (equivalent to HTML: <thead>)
Like table-row-group but, for layout purposes, the first such row group is always displayed before all other rows and row groups.
If a table contains multiple elements with display: table-header-group, only the first is rendered as a header; the others are treated as if they had display: table-row-group.
table-footer-group (equivalent to HTML: <tfoot>)
Like table-row-group but, for layout purposes, the fist such row group is always displayed after all other rows and row groups.
If a table contains multiple elements with display: table-footer-group, only the first is rendered as a footer; the others are treated as if they had display: table-row-group.
table-column (equivalent to HTML: <col>)
Specifies that an element describes a column of cells.
table-column-group (equivalent to HTML: <colgroup>)
Specifies that an element groups one or more columns.
table-cell (equivalent to HTML: <td> or <th>)
Specifies that an element represents a table cell.
table-caption (equivalent to HTML: <caption>)
Specifies a caption for the table. Table captions are positioned between the table margins and its borders.

Authors must not assign a display type from the previous list to replaced elements (like input fields or images). When the display property of a replaced element computes to one of these values, it is handled instead as would inline (for inline-table) or block (for all other values).
This is a breaking change from css 2.1 but matches implementations

2.1.1. Terminology

In addition to the table structure display types, the following wording is also being used in this spec:

table-root box or element
A table or inline-table box.
table-non-root box or element
A proper table child, or a table-cell box.
table-row-grouping box or element
A table-row-group, table-header-group, or table-footer-group box.
table-track box or element
A table-row, or table-column box.
table-track-grouping box or element
A table-row-grouping, or table-column-group box.
proper table child box or element
A table-track-grouping, table-track, or table-caption box.
proper table-row parent box or element
A table-root or a table-row-grouping box.
table-internal box or element
A table-cell, table-track or table-track-grouping box.
tabular container
A table-row or proper table-row parent box.
consecutive boxes
Two sibling boxes are consecutive if they have no intervening siblings other than, optionally, an anonymous inline containing only white spaces. A sequence of sibling boxes is consecutive if each box in the sequence is consecutive to the one before it in the sequence.
slot
A slot is an available space created by the intersection of a row and a column in the table grid.

We should define the table grid, table grid rows, table grid columns, and in general what spanning means for table-cells (e.g. a rowspanning table-cell, a colspanning table-cell, etc). Inspiration can be taken from CSS Grid and/or HTML.

2.2. Fixup

Document languages other than HTML may not contain all the elements in the CSS 2.1 table model. In these cases, the "missing" elements must be assumed in order for the table model to work.

Any table-internal element will automatically generate necessary anonymous table objects around itself, if necessary. Any descendant of a table-root that is not table-internal must have a set of ancestors in the table consisting of at least three nested objects corresponding to a table/inline-table element, a table-row element, and a table-cell element. Missing elements cause the generation of anonymous boxes according to the following rules:

2.2.1. Fixup Algorithm

For the purposes of these rules, out-of-flow elements are represented as inline elements of zero width and height. Their containing blocks are chosen accordingly.

The following steps are performed in three stages:

  1. Remove irrelevant boxes:
    1. Children of a table-column are treated as if they had display: none.
    2. Children of a table-column-group which are not a table-column are treated as if they had display: none.
    3. Anonymous inline boxes which contains only white space, are the first or last child of a tabular container, and whose immediately preceding or following sibling (if any) is a table-non-root element, are treated as if they had display: none.
    4. Anonymous inline boxes which contains only white space and are between two immediate siblings each of which is a table-non-root element, are treated as if they had display: none.
  2. Generate missing child wrappers:
    1. An anonymous table-row box must be generated around each sequence of consecutive children of a table-root box which are not proper table child boxes. !!Testcase
    2. An anonymous table-row box must be generated around each sequence of consecutive children of a table-row-grouping box which are not table-row boxes. !Testcase
    3. An anonymous table-cell box must be generated around each sequence of consecutive children of a table-row box which are not table-cell boxes. !Testcase
  3. Generate missing parents:
    1. An anonymous table-row box must be generated around each sequence of consecutive table-cell box whose parent is not a table-row. Testcase
    2. An anonymous table or inline-table box must be generated around each sequence of consecutive proper table child box which are misparented. If the box’s parent is an inline box, then an inline-table box must be generated; otherwise it must be a table box. Testcase Testcase !Testcase
Please note that some layout modes such as flexbox and grid override the display type of their children. These transformations happen before the table fixup.

2.2.2. Examples

<div class="row">
  <div class="cell">George</div>
  <div class="cell">4287</div>
  <div class="cell">1998</div>
</div>

Here is the associated styles:

.row { display: table-row }
.cell { display: table-cell }

After fixup, this will produce layout boxes as though this was the initial HTML:

<table>
  <tr>
    <td>George</td>
    <td>4287</td>
    <td>1998</td>
  </tr>
</table>

In this example, three table-cell elements are assumed to contain the text in the ROWs. The text inside of the divs with a display: table-row are encapsulated in anonymous inline boxes, as explained in visual formatting model:

<div class="inline-table">
  <div class="row">This is the top row.</div>
  <div class="row">This is the middle row.</div>
  <div class="row">This is the bottom row.</div>
</div>
.inline-table { display: inline-table; }
.row { display: table-row; }

This will produce layout boxes as though this was the initial HTML:

<table>
  <tr>
    <td>This is the top row.</td>
  </tr>
  <tr>
    <td>This is the middle row.</td>
  </tr>
  <tr>
    <td>This is the bottom row.</td>
  </tr>
</table>

3. Layout

3.1. Core layout principles

Unlike other block-level elements, tables do not fill their containing block by default. When their width computes to auto, they behave as if they had fit-content specified instead. This is different from most block-level elements, which behave as if they had fill-available instead.

The min-content width of a table is the width required to fit all of its columns min-content widths and its undistributable spaces.

The max-content width of a table is the width required to fit all of its columns max-content widths and its undistributable spaces.

If the width assigned to a table is larger than its min-content width, the Available Width Distribution algorithm will adjust column widths in consequence.

This section overrides the general-purpose rules that apply to calculating widths described in other specifications. In particular, if the margins of a table are set to 0 and the width to auto, the table will not automatically size to fill its containing block. However, once the used value of width for the table is found (using the algorithms given below) then the other parts of those rules do apply. Therefore, a table can be centered using left and right auto margins, for instance.

3.2. Table layout algorithm

To layout a table, user agents must apply the following actions:

  1. Determine the number of rows/columns the table requires.
    This is done by executing the steps described in §3.3 Dimensioning the row/column grid.
  2. [A] If the row/column grid has at least one slot:
    1. Ensure each cell slot is occupied by at least one cell.
      This is done by executing the steps described in §3.4 Missing cells fixup.
    2. Compute the minimum width of each column.
      This is done by executing the steps described in §3.8 Computing table measures.
    3. Compute the width of the table.
      This is done by executing the steps described in §3.9.1 Computing the table width.
    4. Distribute the width of the table among columns.
      This is done by executing the steps described in §3.9.3 Distribution algorithm.
    5. Compute the height of the table.
      This is done by executing the steps described in §3.10.1 Computing the table height.
    6. Distribute the height of the table among rows.
      This is done by executing the steps described in §3.10.4 Distribution algorithm.

    [B] Else, if the table is empty:

    1. Compute the width of the table.
      This is done by returning the largest value of CAPMIN and the computed width of the table box (including borders and paddings) if it is definite (use zero otherwise).
    2. Compute the height of the table.
      This is done by returning the sum of all table-caption heights (their width being set to the table width, with margins taken into consideration appropriately) and the computed height of the table box (including borders and paddings) if it is definite (use zero otherwise).
  3. Assign to each table-caption and table-cell their position and size.
    This is done by running the steps of §3.11 Positioning of cells, captions and other internal table boxes.

The following schema describes the algorithm in a different way, to make it easier to understand.

Overview of the table layout algorithm. Not normative.

3.3. Dimensioning the row/column grid

Like mentioned in the Table structure section, how many rows and columns a table has can be determined from the table structure. Both dimensioning the row/column grid and assigning table-cells their slot(s) in that grid do require running the HTML Algorithms for tables.

CSS Boxes that do not originate from an HTML table element equivalent to their display type need to be converted to their HTML equivalent before we can apply this algorithm.

<ul class="table">
  <li><b>One</b><i>1</i></li>
  <li><b>Two</b><i>2</i></li>
  <li><b>Three</b><i>3</i></li>
</ul>
<style>
  ul.table { display: table; }
  ul.table > li { display: table-row; }
  ul.table > li > * { display: table-cell; }
</style>

produces the same row/column grid as

<table><tbody>
  <tr>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td>
  </tr>
</tbody></table>
<!-- built using dom api, as this would be fixed by the html parser -->
<grid style="display: table">
  <row style="display: table-row">
    <th rowspan="2">1</th>
    <colgroup style="display: table-cell" span="2" colspan="2">2</colgroup>
  </row>
  <tr>
    <td>A</td>
    <td>B</td>
    <td>C</td>
  </tr>
</grid>

produces the same row/column grid as

<table>
  <tr>
    <th rowspan="2">1</th>
    <td>2</td>
  </tr>
  <tr>
    <td>A</td>
    <td>B</td>
    <td>C</td>
  </tr>
</table>

Note how the second cell of the first row doesn’t have ```colspan=2``` applied, because its originating element is not an HTML TD element.

Testcase. !!Testcase. !Test case. !!Test case. !!Test case.

Apply the HTML5 Table Formatting algorithm on the HTMLified box tree, where boxes act like the HTML element equivalent to their display type, and use the attributes of their originating element only if it as an HTML element of the same type (otherwise, they act like if they didnt’t have any attribute).

The HTML Table Formatting algorithm sometimes generates more tracks than necessary to layout the table properly. Those tracks have historically been ignored by user agents, so the next step just gets rid of them entirely to avoid dealing with them as exceptions later in the spec.

Modify iteratively the obtained grid by merging consecutive tracks as follows: As long as there exists an eligible track in the obtained row/column grid such that there is no table-column/table-row box defining the said track explicitly, and both the said track and the previous one are spanned by the exact same set of cells, those two tracks must be merged into one single track for the purpose of computing the layout of the table. Change the spanning of the cells contained in those tracks accordingly so that no difference would be detectable in terms of slot assignment. (see spanning-ghost-rows test cases)

For tables in auto mode, every track is an eligible track for the purpose of the track-merging algorithm. For tables in fixed mode, only rows are eligible to be merged that way; which means that every column is preserved.

Finally, assign to the table-root element its correct number of rows and columns (from its mapped element), and to each table-cell element its accurate table-row-start/table-column-start/table-row-span/table-column-span (from its mapped element).

3.4. Missing cells fixup

The following section clarifies and extends the CSS 2.1 statement saying that missing cells are rendered as if an anonymous table-cell box occupied their position in the grid (a "missing cell" is a cell in the row/column grid that is not occupied by an element or pseudo-element).

Once the amount of columns in a table is known, any table-row-group element must be modified such that each of its rows contains enough cells to fill all the columns of the table, when taking spanning into account. New table-cell anonymous boxes must be appended to its rows content until this condition is met.

Beside their display type, those anonymous boxes do not receive any specific or default styling, except where otherwise mentioned by this specification (meaning their background is “transparent”, their padding is “0px” and their border is “none” by default).

3.5. Table layout modes

This section covers the flags which modify the way tables are being laid out. There are three major flags for table layout: table-layout, border-collapse, and caption-side. The border-collapse flag has an optional border-spacing parameter.

3.5.1. The Table-Layout property

Name: table-layout
Value: auto | fixed
Initial: auto
Applies to: table-root elements.
Inherited: yes
Percentages: n/a
Media: visual
Computed value: as specified
Canonical order: per grammar
Animation type: discrete

A table-root is said to be layouted in fixed mode whenever the computed value of the table-layout property is equal to fixed, and the specified width of the table root is either a <length-percentage>, min-content or fit-content. When the specified width is not one of those values, or if the computed value of the table-layout property is auto, then the table-root is said to be layouted in auto mode.

When a table-root is layouted in fixed mode, the content of its table-cells is ignored for the purpose of width computation, the aggregation algorithm for column sizing considers only table-cells belonging to the first row track, such that layout only depends on the values explicitly specified for the table-columns or cells of the first row of the table; columns with indefinite widths are attributed their fair share of the remaining space after the columns with a definite width have been considered, or 0px if there is no remaining space (see §3.8.3 Computing Column Measures).

3.5.2. The Border-Collapse property

Name: border-collapse
Value: separate | collapse
Initial: separate
Applies to: table-root elements.
Inherited: yes
Percentages: n/a
Media: visual
Computed value: as specified
Canonical order: per grammar
Animation type: discrete

When the border-collapse property has collapse as its value, the borders of adjacent cells are merged together such that each cell draws only half of the shared border. As a result, some other properties like border-spacing will not applied in this case (see §3.6.2 Overrides applying in collapsed-borders mode), (see §3.7 Border-collapsing).

A table-root element is said to be layouted in collapsed-borders mode in this case. Otherwhise, the table-root element is said to be layouted in separated-borders mode.

3.5.2.1. The Border-Spacing property
Name: border-spacing
Value: <​length​>{1,2}
Initial: 0px 0px
Applies to: table-root elements when border-collapse is separate.
Inherited: yes
Percentages: n/a
Media: visual
Computed value: two absolute lengths
Canonical order: per grammar
Animatable: yes

The lengths specify the distance that separates adjoining cell borders in separated-borders mode.

If one length is specified, it gives both the horizontal and vertical spacing. If two are specified, the first gives the horizontal spacing and the second the vertical spacing.

Lengths may not be negative.

See §3.8.1 Computing Undistributable Space for details on how this affects the table layout.

3.5.3. The Caption-Side property

Name: caption-side
Value: top | bottom
Initial: top
Applies to: table-caption elements
Inherited: yes
Percentages: n/a
Media: visual
Computed value: as specified
Canonical order: per grammar
Animation type: discrete

This property specifies the position of the caption box with respect to the table box. Values have the following meanings:

top
Positions the caption box above the table box.
bottom
Positions the caption box below the table box.
CSS2 described a different width and horizontal alignment behavior. That behavior was supposed to be introduced in CSS3 using the values top-outside and bottom-outside. #REF
Gecko also supports the "left" and "right" values. It was never well defined though. #REF
Gecko has a bug when dealing with multiple captions. !Testcase

To align caption content horizontally within the caption box, use the text-align property.

In this example, the caption-side property places captions below tables. The caption will be as wide as the parent of the table, and caption text will be left-justified.

caption {
  caption-side: bottom;
    width: auto;
    text-align: left
}

3.6. Style overrides

Some css properties behave differently inside css tables. The following sections list the exceptions and their effects.

3.6.1. Overrides applying in all modes

The following rules apply to all table elements, irrespective of the layout mode in use:

3.6.2. Overrides applying in collapsed-borders mode

When a table is layouted in collapsed-borders mode, the following rules apply:

3.7. Border-collapsing

This section explains what is border-collapsing, and how to apply it on a table.

This entire section is a proposal to make the rendering of collapsed borders sane. As implementations diverge very visibly, it is expected to require more discussion than some other parts. Since browsers handle this so differently, convergence cannot happen without reimplementation. A major concern for this proposal was to support as many cases as possible, and yet keep the effort required for a new implementation of tables as low as possible.

Background: CSS+HTML allow unprecedented combinations of border modes for table junctions, and it makes it difficult to support all cases properly; in fact some combinations are not well-posed problems, so no rendering algorithm could be optimal.

Because they grew from something simple (HTML) to something very complex (HTML+CSS), the current table rendering models (backgrounds and borders) used by web browsers are insane (in the sense they are buggy, not interoperable and not CSSish at all). Many usual CSS assumptions are broken, and renderings diverge widely.

This proposal aims at fixing this situation.

This proposal does not respect these stated CSS 2.1 requirements:
UAs must compute an initial left and right border width for the table by examining the first and last cells in the first row of the table. The left border width of the table is half of the first cell’s collapsed left border, and the right border width of the table is half of the last cell’s collapsed right border. If subsequent rows have larger collapsed left and right borders, then any excess spills into the margin area of the table.
This proposal is doing worse than Edge and Firefox (but better than Chrome) when row- or colspanned cells have border styles which conflict with their neighbors, and those neighbors have different styles which conflict with each other. This is a necessary trade-of to make the model sane.

3.7.1. Conflict Resolution for Collapsed Borders

When they are layouted in collapsed-borders mode, table-root and table-cell elements sharing a border attempt to unify their borders so that they render using the same style, width, and color (whenever this is possible). This is accomplished by running the following algorithm.

3.7.1.1. Conflict Resolution Algorithm for Collapsed Borders
For the purpose of this algorithm, “harmonizing” a set of borders means applying the “Harmonization Algorithm for Collapsed Borders” on the given set of borders, and set those borders' used values to the value resulting from the algorithm, except for cells having a border-image-source different from none: those keep their initial values.

For any table-cell element C° of a table-root element:

Then, for that table-root element:

Implementations may of course choose to skip some of the steps of the previous algorithm, provided they can prove those have no visible impact on the final results; certain borders are harmonized more than once using the previous steps which is completely unnecessary, but preventing this would make the spec harder to read.
To help the reader get a better idea of what this algorithm is doing, the main steps of applying the previous algorithm over a sample table have been outlined here:

https://jsfiddle.net/bn3d1sm4/
https://jsfiddle.net/bn3d1sm4/1/
https://jsfiddle.net/bn3d1sm4/2/

https://jsfiddle.net/bn3d1sm4/15/
3.7.1.2. Harmonization Algorithm for Collapsed Borders
For the purpose of this algorithm, “considering” a border’s properties means that “if its properties are more specific than CurrentlyWinningBorderProperties, set CurrentlyWinningBorderProperties to its properties”.
There is an outstanding proposal from Fantasai to change the "more specific than" part of these rules to "as specific or more than". This would change the priority order from cell, track, track-group, table to table, track-group, track, cell.

Given an ordered set of borders (BC1, BC2, … located in cells C1, C2, …) execute the following algorithm to determine the used value of the border properties for those conflicting borders.

3.7.1.3. Specificity of a border style

Given two borders styles, the border style having the most specificity is the border style which…

  1. … has the value "hidden" as border-style, if only one does
  2. … has the biggest border-width, once converted into css pixels
  3. … has the border-style which comes first in the following list:
    double, solid, dashed, dotted, ridge, outset, groove, inset, none

If none of these criterion matches, then both borders share the same specificity.

3.8. Computing table measures

3.8.1. Computing Undistributable Space

This section will deal with the undistributable space of the table.

The undistributable space of the table is the sum of the distances between the borders of consecutive table-cells (and between the border of the table-root and the table-cells).

The distance between the borders of two consecutive table-cells is the border-spacing, if any.

The distance between the table border and the borders of the cells on the edge of the table is the table’s padding for that side, plus the relevant border spacing distance (if any).

For example, on the right hand side, the distance is padding-right + horizontal border-spacing.

3.8.2. Computing Cell Measures

This section will deal with the measurement of a cell.

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:
  • In separated-borders mode: the computed horizontal padding and border of the table-cell
  • In collapsed-borders mode: the computed horizontal padding of the cell and, for border values, the used border-width values of the cell (half the winning border-width)
table intrinsic offsets
The table intrinsic offsets 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:
  • In separated-borders mode: the computed horizontal padding and border of the table-root
  • In collapsed-borders mode: the used border-width values of the cell (half the winning border-width)
    Is this the correct way to account for the various changes that have gone into CSS2.1 regarding which border sticks out into the margin?

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? I don’t think so because they are resolved based on parent anyway
total horizontal border spacing
The total horizontal border spacing is defined for each table:
  • For tables layouted in separated-borders mode containing at least one column, the horizontal component of the computed value of the border-spacing property times one plus the number of columns in the table
  • Otherwise, 0
outer min-content and outer max-content widths
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 outer min-content width of a table cell is max(min-width, min(max-width, min-content width)) adjusted by the cell intrinsic offsets.
    Should max-width really be able to override the min-content width? An alternative expression is max(min-width, min-content width) @ FR: I think we should choose this option.
    Should min-width affect outer min-content widths at all? @ FR: I think it should, yes. That’s interoperable.
  • The outer min-content width of a table column or column group is min-width.
    Should min-width affect outer min-content widths at all?
  • The outer max-content width of a table cell in a non-constrained column is max(min-width, min(max-width, max-content width)) adjusted by the cell intrinsic offsets.
    Should max-width be able to override the intrinsic min-content width? An alternative expression is max(min-width, min-content width, min(max-width, max-content width).
  • The outer max-content width of a table cell in a constrained column is max(min-width, min(max-width, max(width, min-content width))) adjusted by the cell intrinsic offsets.
    Should max-width be able to override the min-content width? An alternative expression is max(min-width, min-content width, min(max-width, width)).
  • The outer max-content width of a table column or column group is max(min-width, min(max-width, width)).
percentage contributions
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:

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.

3.8.3. Computing Column Measures

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.

For the purpose of measuring a column when layouted in fixed mode, only cells which originate in the first row of the table (after reordering the header and footer) will be considered, if any. In addition, the min-content and max-content width of cells is considered zero unless they are directly specified as a length-percentage, in which case they are resolved based on the table width (if it is definite, otherwise use 0).

For the purpose of calculating the outer min-content width of cells, descendants of table cells whose width depends on percentages of their parent cell' width are considered to have an auto width if they have overflow set to visible, and a 0px height if they have not.

intermediate min-content width for span 1
The largest of:
  • the outer min-content width of the column group, if any
  • the outer min-content width of the column, if any
  • the outer min-content width of each cell in the column whose column-span is 1 (or just the one in the first row in fixed mode) or 0 if there is none
intermediate max-content width for span 1
The largest of:
  • the outer max-content width of the column group, if any
  • the outer max-content width of the column, if any
  • the outer max-content width of each cell in the column whose column-span is 1 (or just the one in the first row if in fixed mode) or 0 if there is no such cell
intermediate intrinsic percentage width for span 1
The largest of the percentage contributions of each cell in the column whose column-span is 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 is 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 horizontal border-spacing for any columns spanned by the cell, other than the one in which the cell originates.
  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 is 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 horizontal border-spacing for any columns spanned by the cell, other than the one in which the cell originates.
  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 is 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
    • the column’s non-spanning max-content width to
    • 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:
  • intermediate intrinsic percentage width for span N, where N is the number of columns in the table
  • 100% minus the sum of the intrinsic percentage width of all prior columns in the table (further left (right) when direction is "ltr" ("rtl"))

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?
In a future revision of this specification, this algorithm will need 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 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 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. FR: Not sure what this means
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?)

3.9. Available Width Distribution

3.9.1. Computing the table width

Before deciding on the final width of all columns, it is necessary to compute the width of the table itself.

As noted before, this would usually be the sum of preferred width of all columns, plus any extra. In this case, the width distribution will result in giving each column its preferred width. There are however a few cases where the author asks for some other width explicitly, as well as a few cases where the table cannot be given the width it requires.

The caption width minimum (CAPMIN) is the largest of the table captions min-content contribution.

The row/column-grid width minimum (GRIDMIN) width is the sum of the min-content width of all the columns plus cell spacing or borders.

The row/column-grid width maximum (GRIDMAX) width is the sum of the max-content width of all the columns plus cell spacing or borders.

Column and caption widths influence the final table width as follows:

The assignable table width can easily be determined from the table used width. This is the width that we will be able to allocate to the columns.

In this algorithm, rows (and row groups) and columns (and column groups) both constrain and are constrained by the dimensions of the cells they contain. Setting the width of a column may indirectly influence the height of a row, and vice versa.

3.9.2. Core distribution principles

This section is not normative.

3.9.2.1. Rules

Ideally, each column should get its preferred width (usually its max-content width). However, the assignable table width calculated before may not be big or small enough to achieve this result, in which case the user agent must assign adhoc widths to columns as described in the width distribution algorith.

This algorithm follows three rules when determining a column’s used width:

Rule 1: When assigning preferred widths, specified percent columns have a higher priority than specified unit value columns, which have a higher priority than auto columns.

Rule 2: Columns using the same sizing type (eg: absolute, relative, auto) follow the same distribution method. For example, they all get their min-content width or they all get their max-content width.
There is one exception to this rule. When giving its preferred percent width on a percent column, the computed value may be smaller than the column min-content width. In this case, the column will be assigned its min-content width though the percent column group as a whole is still regarded as being assigned the preferred percent widths.

Rule 3: The sum of width assgined to all columns should be equal to the assignable table width.

3.9.2.2. Available sizings

All three types of columns have the following possible used widths.

  1. min-content width:
    The size required to fit the content of the column
  2. min-content width + delta:
    A value between the min-content and preferred widths
  3. preferred width:
    The size specified for the column, or the size required to fit the content of the column without breaking
  4. preferred width + delta
    A value larger than the preferred width

    The distribution algorithm defines those values and explains when to use them.

    3.9.3. Distribution algorithm

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

    For the purpose of this algorithm, we clarifty that the assignable table width is the used width of the table minus the total horizontal border spacing.

    1. Define the min-content guess as the set of column width assignments where each column is assigned its min-content width.
    2. Define the min-content-percentage guess as the set of column width assignments where:
      • each column with an intrinsic percentage width greater than 0% is assigned the larger of:
        • its intrinsic percentage width times the assignable width and
        • its min-content width.
      • all other columns are assigned their min-content width.
    3. Define the min-content-specified guess as the set of column width assignments where:
      • each column with an intrinsic percentage width greater than 0% is assigned the larger of:
        • its intrinsic percentage width times the assignable width and
        • its min-content width, and
      • any other column that is constrained is assigned its max-content width, and
      • all other columns are assigned their min-content width.
    4. Define the max-content guess as the set of column width assignments where:
      • each column with an intrinsic percentage width greater than 0% is assigned the larger of:
        • its intrinsic percentage width times the assignable width and
        • its min-content width
        • all other columns are assigned their max-content width.
        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 table 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 consecutive 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 to the columns of the table according to the rules for distributing excess width to columns for used width calculation.

        The following schema describes the algorithm in a different way, to make it easier to understand.

        Overview of the width distribution algorithm. Not normative.

        Edge and Chrome ignores "min-width: %" while Firefox applies it properly. Firefox continues to apply a "min-width: %" when a "width: px" is specified (the width is ignored). We should decide on what is the right behavior and make sure it is written in the spec.

        3.9.3.1. 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.

        1. If there are non-constrained columns that have originating cells with intrinsic percentage width of 0% and with nonzero max-content width (aka the 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.
        2. Otherwise, if there are non-constrained columns that have originating cells with intrinsic percentage width of 0% (aka the 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.
        3. Otherwise, if there are (constrained) columns with intrinsic percentage width of 0% and with nonzero max-content width (aka the 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.
        4. Otherwise, if there are columns with intrinsic percentage width greater than 0% (aka the 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.
        5. Otherwise, if there is any such column, the distributed widths of all columns that have originating cells are increased by equal amounts so the total increase adds to the excess width.
        6. Otherwise, the distributed widths of all columns are increased by equal amounts so the total increase adds to the excess width.
      These rules do not apply when the table is layouted in fixed mode. In this case, the simpler rules that follow apply instead:
      • If there are any columns with no width specified, the excess width is distributed in equally to such columns
      • otherwise, if there are columns with non-zero length widths from the base assignment, the excess width is distributed proportionally to width among those columns
      • otherwise, if there are columns with non-zero percentage widths from the base assignment, the excess width is distributed proportionally to percentage width among those columns
      • otherwise, the excess width is distributed equally to the zero-sized columns

      3.10. Available Height Distribution

      3.10.1. Computing the table height

      This section will deal with the measurement of a table (height).

      ?Testcase ?Testcase ?Testcase

      The height of a table is the sum of the table-row heights plus any cell spacing or borders. If the table has a height property with a value other than auto, it is treated as a minimum height, and will be distributed to the height of the table-rows.

      The minimum height of a table-row is the maximum of:

      • the row’s computed height (if definite, percentages being considered 0px)
      • the computed height of each cell spanning the current row exclusively (if definite, percentages being treated as 0px), and
      • the minimum height (ROWMIN) required by the cells spanning the row.

      ROWMIN is defined as the sum of the minimum height of the rows after a first row layout pass.

      Once the table height has been determined, a second row layout pass must happen to assign the correct minimum height to table rows, by taking percentages used in rows/cells specified height into account.

      Then, if the sum of the new heights of the table rows after this second pass is different from what is needed to fill the table height, the height distribution algorithm defined below is applied (either to size rows intermediately between their first minimum height and their new, or to increase the heights of rows beyond their new minimum height; in neither case, this will have an impact on the baseline of the rows).

      Once the final size of the table and the rows has been determined, the content of the table-cells must also go through a second layout pass, where this time percentage-based heights are resolved against their parent cell height.
      It is possible that this second layout pass (where height percentages are being resolved) will make some cell contents overflow their parent cell. This is by design.

      3.10.2. Row layout

      The minimum height of a row (without spanning-related height distribution) is defined as the height of an hypothetical linebox containing the cells originating in the row and where cells spanning multiple rows are considered having a height of 0px (but their correct baseline). In this hypothetical linebox, cell heights are considered auto, but their other properties are conserved.

      For the purpose of calculating this height, descendants of table cells whose height depends on percentages of their parent cell' height are considered to have an auto height if they have overflow set to visible, and a 0px height if they have not.

      The baseline of a cell is defined as the baseline of the first in-flow line box in the cell, or the first in-flow table-row in the cell, whichever comes first. If there is no such line box or table-row, the baseline is the bottom of content edge of the cell box.

      Here is how this works out in practice:

      td { vertical-align: baseline; outline: 3px solid silver; }
      img { float: left; clear: left; width: 32px; height: 32px; }
      img[title] { float: none; }
      
      <table><tr>
        <td>Baseline</td>
        <td>Baseline<table><tr><td>After</td></tr></table></td>
        <td><table><tr><td>Baseline</td></tr></table>After</td>
        <td><table align=right><tr><td>Before</td></tr></table><p>Baseline</p></td>
        <td><img src="http://w3.org/favicon.ico" /><p>Baseline</p></td>
        <td><img src="http://w3.org/favicon.ico" title="Baseline"/><br/><img src="http://w3.org/favicon.ico" title="After"/></td>
        <td><img src="http://w3.org/favicon.ico" /><img src="http://w3.org/favicon.ico" /></td>
      </tr></table>
      
      Rendering of this example in a compliant browser

      For the purposes of finding a baseline, in-flow boxes with a scrolling mechanisms (see the overflow property) must be considered as if scrolled to their origin position.

      The baseline of a cell may end up below its bottom border, see the example below.

      The cell in this example has a baseline below its bottom border:

      div { height: 0; overflow: hidden; }
      
      <table>
      <tr>
      <td>
      <div> Test </div>
      </td>
      </tr>
      </table>
      

      The vertical-align property of each table cell determines its alignment within the row. Each cell’s content has a baseline, a top, a middle, and a bottom, as does the row itself.

      In the context of table cells, values for vertical-align have the following meanings:

      baseline The baseline of the cell is put at the same height as the baseline of the first of the rows it spans (see below for the definition of baselines of cells and rows).
      top The top of the cell box is aligned with the top of the first row it spans.
      bottom The bottom of the cell box is aligned with the bottom of the last row it spans.
      middle The center of the cell is aligned with the center of the rows it spans.
      ... Other values do not apply to cells; the cell is aligned at the baseline instead.

      The maximum distance between the top of the cell box and the baseline over all cells that have 'vertical-align: baseline' is used to set the baseline of the row. If a row has no cell box aligned to its baseline, the baseline of that row is the bottom content edge of the lowest cell in the row.

      To avoid ambiguous situations, the alignment of cells proceeds in the following order:

      • First the cells that are aligned on their baseline are positioned. This will establish the baseline of the row.
      • Next the cells with 'vertical-align: top' are positioned. The row now has a top, possibly a baseline, and a provisional height, which is the distance from the top to the lowest bottom of the cells positioned so far.
      • If any of the remaining cells, those aligned at the bottom or the middle, have a height that is larger than the current height of the row, the height of the row will be increased to the maximum of those cells, by lowering the bottom.
      • Finally, assign their position to the remaining cells.

      Example showing how the previous algorithm creates the various alignment lines of a row.

      Diagram showing the effect of various values of vertical-align on table cells. Cell boxes 1 and 2 are aligned at their baselines. Cell box 2 has the largest height above the baseline, so that determines the baseline of the row.

      Since during row layout the specified heights of cells in the row were ignored and cells that were spanning more than one rows have not been sized correctly, their height will need to be eventually distributed to the set of rows they spanned. This is done by running the same algorithm as the column measurement for spans N>1, with the span=1 value being initialized with the largest of the resulting height of the previous row layout, and the largest specified height of cells that span this row only.

      Import the relevant section of §3.8.3 Computing Column Measures here.

      Rows that see their size increase as a result of applying these steps adjust by lowering their bottom.

      The cells whose position depended on the bottom of any updated row must be positioned correctly again in their respective rows.

      At this point, cell boxes that are smaller than the height of the rows they span receive extra top and/or bottom padding such that their content does not move vertically but their top and bottom edges meet the ones of the rows they span.

      Please note that heights being defined on row groups are being ignored by this algorithm

      3.10.3. Core distribution principles

      TODO. For current proposal, skip to §3.10.4 Distribution algorithm.

      Investigations on height distribution

      Initial analysis shows that there are indeed similarities between width and height distribution. There are also differences which I described here below:

      In many case, all browsers apply a distribution algorithm that favors percentages over pixels over auto. Case 6.

      A difference with the width distribution algorithm is that if the sum of all rows' heights is higher than 100%, then all browsers enter a completely different mode. Case 7. NOTE: The sum counts as well percentage heights and pixels heights, since at this point you can safely resolve percentages.

      In this case, pixel-tracks are sized properly first. Then, percentage tracks get the remaining space proportionally to their height percentage up to their height percentage. Finally, auto tracks get to fill the remaining space, if there is any auto track. If there is none, percentage tracks continue growing above their height percentage until all the space is filled. Case 9.

      The height distribution algorithm also caps the sum of percentage heights to 100% in all browsers but Edge. That means that some rows get an arbitrary 0% height. Case 8.

      In Edge and Firefox, empty tracks do not get an increased size by this distribution if there are filled auto tracks. In Chrome, empty tracks count as distributable tracks as well even if there are other auto tracks.

      Intersting test cases about min-content and content using percentage sizes:


      Chrome and Edge apply percentages on the final layout. All browsers work around them during the first pass by considering them 0% (Chrome) or by ignoring the declaration (Edge, Firefox). The difference of choice is visible in Case 12. Case 13.

      3.10.4. Distribution algorithm

      The first step is to attribute to each row its base size and its reference size.

      Its base size is the size it would have got if the table didn’t have a specified height (the one it was assigned when ROWMIN was evaluated).

      Its reference size is the largest of

      • its initial base height and
      • its new base height (the one evaluated during the second layout pass, where percentages used in rowgroups/rows/cells' specified heights were resolved according to the table height, instead of being ignored as 0px).

      The second step is to compute the final height of each row based on those sizes.

      If the table height is equal or smaller than sum of reference sizes, the final height assigned to each row will be the weighted mean of the base and the reference size that yields the correct total height.

      Else, if the table contains any “auto-height” row (a row whose size is only determined by its content size and none of the specified heights), each non-auto-height row receives its reference height and auto-height rows receive their reference size plus some increment which is equal to the height missing to amount to the specified table height divided by the amount of such rows.

      Else, all rows receive their reference size plus some increment which is equal to the height missing to amount to the specified table height divided by the amount of rows.

      The cells whose position depended on the bottom of any updated row must be positioned correctly again in their respective rows.

      At this point, cell boxes that are smaller than the height of the rows they span receive extra top and/or bottom padding such that their content does not move vertically but their top and bottom edges meet the ones of the rows they span.

      3.11. Positioning of cells, captions and other internal table boxes

      This section will explain where internal table boxes should be positioned.

      We need a resolution on what visibility:collapse does. The current proposal is to do like "hidden" but in addition use the following formula to shift back the next rows/columns to accomodate the disappearance of collapsed tracks. The total width/height of the table would not be affected, only the bounding client rectangles of the cells would be. !!Testcase. !!Testcase. !!Testcase.

      Once the width of each column and the height of each row of the table grid has been determined, the final step of algorithm is to assign to each table-internal box its final position.

      The position defined here is the position of the children inside the space reserved for the table, which excludes only its margins. This is because the captions of the table are somewhat outside the border-box area of the table.

      The position of any table-caption having "top" as caption-side within the table is defined as the rectangle whose:

      • width/height is:
        • the width/height assigned to the caption during layout
      • top location is the sum of:
        • the height reserved for previous top captions (including margins), if any
        • any necessary extra top margin remaining after collapsing margins with the previous caption, if any.
      • left location is the sum of:
        • the margin left of the caption
        • half of (the table width minus the width of caption and its total horizontal margin).

      The position of any table-cell, table-track, or table-track-grouping box within the table is defined as the rectangle whose:

      • width/height is the sum of:
        • the widths/heights of all spanned visible columns/rows
        • the horizontal/vertical border-spacing times the amount of spanned visible columns/rows minus one
      • left/top location is the sum of:
        • for top: the height reserved for top captions (including margins), if any
        • the padding-left/padding-top and border-left-width/border-top-width of the table
        • the widths/heights of all previous visible columns/rows
        • the horizontal/vertical border-spacing times the amount of previous visible columns/rows plus one
      For table-track and table-track-grouping elements, all tracks of the opposite direction to the grouping are considered spanned. For instance, a table-header-group is considered to span all the columns, and a table-column-group is considered to span all the rows.

      The position of any table-caption having "bottom" as caption-side within the table is defined as the rectangle whose:

      • width/height is:
        • the width/height assigned to the caption during layout
      • top location is the sum of:
        • the height reserved for top captions (including margins), if any
        • padding-top and border-top-width of the table
        • the height of all visible rows
        • padding-bottom and border-bottom-width of the table
        • the height reserved for previous bottom captions (including margins), if any
        • any necessary extra top margin remaining after collapsing margins with the previous bottom caption, if any.
      • left location is the sum of:
        • the margin left of the caption
        • half of (the table width minus the width of caption and its total horizontal margin).
      Cell overflow: If the table is layouted in fixed mode, if the content of some cell has grown more than the cell during its second layout pass or if some tracks spanned by visible cells are deemed not visible, the content of some cells may exceed the available space, and cause an overflow. Such overflow should behave exactly like if the cell was an absolutely positioned display:block box with the appropriate alignment in place to keep its content in place relative to its inline-start block-start corner (usually top left). !Testcase !Testcase Testcase
      Visible tracks: For the purpose of this algorithm, a column or row is considered a visible track if both of those conditions apply:
      • It is not explicitly defined by a table-column or table-row element, or:
        It is explicitly defined by a table-column or table-row element that does not have visibility:collapse
      • It is not logically contained in a table-column-grouping or table-row-grouping element, or:
        It is logically contained in a table-column-grouping or table-row-grouping element that does not have visibility:collapse
      A table with a caption above it, showing how the caption margins are totally nested inside the table margins, but are outside the border-box of the table nonetheless.
      Diagram of a table with a caption above it.

      4. Rendering

      4.1. Paint order of cells

      Table cells are painted in a table-root in DOM order as usual, independently of where cells end up actually being drawn.

      4.2. Empty cell rendering (separated-borders mode)

      Cells are empty unless they contain one or more of the following:

      • floating content, or
      • in-flow content (other than white space that has been collapsed away by the white-space property handling).
      Chrome simplified this to just matching :empty.
      Name: empty-cells
      Value: show | hide
      Initial: show
      Applies to: table-cell elements
      Inherited: yes
      Percentages: n/a
      Media: visual
      Computed value: as specified
      Canonical order: per grammar
      Animation type: discrete

      In collapsed-borders mode, this property has no effect.

      In separated-borders mode, this property controls the rendering of borders and backgrounds around cells that have no visible content.

      When this property has the value hide, no borders or backgrounds are drawn around/behind empty cells.

      Furthermore, if all the cells in a row have a value of hide and have no visible content, then the row has zero height and the vertical border-spacing applies to one side of the row only.

      The behavior of empty-cells:hide is a strange exception.

      1. Why not just say that the cell has "visibility: hidden"?
      2. Why not just say that the row has "display: none"? !!Testcase

      For example, take the following markup and css:

      <table>
        <td><span></span></td>
        <td></td>
        <td><span></span></td>
      </table>
      
      table {
        width: 500px; height: 300px;
        empty-cells: hide;
      }
      
      table { background: black; border: 10px solid black; }
      td { background: white; }
      
      table { border-spacing: 0px; }
      td { padding: 0; }
      

      The correct rendering of this code snippet is depicted here:

      Rendering of three columns whose middle one is hidden by empty-cells:hide

      4.3. Drawing backgrounds and borders

      4.3.1. Drawing table backgrounds and borders

      Unlike other boxes types, table and inline-table elements do not render their background and borders around their entire client rect. Indeed, the table captions are positioned between the table margins and its borders. Given backgrounds extends and original form the border-box area of an element (or one of the area contained inside the boder-box area like content-box), they are affected by this positioning scheme.

      The padding of the table is accounted around the area occupied by the row/column grid Borders of the table box are rendered around the area occupied by the row/column grid and its padding. That area which contains the borders is the rectangular area which comprises of the full width of the table box, but does not contain the vertical areas occupied by the captions or their margins.

      The border-box of the table is relative to the area described previously. The padding-box of the table is the rectangular area contained inside the border-box which does not interesct with the table borders (independently of whether the table draws them or not). The content-box of the table is the rectangular area contained inside the padding-box which does not interesct with the table paddings (this includes border-spacings at the edge of the table).

      4.3.1.1. Changes in collapsed-borders mode

      When a table is layouted in collapsed-borders mode, the rendering of its borders on and those of its table-cells is modified. The following rules describe in which way.

      The rules for background and borders painting defined in §4.3 Drawing backgrounds and borders still apply if they are not overriden.

      Borders of a table-root element are not layouted in collapsed-borders mode, except if the border-image property is set (or if the table has no cell).

      In this case, the border is drawn as if the table border was twice as big as its used value specify, and as if that excess was rendered inside the padding area of the table-root element.

      Even if they are not drawn by the table, the table borders still occupy their space in the layout. Cells will render those shared borders.

      4.3.2. Drawing cell backgrounds

      Anonymous table-cells added by the missing cells fixup step do not render any of their backgrounds.

      In addition to its own background, table-cell elements also render the backgrounds of the table-track and table-track-grouping elements in which they belong. This is actually different from simply inheriting their background because the background-origin and background-size computations will actually be done on the bounds of the grouping elements, and not on those of the cell.

      For the purposes of finding the background of each table cell, the different table elements may be thought of as being on six superimposed layers. The background set on an element in one of the layers will only be visible if the layers above it have a transparent background.

      Schema of table layers.

      1. The table background is being rendered by the table, and does not affect the cell background.
      2. The first background drawn by a cell is the background of its originating column group. For the purpose of background-positioning, it is expected that a column group occupies the largest possible area a single cell could occupy in the row/column grid while originating in the column group and not entering any column not part of the column group.
      3. The second background drawn by a cell is the background of its originating column. For the purpose of background-positioning, it is expected that a column occupies the largest possible area a single cell could occupy in the row/column grid while originating in the column and not entering any other column.
      4. The third background drawn by a cell is the background of its originating row group. For the purpose of background-positioning, it is expected that a row group occupies the largest possible area a single cell could occupy in the row/column grid while originating in the row group and not entering any row not part of the row group.
      5. The fourth background drawn by a cell is the background of its originating row. For the purpose of background-positioning, it is expected that a row occupies the largest possible area a single cell could occupy in the row/column grid while originating in the row and not entering any other row.
      6. The fifth background drawn by a cell is its own background. This is the one that appears on top once all backgrounds have been rendered.

      As the figure above shows, although all rows contain the same number of cells, not every cell may have specified content. In separated-borders mode, if the value of their empty-cells property is hide, these "empty" cells are not rendered at all, as if visibility: hidden was specified on them, letting the table background show through.

      4.3.3. Drawing cell borders

      In separated-borders mode, borders of table cells are rendered as usual.

      4.3.3.1. Changes in collapsed-borders mode

      Borders of a table-cell element are rendered in collapsed-borders mode as if the cell border was twice as big as its used value specify, and as if that excess was rendered in the margin area of the cell, with the added constraint that for each side of the border which isn’t located at one of the table edges, the border is actually clipped to the border-box drawing area as its real used value define except if the border-image property is set.

      If applying the previously-mentioned clipping behavior results in clipping a border over a non-integer amount of device pixels, browsers may decide to snap the clipping area to a device pixel instead by ceiling the x- and y-values of the clipping area. Ceiling the values ensures that in a normal writing mode, the cell which gets the contested pixels between multiple cells is actually the most top left one, which has a greater specificity than the other ones according to this spec. See §4.1 Paint order of cells and §3.7.1.1 Conflict Resolution Algorithm for Collapsed Borders.

      4.3.4. Border styles (collapsed-borders mode)

      Some of the values of the border-style have different meanings in tables in collapsed-borders mode than for other elements. Those definitions override the default behavior for border-style values.

      hidden

      Same as none, but also inhibits any other border (see §3.7.1.3 Specificity of a border style).

      inset

      Same as ridge.

      outset

      Same as groove.

      5. Fragmentation

      This section overrides any other behavior defined in the fragmentation specification.

      5.1. Breaking across fragmentainers

      When fragmenting a table, user agents must attempt to preserve the table rows unfragmented if their height is at least twice smaller than the table width. Other rows are said freely fragmentable.

      When a table doesn’t fit entirely in a fragmentainer, and the first row that does not fit in the fragmentainer is not freely fragmentable. the user agent has to insert some vertical gap between the rows located before and at the overflow point such that the two rows end up separated in sibling fragmentainers. Cells spanning across those two rows are divided into two fragments (one in each fragmentainer), whose height is kept equal to the rows they span in each of these fragments, and their content is fragmented among those two fragments, in parallel.

      Expected rendering of table fragmented across two pages

      When there is no row fitting entirely in the current fragmentainer or when the first row that does not fit in the fragmentainer is freely fragmentable, user agents must split each cell of the row in two fragments (one in each fragmentainer) so that all fragments in the same fragmentainer continue to share the same height. Then, the user agent must fragment the content of each cell among its two fragments, in parallel.

      Expected rendering of table containing a tall row fragmented across two pages

      When break-before or break-after is applied to a table-row-grouping or a table-row box, the user agent has to insert some horizontal gap between the rows located before and after the breaking point such that the two rows end up separated in sibling fragmentainers as required by the property value.

      5.2. Repeating headers across pages

      When rendering the document into a paged media, user agents must repeat header rows and footer rows on each page spanned by a table.

      When the header rows are being repeated, user agents must leave room and if needed render the table top border. The same applies for footer rows and the table bottom border.

      Expected rendering of table with headers and footers fragmented across two pages

      When doing so doesn’t leave enough space to insert at least one content row, users agents must drop the repeated footer.

      When doing so still doesn’t leave enough space to insert at least one content row, users agents must drop the repeated header.

      User agents may decide to extend this behavior to every fragmentation context, and not just to the main document’s paging fragmentation context. User-agents that are rendering static documents are more likely to adopt this behavior, though this is not required per spec.

      6. Security Considerations

      Using CSS Tables does not incur any security risk to mitigate.

      7. Privacy Considerations

      Using CSS Tables does not incur any privacy risk to mitigate.

      8. List of bugs being tracked

      This section is not normative.

      9. Appendices

      9.1. Mapping between CSS & HTML attributes

      The default style sheet for HTML4 illustrates how its model maps to css properties and values:

      Some extensions to CSS have been used for contraints not mappable to current CSS constructs
      table    { display: table }
      thead    { display: table-header-group }
      tbody    { display: table-row-group }
      tfoot    { display: table-footer-group }
      tr       { display: table-row }
      td, th   { display: table-cell }
      colgroup { display: table-column-group }
      col      { display: table-column }
      caption  { display: table-caption }
      table, thead, tbody, tfoot, tr, td, th, colgroup, col, caption { box-sizing: border-box; }
      
      table {
        box-sizing: border-box;
        border-spacing: 2px;
        border-collapse: separate;
        text-indent: initial;
      }
      
      thead, tbody, tfoot, table > tr { vertical-align: middle; }
      tr, td, th { vertical-align: inherit; }
      
      td, th { padding: 1px; }
      th { font-weight: bold;  }
      
      table, td, th { border-color: gray; }
      thead, tbody, tfoot, tr { border-color: inherit; }
      
      
      
      table[frame=box i], table[frame=border i], table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
        border: 1px solid inset;
      }
      
      
      table:matches([rules=all i], [rules=rows i], [rules=cols i], [rules=groups i], [rules=none i]) {
        border-collapse: collapse;
        border-style: hidden;
      }
      
      table:matches([rules=all i], [rules=rows i], [rules=cols i], [rules=groups i], [rules=none i]),
      table:matches([rules=all i], [rules=rows i], [rules=cols i], [rules=groups i], [rules=none i]) > :matches(thead,tbody,tfoot) > tr > :matches(th,td) {
        border-color: black;
      }
      
      table[border=$border] /* if(parseInt($border) > 0) */ {
        border: /*(parseInt($border) * 1px)*/ outset rgb(128, 128, 128);
      }
      table[border=$border] > :matches(thead,tbody,tfoot) > tr > :matches(th,td) /* if(parseInt($border) > 0) */ {
        border: 1px inset rgb(128, 128, 128);
      }
      
      table[rules=all i] > :matches(thead,tbody,tfoot) > tr > :matches(th,td) {
        border: 1px solid grey;
      }
      table[rules=rows i] > :matches(thead,tbody,tfoot) > tr > :matches(th,td) {
        border: 1px solid grey;
        border-left: none;
        border-right: none;
      }
      table[rules=cols i] > :matches(thead,tbody,tfoot) > tr > :matches(th,td) {
        border: 1px solid grey;
        border-top: none;
        border-bottom: none;
      }
      table[rules=none i] > :matches(thead,tbody,tfoot) > tr > :matches(th,td) {
        border: none;
      }
      
      table[rules=groups i] > :matches(thead,tbody,tfoot) {
        border-top-width: 1px; border-top-style: solid;
        border-bottom-width: 1px; border-bottom-style: solid;
      }
      table[rules=groups i] > colgroup {
        border-left-width: 1px; border-left-style: solid;
        border-right-width: 1px; border-right-style: solid;
      }
      
      table[frame=box i], table[frame=border i], table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
        border-style: outset;
      }
      table[frame=below i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
        border-top-style: hidden;
      }
      table[frame=above i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
        border-bottom-style: hidden;
      }
      table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=rhs i] {
        border-left-style: hidden;
      }
      table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=rhs i] {
        border-right-style: hidden;
      }
      
      table[cellpadding=$x] > :matches(thead,tbody,tfoot) > tr > :matches(th,td) /* if(parseInt($x)>0) */ {
        padding: /*(parseInt($x) * 1px)*/;
      }
      table[cellspacing=$x] /* if(parseInt($x)>0) */ {
        border-spacing: /*(parseInt($x) * 1px)*/;
      }
      
      
      table[width=$w] /* if(parseInt($w) > 0) */ {
        width: /*(parseInt($w) * 1px)*/;
      }
      table[width=$w] /* if($w matches /(+|-|)([0-9]+([.][0-9]+|)|([.][0-9]+))[%]/) */ {
        width: /*(parseInt($w) * 1px)*/;
      }
      table[height=$h] /* if(parseInt($h) > 0) {
        height: /*(parseInt($h) * 1px)*/;
      }
      table[height=$h] /* if($h matches /(+|-|)([0-9]+([.][0-9]+|)|([.][0-9]+))[%]/) */ {
        height: /*(parseInt($h) * 1px)*/;
      }
      
      
      table[bordercolor=$color] {
        border-color: /*parseHTMLColor($color)*/;
      }
      table[bordercolor] > :matches(tbody, thead, tfoot, tr, colgroup, col), 
      table[bordercolor] > :matches(tbody, thead, tfoot) > tr,
      table[bordercolor] > :matches(tbody, thead, tfoot) > tr > :matches(td, th),
      table[bordercolor] > tr > :matches(td, th)
      table[bordercolor] > colgroup > col
      ) {
        border-color: inherit;
      }
      table[bgcolor=$color] {
        background-color: /*parseHTMLColor($color)*/;
      }
      table[align=left i] {
        float: left;
      }
      table[align=right i] {
        float: right;
      }
      table[align=center i] {
        margin-left: auto;
        margin-right: auto;
      }
      
      caption[align=bottom i] { caption-side: bottom; }
      :matches(thead,tbody,tfoot,tr,td,th)[valign=top i] {
        vertical-align: top;
      }
      :matches(thead,tbody,tfoot,tr,td,th)[valign=middle i] {
        vertical-align: middle;
      }
      :matches(thead,tbody,tfoot,tr,td,th)[valign=bottom i] {
        vertical-align: bottom;
      }
      :matches(thead,tbody,tfoot,tr,td,th)[valign=baseline i] {
        vertical-align: baseline;
      }
      
      :matches(thead,tbody,tfoot,tr,td,th)[align=absmiddle i] {
        text-align: center;
      }
      
      :matches(colgroup,col,thead,tbody,tfoot,tr,td,th)[hidden] {
        visibility: collapse;
      }
      
      :matches(td,th)[nowrap] { white-space: nowrap; }
      :matches(td,th)[nowrap][width=$w] /* if(quirksMode && parseInt($w) > 0) */ {
        white-space: normal;
      }
      
      Some of the content here came from the WHATWG spec on the HTML to CSS mapping of tables. However, since they include things which are not true in most browsers, this is not a simple copy. Investigations are therefore required for each and any merge being made from one source to another!

      10. (link here for missing sections)

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Advisements are normative sections styled to evoke special attention and are set apart from other normative text with <strong class="advisement">, like this: UAs MUST provide an accessible alternative.

Conformance classes

Conformance to this specification is defined for three conformance classes:

style sheet
A CSS style sheet.
renderer
A UA that interprets the semantics of a style sheet and renders documents that use them.
authoring tool
A UA that writes a style sheet.

A style sheet is conformant to this specification if all of its statements that use syntax defined in this module are valid according to the generic CSS grammar and the individual grammars of each feature defined in this module.

A renderer is conformant to this specification if, in addition to interpreting the style sheet as defined by the appropriate specifications, it supports all the features defined by this specification by parsing them correctly and rendering the document accordingly. However, the inability of a UA to correctly render a document due to limitations of the device does not make the UA non-conformant. (For example, a UA is not required to render color on a monochrome monitor.)

An authoring tool is conformant to this specification if it writes style sheets that are syntactically correct according to the generic CSS grammar and the individual grammars of each feature in this module, and meet all other conformance requirements of style sheets as described in this module.

Requirements for Responsible Implementation of CSS

The following sections define several conformance requirements for implementing CSS responsibly, in a way that promotes interoperability in the present and future.

Partial Implementations

So that authors can exploit the forward-compatible parsing rules to assign fallback values, CSS renderers must treat as invalid (and ignore as appropriate) any at-rules, properties, property values, keywords, and other syntactic constructs for which they have no usable level of support. In particular, user agents must not selectively ignore unsupported property values and honor supported values in a single multi-value property declaration: if any value is considered invalid (as unsupported values must be), CSS requires that the entire declaration be ignored.

Implementations of Unstable and Proprietary Features

To avoid clashes with future stable CSS features, the CSSWG recommends following best practices for the implementation of unstable features and proprietary extensions to CSS.

Implementations of CR-level Features

Once a specification reaches the Candidate Recommendation stage, implementers should release an unprefixed implementation of any CR-level feature they can demonstrate to be correctly implemented according to spec, and should avoid exposing a prefixed variant of that feature.

To establish and maintain the interoperability of CSS across implementations, the CSS Working Group requests that non-experimental CSS renderers submit an implementation report (and, if necessary, the testcases used for that implementation report) to the W3C before releasing an unprefixed implementation of any CSS features. Testcases submitted to W3C are subject to review and correction by the CSS Working Group.

Further information on submitting testcases and implementation reports can be found from on the CSS Working Group’s website at http://www.w3.org/Style/CSS/Test/. Questions should be directed to the public-css-testsuite@w3.org mailing list.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-BACKGROUNDS-3]
CSS Backgrounds and Borders Module Level 3 URL: https://drafts.csswg.org/css-backgrounds-3/
[CSS-BREAK-3]
Rossen Atanassov; Elika Etemad. CSS Fragmentation Module Level 3. 14 January 2016. CR. URL: http://dev.w3.org/csswg/css-break/
[CSS-COLOR-4]
Tab Atkins Jr.; Chris Lilley. CSS Color Module Level 4. 5 July 2016. WD. URL: https://drafts.csswg.org/css-color/
[CSS-DISPLAY-3]
Tab Atkins Jr.; Elika Etemad. CSS Display Module Level 3. 15 October 2015. WD. URL: http://dev.w3.org/csswg/css-display/
[CSS-OVERFLOW-4]
CSS Overflow Module Level 4 URL: https://drafts.csswg.org/css-overflow-4/
[CSS-SIZING-4]
CSS Intrinsic & Extrinsic Sizing Module Level 4 URL: https://drafts.csswg.org/css-sizing-4/
[CSS-TEXT-3]
Elika Etemad; Koji Ishii. CSS Text Module Level 3. 10 October 2013. LCWD. URL: http://dev.w3.org/csswg/css-text-3/
[CSS-TRANSFORMS-1]
Simon Fraser; et al. CSS Transforms Module Level 1. 26 November 2013. WD. URL: http://dev.w3.org/csswg/css-transforms/
[CSS-UI-3]
Tantek Çelik; Florian Rivoal. CSS Basic User Interface Module Level 3 (CSS3 UI). 7 July 2015. CR. URL: http://dev.w3.org/csswg/css-ui/
[CSS-VALUES]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 11 June 2015. CR. URL: http://dev.w3.org/csswg/css-values/
[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 7 June 2011. REC. URL: https://www.w3.org/TR/CSS2
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119

Property Index

Name Value Initial Applies to Inh. %ages Media Ani­mat­able Anim­ation type Canonical order Com­puted value
table-layout auto | fixed auto table-root elements. yes n/a visual discrete per grammar as specified
border-collapse separate | collapse separate table-root elements. yes n/a visual discrete per grammar as specified
border-spacing <​length​>{1,2} 0px 0px table-root elements when border-collapse is separate. yes n/a visual yes per grammar two absolute lengths
caption-side top | bottom top table-caption elements yes n/a visual discrete per grammar as specified
empty-cells show | hide show table-cell elements yes n/a visual discrete per grammar as specified

Issues Index

This is a breaking change from css 2.1 but matches implementations
We should define the table grid, table grid rows, table grid columns, and in general what spanning means for table-cells (e.g. a rowspanning table-cell, a colspanning table-cell, etc). Inspiration can be taken from CSS Grid and/or HTML.
This is a spec breaking change from the previous spec, but not a real breaking change. Border-radius only (incorrectly) works in IE/Edge and does not work in FF/Chrome. Actually, this isn’t even totally true, as box-shadow shows: https://jsfiddle.net/wazhrfe3/1/
This proposal does not respect these stated CSS 2.1 requirements:
UAs must compute an initial left and right border width for the table by examining the first and last cells in the first row of the table. The left border width of the table is half of the first cell’s collapsed left border, and the right border width of the table is half of the last cell’s collapsed right border. If subsequent rows have larger collapsed left and right borders, then any excess spills into the margin area of the table.
This proposal is doing worse than Edge and Firefox (but better than Chrome) when row- or colspanned cells have border styles which conflict with their neighbors, and those neighbors have different styles which conflict with each other. This is a necessary trade-of to make the model sane.
There is an outstanding proposal from Fantasai to change the "more specific than" part of these rules to "as specific or more than". This would change the priority order from cell, track, track-group, table to table, track-group, track, cell.
Is this the correct way to account for the various changes that have gone into CSS2.1 regarding which border sticks out into the margin?
But doesn’t that break handling of percentage padding? I don’t think so because they are resolved based on parent anyway
Should max-width really be able to override the min-content width? An alternative expression is max(min-width, min-content width) @ FR: I think we should choose this option.
Should min-width affect outer min-content widths at all? @ FR: I think it should, yes. That’s interoperable.
Should min-width affect outer min-content widths at all?
Should max-width be able to override the intrinsic min-content width? An alternative expression is max(min-width, min-content width, min(max-width, max-content width).
Should max-width be able to override the min-content width? An alternative expression is max(min-width, min-content width, min(max-width, width)).
These definitions need to account for the box-sizing property.
Do we need intermediate constrainedness? It’s easier to implement that way, but does it actually make any difference?
The handling of the max-width property 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. FR: Not sure what this means
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?)
Edge and Chrome ignores "min-width: %" while Firefox applies it properly. Firefox continues to apply a "min-width: %" when a "width: px" is specified (the width is ignored). We should decide on what is the right behavior and make sure it is written in the spec.
Import the relevant section of §3.8.3 Computing Column Measures here.
TODO. For current proposal, skip to §3.10.4 Distribution algorithm.
We need a resolution on what visibility:collapse does. The current proposal is to do like "hidden" but in addition use the following formula to shift back the next rows/columns to accomodate the disappearance of collapsed tracks. The total width/height of the table would not be affected, only the bounding client rectangles of the cells would be. !!Testcase. !!Testcase. !!Testcase.
Chrome simplified this to just matching :empty.

The behavior of empty-cells:hide is a strange exception.

  1. Why not just say that the cell has "visibility: hidden"?
  2. Why not just say that the row has "display: none"? !!Testcase
Should we hide the row-group background by saying cells only draw the backgrounds of visibility:visible grouping elements?