Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-tables] How does table-layout:fixed even work? #121

Closed
FremyCompany opened this issue May 17, 2016 · 8 comments
Closed

[css-tables] How does table-layout:fixed even work? #121

FremyCompany opened this issue May 17, 2016 · 8 comments
Assignees
Labels
css-tables-3 Current Work

Comments

@FremyCompany
Copy link
Contributor

FremyCompany commented May 17, 2016

Hi there. I am not sure I understand how fixed table-layout works in some edge cases (and given the docs I can find online I am not the only one).

TLDR: The ask is for browser vendors to have a look at how table-layout:fixed works in their browser. Particular attention is needed for these cases: width:auto; width:min-content; width:max-content; float:left; position:absolute; when the sum of column widths overflow the table width; when some columns do not have a <td> or <th> in the first row, but are required by later <tr>...<td>; I am interested in all behavior involving table-layout:fixed at this point.

So, lets start by one definition that clearly does not match implementation:

According to MSDN:

You can optimize table rendering performance by specifying the table-layout property. This property causes the table to be rendered one row at a time, providing users with information at a faster pace.

The table-layout property determines column widths for a table in the following order:

  • By using information in the width property for the col or colGroup element.
  • By using information in the width property for the td elements in the first row.
  • By dividing the table columns equally, regardless of the size of the content.

If no width is specified for the table, it renders by default with width=100%.

If the content of a cell exceeds the fixed width of the column, the content is wrapped or, if wrapping is not possible, it is clipped. If the table-layout property is set to fixed, the overflow property can be used to handle content that exceeds the width of a td element. If the row height is specified, wrapped text is clipped when it exceeds the set height.

Setting the property to fixed significantly improves table rendering speed, particularly for longer tables. Setting row height further improves rendering speed, again enabling the parser to begin rendering the row without examining the content of each cell in the row to determine row height.

Then how do we explain this test case:

I think the reason is that no browser apply the 10.3.3 algorithm when the width of the table is auto, and therefore use normal layout (initially I thought Firefox also did an exception if the width of the cells of the first row is explicit (example /3/ here), but it looks like to be a difference in the general sizing algorithm instead).

Closer definitions

According to MDN:

Table and column widths are set by the widths of table and col elements or by the width of the first row of cells. Cells in subsequent rows do not affect column widths.

Under the "fixed" layout method, the entire table can be rendered once the first table row has been downloaded and analyzed. This can speed up rendering time over the "automatic" layout method, but subsequent cell content may not fit in the column widths provided. Any cell that has content that overflows uses the overflow property to determine whether to clip the overflow content.

According to CSS 2.1:

With this (fast) algorithm, the horizontal layout of the table does not depend on the contents of the cells; it only depends on the table's width, the width of the columns, and borders or cell spacing.
The table's width may be specified explicitly with the 'width' property. A value of 'auto' (for both 'display: table' and 'display: inline-table') means use the automatic table layout algorithm. However, if the table is a block-level table ('display: table') in normal flow, a UA may (but does not have to) use the algorithm of 10.3.3 to compute a width and apply fixed table layout even if the specified width is 'auto'.

In the fixed table layout algorithm, the width of each column is determined as follows:

  • A column element with a value other than 'auto' for the 'width' property sets the width for that column.
  • Otherwise, a cell in the first row with a value other than 'auto' for the 'width' property determines the width for that column. If the cell spans more than one column, the width is divided over the columns.
  • Any remaining columns equally divide the remaining horizontal table space (minus borders or cell spacing).
  • The width of the table is then the greater of the value of the 'width' property for the table element and the sum of the column widths (plus cell spacing or borders). If the table is wider than the columns, the extra space should be distributed over the columns.

If a subsequent row has more columns than the greater of the number determined by the table-column elements and the number determined by the first row, then additional columns may not be rendered. CSS 2.2 does not define the width of the columns and the table if they are rendered. When using 'table-layout: fixed', authors should not omit columns from the first row.
In this manner, the user agent can begin to lay out the table once the entire first row has been received. Cells in subsequent rows do not affect column widths. Any cell that has content that overflows uses the 'overflow' property to determine whether to clip the overflow content.

Remaining questions

Now, what to do when the width of the table depends on the content is another question. Firefox ignores the fixed algorithm as if the width was auto for max-content, set width:0 for min-content. Chrome set width:0 for both cases (Edge does not support those):

The final bit that was left undefined was how other columns that are not in the first row are rendered.
It looks like they are with width set to 0 in all browsers:

Call for action

I'm going to check whether all the previous assumptions holds true in EdgeHTML, but I would like other browser vendors to chime in in this case to assert there is no other special case where they apply the fixed algorithm anyway. Nobody seemed to apply it when floated or absolutely positioned (should behave like width:min-content), though in the latter case browsers didn't agree on the 100% table width.

Cc: @dbaron + @tabatkins ?

@FremyCompany FremyCompany self-assigned this May 17, 2016
@FremyCompany FremyCompany added the css-tables-3 Current Work label May 17, 2016
@tabatkins
Copy link
Member

Pinging @atotic - fix one bug in tables, deal with tables the rest of your life.

@dbaron
Copy link
Member

dbaron commented May 24, 2016

In Gecko, we used fixed layout when all of the following conditions (see nsTableFrame::IsAutoLayout) hold:

  • computed value of table-layout is fixed
  • computed value of 'inline-size' is not 'auto' or 'max-content'

Fixed-layout tables report an intrinsic max-content inline size as infinite. The intrinsic min-content inline size is computed by adding, for each column:

  • the inline component of the cell-spacing, plus:
  • if the column has a specified inline-size, the value if it is a length or length-only calc(), and 0 otherwise
  • otherwise, if there is a cell in the first row of the column with a width that is a length or a calc() that is length-only, or min-content or max-content, the intrinsic inline size of that cell (which includes adjustment of the value for box-sizing), adjusted for the cell's colspan and the cell-spacing, i.e., ((inline-size + inline-cell-spacing) / colspan) - inline-cell-spacing
  • otherwise, if there is a cell in the first row of the column with a percent width and that cell has a colspan, attempt to cancel out the above addition of cell-spacing but do it wrong and subtract too much (so it subtracts colspan-1 spacings for each column this happens in, instead of 1)
  • otherwise, 0

The actual column size calculations in final layout are similar, except that there's a percent distribution and balancing pass. Columns either have a length width, a percent width, or no width, based on the same rules used above for min-content width computation, except without the bogus attempts to subtract off cell-spacing for percentage widths. Note that, again, we use the colspan-adjusted share of cells in the first row for each column, which doesn't really make sense if some of those columns have other specified widths. If you want me to try to write out this algorithm in more detail, let me know.

Then, if that assignment takes up too much space, reduce the width of any percentage-width columns proportionally to their percentage, but not below zero.

Then, if there is extra space:

  • if there are any columns with no width specified, distributed in equally to such columns
  • otherwise, if there are columns with non-zero length widths from the above width assignment to columns, distribute the excess proportionally to width among those columns
  • otherwise, if there are columns with non-zero percentage widths from the above assignment, distribute the excess proportionally to percentage width among those columns
  • otherwise, distribute the space equally to the zero-sized columns
    (This is much like auto layout.)

@FremyCompany
Copy link
Contributor Author

Thanks @dbaron! I think I can manage from here.

I still have a question about this behavior:

Based on my knowledge of css and your intrinsic min-content inline size computation algorithm, /3/ looks really strange to me. It looks consistent across browsers though which makes me wonder how...

@dbaron
Copy link
Member

dbaron commented May 25, 2016

Isn't that just the intrinsic max-content inline size being infinite? I don't see how intrinsic min-content inline sizes are involved in that test.

@FremyCompany
Copy link
Contributor Author

I thought by default "float:left" used min-content sizing, that's why

@dbaron
Copy link
Member

dbaron commented May 25, 2016

No, it does fit-content, as described in https://drafts.csswg.org/css-sizing-3/#valdef-width-fit-content

@FremyCompany
Copy link
Contributor Author

FremyCompany commented May 25, 2016

Oh, that makes sense. Otherwise we would wrap at every word, or so. Thank you for clarifying.

Still found another strange case when combined with flex for this one (still reasonable in Firefox and Edge, not much so in Chrome):
https://jsfiddle.net/q05o4drf/6/
https://jsfiddle.net/q05o4drf/7/

Do you think we should make Firefox/Edge behavior per spec? How would we achieve that? If max-content was really infinite, the table should accept to grow; shouldn't it?

@fantasai
Copy link
Collaborator

The min-content and max-content keywords should trigger the same behavior (be that auto or fixed). Otherwise it's confusing, since they seem to be parallel concepts to an author.

frivoal added a commit to frivoal/csswg-drafts that referenced this issue Nov 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-tables-3 Current Work
Projects
None yet
Development

No branches or pull requests

4 participants