Why is table-layout: fixed affecting the width of the parent element?

css display: table-cell width
css div table layout
html table column width: auto
table width css
html table autosize columns
css table td width
html table fixed column width
table-layout fixed column width

Can someone explain why my div with table-layout:fixed is changing the width of its parent element (body in this case) to make it 100% when it shouldn't be 100% since it's positioned?

body {
  border: 2px solid red;
  height: 100vh;
  margin:0;
  padding: 0;
  position: absolute;
}

.c{
  display: table;
  width: 80%; /* Any percentage value different from 0 */
  table-layout:fixed;
  outline: 2px solid blue;
}
<div class="c">d</div>

Looks like you're not the first to bring this up. You might be the second, though.

To be clear, this is a combination of two issues:

  1. The width of an absolutely positioned element is shrink-to-fit. Somehow the shrink-to-fit width is being determined to be as wide as the absposed element's containing block will allow. (The containing block for the absolutely positioned body is the initial containing block.)

  2. A percentage width on an element whose containing block depends on its contents for auto sizing results in undefined behavior.

Issue #2 is pretty easy to write off:

implementations agree not to calculate the width of either element more than once.

i.e. body is sized using shrink-to-fit, then the table is set to 80% of that width, and the size of body is "not computed again". The only "undefinedness" of this is that the spec doesn't require or disallow, or indeed care what implementations do.

So the question then boils down to why shrink-to-fit is yielding "as wide as possible" in #1 prior to determining the size of the table in #2. Here is how the spec describes shrink-to-fit for absposed elements:

[...] Roughly: calculate the preferred width by formatting the content without breaking lines other than where explicit line breaks occur, and also calculate the preferred minimum width, e.g., by trying all possible line breaks. CSS 2.1 does not define the exact algorithm. Thirdly, calculate the available width: this is found by solving for 'width' after setting 'left' (in case 1) or 'right' (in case 3) to 0.

Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width).

But this doesn't tell us why, or even that, the preferred width of a fixed-layout table is "as wide as its containing block will allow". Neither css-sizing-3 nor css-tables-3 appears to contain the answer.

According to David Baron (from the same thread), who works on Gecko:

Fixed-layout tables report an intrinsic max-content inline size as infinite.

(note that "max-content inline size" means the same thing as "preferred width")

So there's our answer. The unbounded max-content inline size of fixed-layout tables is what causes this table's absolutely positioned parent to be stretched as wide as its own containing block (the initial containing block) will allow, in contrast to auto-layout tables.

And, at least for now, this is as close as I'll get to an official source because I'm having trouble reaching the same conclusion just by reading css-sizing-3, and I'm unsure if David's statement is based on Gecko's behavior alone, behavior of all implementations, or on specified behavior.

table-layout, The table-layout CSS property sets the algorithm used to lay out table cells, rows, 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. With table-layout: fixed; Things get a lot sturdier and more predictable with property/value in place. The layout is fixed based on the first row. Set the width of those, and the rest of the table follows. It’s a little more complicated, but not much. Here’s an exploration:


This is my explanation based on the described above issue so it can be viewed as speculation based on the bounty requirements for "official resources".

When table-layout: fixed is applied, the content no longer dictates the layout, but instead, the browser uses any defined widths from the table's first row to define column widths. If no widths are present on the first row, the column widths are divided equally across the table, regardless of content inside the cells.

In order for a value of fixed to have any effect, the table's width has to be set to something other than auto (the default for the width property) ... source

Once table-layout:fixed; is applied without the parent container having any set width and its own width set in percents it would expand its parent container (whatever that container is body/div/etc) to 100% and take the specified width (in this case 80%) relative to that of the parent.

It would do this since its default purpose is with width being set to make sure its columns width is distributed evenly regardless if there are columns or not. If they aren't any columns it would treat the element as one column. To do that it would still need its width to be relative to its parent (when its own width is set in %).

Example table-layout:fixed is not applied since it has no defined width although it is set in the CSS, table-layout:auto is applied as that is the default:

body {
  border: 2px solid red;
  height: 100vh;
  margin: 0;
  padding: 0;
  position: absolute;
}

.c {
  display: table;
  table-layout: fixed;
  /* width: 80%; */
  outline: 2px solid blue;
}
<div class="c">d</div>

table-layout, In order for a value of fixed to have any effect, the table's width has to be set widths are set to 100%, which assumes we want the table to fill its parent a <​colgroup> element whose first <col> element has a width of 400px . Sets a fixed table layout algorithm. The table and column widths are set by the widths of table and col or by the width of the first row of cells. Cells in other rows do not affect column widths. If no widths are present on the first row, the column widths are divided equally across the table, regardless of content inside the cells.


In your second example,

body {
  border   : 2px solid red;
  height   : 100vh;
  margin   : 0;
  padding  : 0;
  position : absolute;

}

.c {
  display : table;
  width   : 80%;
  outline : 2px solid blue;
  /* table-layout : fixed; */
}

You have absolutely positioned the body, so it's taken out of normal flow and it doesn't influence the positioning or sizing of its .c child.

So the width of .c isn't 80% of the body as you might initially expect.

You can however use units like pixels or vw to set the width of .c and the result will be more intuitive, like this.

.c {
  display : table;
  width   : 80vw; 
  outline : 2px solid blue;
  /* width : 80%;  */
  /* table-layout : fixed; */
}

Similarly, when you use table-layout:fixed; your browser uses an algorithm to calculate the width of the table which is similar to using units like pixels or vw to calculate the width for the table.

To quote from the W3C spec

17.5.2.1 Fixed table layout With this (fast) algorithm, the horizontal layout of the table does not depend on the contents of the cells ...

Fixed Table Layouts, The default property for table-layout is auto , and that is the table layout Set the width of those, and the rest of the table follows. Text down here doesn't affect layout anymore. For good measure, know that you can use the <col> element to set column widths too, because those effect the first row of cells  When table-layout: fixed is applied, the content no longer dictates the layout, but instead, the browser uses any defined widths from the table’s first row to define column widths. If no widths are present on the first row, the column widths are divided equally across the table, regardless of content inside the cells.


table layout · WebPlatform Docs, The width of the table and its cells depends on the content of the cells. fixed: Table inherit: This features inherits table-layout property from the parent element. table-layout: auto fixed: auto is the default. The width of the table and its cells depends on the content inside. If you change this to fixed, the 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, which can speed up rendering.


CSS table-layout property, Example. Set different table layout algorithms: table.a { table-layout: auto; width: 180px; } table.b { the first row of cells. Cells in other rows do not affect column widths. inherit, Inherits this property from its parent element. Read about inherit​  the problem is that the input-group is rendered as a table. the default text-overflow behavior wraps the lines depending on the tables/columns width. on the other hand a table/columns width must be at least as width as the longest line inside - wich is the longest word cause the text is wrapped (hope you get me^^). now if we disable the wrapping the the hole content is in one line. the table will adapt to this ignoring its parents width.


CSS tables, For the layout, this chapter introduces two algorithms; the first, the fixed table layout An internal table element is one that produces a row, row group, column, All child boxes of a 'table-column' parent are treated as if they had 'display: none'. In addition, the width of the table is diminished by the width the column would  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.