These rules do not apply when the table is laid out
in fixed mode. In this case, the simpler rules that follow apply instead:
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:
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 layoutThe 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
or hidden
or if they are replaced elements, and a 0px height if they have not. Testcase !!Testcase
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:
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.
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 principlesInvestigations 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 algorithmThe 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
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 owns 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 boxesWe need a resolution on what visibility:collapse does. <https://github.com/w3c/csswg-drafts/issues/478>
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 table-wrapper box is then sized such that it contains the margin box of all table-non-root boxes as well as the table-root border-box.
The position defined here is the position of the children inside the space reserved for the table-wrapper, which excludes only its margins. This is because the captions of the table are located outside the border-box area of the table-root.
The position of any table-caption having "top" as caption-side within the table is defined as the rectangle whose:
The position of any table-cell, table-track, or table-track-grouping box within the table is defined as the rectangle whose:
For table-track and table-track-grouping boxes, 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:
If the table is laid out
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 trackif both of those conditions apply:
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) Name: empty-cells Value: show | hide Initial: show Applies to:table-cell
boxes 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, when this property has the value hide
, no borders or backgrounds are drawn around/behind empty cells.
Cells are empty unless they contain one or more of the following:
Can we simplify empty-cells:hide? <https://github.com/w3c/csswg-drafts/issues/605>
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 bordersUnlike other boxes types, table and inline-table boxes 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 modeWhen a table is laid out 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 laid out 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 backgroundsAnonymous table-cells added by the missing cells fixup step do not render any of their backgrounds.
In addition to its own background, table-cell boxes also render the backgrounds of the table-track and table-track-grouping boxes 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 boxes, and not on those of the cell.
For the purposes of finding the background of each table cell, the different table boxes 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.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.
In separated-borders mode, borders of table cells are rendered as usual.
4.3.3.1. Changes in collapsed-borders modeBorders 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 for tables in collapsed-borders mode than usual. 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
.
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 pagesWhen 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 pagesWhen 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.
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 pagesWhen 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 ConsiderationsUsing CSS Tables does not incur any security risk to mitigate.
7. Privacy ConsiderationsUsing CSS Tables does not incur any privacy risk to mitigate.
8. List of bugs being trackedThis section is not normative.
This specification says that Chrome and Firefox are right.
The WHATWG spec says that Chrome is wrong.
The specs says that Edge is wrong.
This specification should say that Chrome and Firefox are right, I guess.
This specification has no opinion yet on the matter.
This may be solved by www-list on the width of the table boxes in relation to their table captions
This specification has no opinion yet on the matter.
This specification has no opinion yet on the matter.
This specification has no opinion yet on the matter.
This specification has no opinion yet on the matter.
This specification has no opinion yet on the matter.
This specification has no opinion yet on the matter.
There is no doubt this is a bug, but it is a good test case for the algorithm.
This specification currently says that Chrome is right.
Should we hide the row-group background by saying cells only draw the backgrounds of visibility:visible grouping elements?
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 truein 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)RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4