Skip to content

[css2][css-tables] Do collapsed tracks also shrink the table wrapper box or only the table grid box? #11408

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

Open
Loirooriol opened this issue Dec 22, 2024 · 11 comments
Labels

Comments

@Loirooriol
Copy link
Contributor

https://drafts.csswg.org/css2/#blockwidth
https://drafts.csswg.org/css2/#dynamic-effects

<!DOCTYPE html>
<div style="border: solid; width: 150px">
  <table style="width: 100px; height: 50px; border-spacing: 0; margin: auto; background: cyan">
    <col style="visibility: collapse"></col>
    <td></td>
    <td></td>
  </table>
</div>
Gecko Blink WebKit
  • Gecko resolves auto margins using width: 100px, so they become 25px each. Then the table ends up being only 50px, but the margins stay as 25px.
  • Blink resolves auto margins with the final width, so they become 50px each.
  • WebKit doesn't support visibility: collapse.

Blink seems better I guess.

@Loirooriol
Copy link
Contributor Author

What Gecko does is: it shrinks the table grid box, but not the table wrapper box. That's why margins are unaffected, or here the table doesn't fit next to the float:

<!DOCTYPE html>
<div style="border: solid; width: 150px">
  <div style="float: left; width: 75px; height: 50px; background: magenta"></div>
  <table style="width: 100px; height: 50px; border-spacing: 0; background: cyan">
    <col style="visibility: collapse"></col>
    <td></td>
    <td></td>
  </table>
</div>
Gecko Blink
imatge

That the table wrapper doesn't shrink can be observed with outline. And it's possible to align the table grid box to the right of the table wrapper box with direction: rtl:

<!DOCTYPE html>
<div style="border: 6px solid; width: 150px">
  <table style="width: 100px; height: 50px; border-spacing: 0; background: cyan; outline: solid magenta; direction: ltr;">
    <col style="visibility: collapse"></col>
    <td></td><td></td>
  </table>
  <table style="width: 100px; height: 50px; border-spacing: 0; background: cyan; outline: solid magenta; direction: rtl;">
    <col style="visibility: collapse"></col>
    <td></td><td></td>
  </table>
</div>
Gecko Blink

I think both can be reasonable, but since Gecko allows the wrapper to be bigger than the grid (it can also happen with a caption, but Blink & WebKit never allow it), it should be possible to customize the alignment with justify-items (it would apply to the table wrapper, and affect the table grid that would get the initial justify-self: auto

@Loirooriol Loirooriol changed the title [css2][css-tables] Should tables re-resolve their margins after shrinking due to visibility: collapse? [css2][css-tables] Do collapsed tracks also shrink the table wrapper box or only the table grid box? Dec 23, 2024
@Loirooriol
Copy link
Contributor Author

Though Gecko is inconsistent with the block axis, where the wrapper doesn't stay with the same size as before collapsing a row:

<!DOCTYPE html>
<div style="border: 6px solid; width: 150px">
  <table style="width: 100px; height: 100px; border-spacing: 0; background: cyan; outline: solid magenta">
    <col style="visibility: collapse"></col>
    <tr style="visibility: collapse"><td></td><td></td></tr>
    <tr><td></td><td></td></tr>
  </table>
</div>
Gecko Blink

@Loirooriol
Copy link
Contributor Author

Note that Blink doesn't shrink the wrapper beyond the size of the caption. Since it doesn't allow the wrapper to be bigger than the grid, it seems to add trailing tracks.

<!DOCTYPE html>
<table style="width: 100px; height: 50px; border-spacing: 0; background: cyan; outline: solid magenta; border: solid">
  <caption style="width: 75px; height: 25px; background: orange"></caption>
  <col style="visibility: collapse"></col>
  <td></td><td style="background: yellow"></td>
</table>
Gecko Blink

@Loirooriol
Copy link
Contributor Author

OK, so things get even weirder:
☑️ = Shrunken by collapsed tracks
❌ = Not shrunken by collapsed tracks

Flex row Flex col Grid Block Abspos
Intrinsic inline contributions ❌ Gecko
❌ Blink
❌ Gecko
❌ Blink
❌ Gecko
❌ Blink
❌ Gecko
❌ Blink
N/A
Table wrapper inline size ❌ Gecko
❌ Blink
❌ Gecko
☑️ Blink
❌ Gecko
☑️ Blink
❌ Gecko
☑️ Blink
❌ Gecko
❌ Blink
Table grid inline size ☑️ Gecko
❌ Blink
☑️ Gecko
☑️ Blink
☑️ Gecko
☑️ Blink
☑️ Gecko
☑️ Blink
☑️ Gecko
❌ Blink
Intrinsic block contributions ☑️ Gecko
☑️ Blink
❌ Gecko
❌ Blink
☑️ Gecko
☑️ Blink
☑️ Gecko
☑️ Blink
N/A
Table wrapper block size ☑️ Gecko
☑️ Blink
☑️ Gecko
❌ Blink
☑️ Gecko
☑️ Blink
☑️ Gecko
☑️ Blink
☑️ Gecko
☑️ Blink
Table grid block size ☑️ Gecko
☑️ Blink
☑️ Gecko
☑️ Blink
☑️ Gecko
☑️ Blink
☑️ Gecko
☑️ Blink
☑️ Gecko
☑️ Blink
Code
<!DOCTYPE html>
<style>
.container { display: inline-flex; padding: 5px; border: 5px solid; vertical-align: top }
table { outline: 5px solid magenta; border: 5px solid cyan; width: 100px; height: 100px }
col + col, tr + tr { visibility: collapse }
td { background: yellow }
</style>
<div class="container" style="display: inline-flex; flex-direction: row">
  <table>
    <col></col><col></col>
    <tr><td></td><td></td></tr>
    <tr><td></td><td></td></tr>
  </table>
</div>
<div class="container" style="display: inline-flex; flex-direction: column">
  <table>
    <col></col><col></col>
    <tr><td></td><td></td></tr>
    <tr><td></td><td></td></tr>
  </table>
</div>
<div class="container" style="display: inline-grid">
  <table>
    <col></col><col></col>
    <tr><td></td><td></td></tr>
    <tr><td></td><td></td></tr>
  </table>
</div>
<div class="container" style="display: inline-block">
  <table>
    <col></col><col></col>
    <tr><td></td><td></td></tr>
    <tr><td></td><td></td></tr>
  </table>
</div>
<div class="container" style="position: relative">
  <table style="position: absolute">
    <col></col><col></col>
    <tr><td></td><td></td></tr>
    <tr><td></td><td></td></tr>
  </table>
</div>

@Loirooriol
Copy link
Contributor Author

Loirooriol commented Jan 8, 2025

I tried to align Servo with Gecko, but there are various tests that check that collapsed columns shrink the offsetWidth of the table. Seems like Gecko is doing something special:

<!DOCTYPE html>
foo
<table style="display: inline-table; width: 100px; height: 50px; border: 5px solid; outline: 5px solid magenta; box-sizing: content-box">
  <col style="visibility: collapse"></col><col></col>
</table>
bar
<pre></pre>
<script>
var t = document.querySelector("table");
document.querySelector("pre").textContent = `
  clientWidth: ${t.clientWidth}
  offsetWidth: ${t.offsetWidth}
  getBoundingClientRect().width: ${t.getBoundingClientRect().width}
  getClientRects()[0].width: ${t.getClientRects()[0].width}
`;
</script>

Indeed: https://searchfox.org/mozilla-central/rev/6b61714b224f8cdca1a48ef1c51edab027f2c09f/layout/base/nsLayoutUtils.cpp#3384-3393

  if (pseudoType == PseudoStyleType::tableWrapper) {
    AddBoxesForFrame(aFrame->PrincipalChildList().FirstChild(), aCallback);
    if (aCallback->mIncludeCaptionBoxForTable) {
      nsIFrame* kid =
          aFrame->GetChildList(FrameChildListID::Caption).FirstChild();
      if (kid) {
        AddBoxesForFrame(kid, aCallback);
      }
    }
  }

@astearns astearns moved this to FTF agenda items in CSSWG January 2025 meeting Jan 22, 2025
Loirooriol added a commit to Loirooriol/servo that referenced this issue Jan 23, 2025
A box is usually sized by the formatting context in which it participates.
However, tables have some special sizing behaviors that we implemented
with a `content_inline_size_for_table` override.

However, each formatting context had to remember to handle the override
(e.g. flex was missing it), and this approach was problematic, because:
 - It's hard for the table to know how the parent formatting context
   would resolve some sizing keywords like `stretch`.
 - The parent formatting context may decide the size with other inputs
   than the sizing properties, e.g. flex items can flex their size.
 - Collapsed columns could unexpectedly shrink the assumed width, so e.g.
   when placing among floats we could skip some candidate areas thinking
   that the table wouldn't fit, even if might end up fitting.

Therefore this patch lets the parent formatting context decide the final
inline size of the table as normal, just with the addition of enforcing
a min-content minimum.

In particular, we no longer allow collapsed columns to shrink the inline
size, like Gecko. Blink sometimes allows it, sometimes doesn't.

The block size is a bit more special: the parent formatting context
ignores the sizing properties, and instead sizes intrinsically. However,
the table takes the sizing properties into account when deciding its
intrinsic block size.

This may need to be revisited depending on the outcome of
w3c/csswg-drafts#11408
Loirooriol added a commit to Loirooriol/servo that referenced this issue Jan 29, 2025
…olumns

A box is usually sized by the formatting context in which it participates.
However, tables have some special sizing behaviors that we implemented
with a `content_inline_size_for_table` override.

However, breaking the assumptions of the formatting context isn't great.
It was also bad for performance that we could try to layout a table
among floats even though it wouldn't en up fitting because of a larger
min-content size.

Therefore, this changes the logic so that formatting contexts use some
special sizing for tables, and then tables only override that amount
when there are collapsed columns. Eventually, we should try to remove
that case too, see w3c/csswg-drafts#11408

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Loirooriol added a commit to Loirooriol/servo that referenced this issue Jan 29, 2025
…olumns

A box is usually sized by the formatting context in which it participates.
However, tables have some special sizing behaviors that we implemented
with a `content_inline_size_for_table` override.

However, breaking the assumptions of the formatting context isn't great.
It was also bad for performance that we could try to layout a table
among floats even though it wouldn't en up fitting because of a larger
min-content size.

Therefore, this changes the logic so that formatting contexts use some
special sizing for tables, and then tables only override that amount
when there are collapsed columns. Eventually, we should try to remove
that case too, see w3c/csswg-drafts#11408

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Loirooriol added a commit to Loirooriol/servo that referenced this issue Feb 4, 2025
…olumns

A box is usually sized by the formatting context in which it participates.
However, tables have some special sizing behaviors that we implemented
with a `content_inline_size_for_table` override.

However, breaking the assumptions of the formatting context isn't great.
It was also bad for performance that we could try to layout a table
among floats even though it wouldn't en up fitting because of a larger
min-content size.

Therefore, this changes the logic so that formatting contexts use some
special sizing for tables, and then tables only override that amount
when there are collapsed columns. Eventually, we should try to remove
that case too, see w3c/csswg-drafts#11408

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
github-merge-queue bot pushed a commit to servo/servo that referenced this issue Feb 5, 2025
…olumns (#35209)

A box is usually sized by the formatting context in which it participates.
However, tables have some special sizing behaviors that we implemented
with a `content_inline_size_for_table` override.

However, breaking the assumptions of the formatting context isn't great.
It was also bad for performance that we could try to layout a table
among floats even though it wouldn't en up fitting because of a larger
min-content size.

Therefore, this changes the logic so that formatting contexts use some
special sizing for tables, and then tables only override that amount
when there are collapsed columns. Eventually, we should try to remove
that case too, see w3c/csswg-drafts#11408

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
github-merge-queue bot pushed a commit to servo/servo that referenced this issue Feb 5, 2025
…olumns (#35209)

A box is usually sized by the formatting context in which it participates.
However, tables have some special sizing behaviors that we implemented
with a `content_inline_size_for_table` override.

However, breaking the assumptions of the formatting context isn't great.
It was also bad for performance that we could try to layout a table
among floats even though it wouldn't en up fitting because of a larger
min-content size.

Therefore, this changes the logic so that formatting contexts use some
special sizing for tables, and then tables only override that amount
when there are collapsed columns. Eventually, we should try to remove
that case too, see w3c/csswg-drafts#11408

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
@mstensho
Copy link
Contributor

I would like to point out that Blink currently doesn't really have a separate table wrapper and table grid box in the implementation (it's just one LayoutObject). We just try to behave as if we did have this separation, to match specs as closely as possible, which is hard, and there are still issues:

https://issues.chromium.org/issues/360905183/blocking

I have no strong opinion, but if we are to do what the spec suggests, with "the space normally taken up by the row or column to be made available for other content" [1], shrinking both seems right, so that it also affects intrinsic size contributions. Or fix the spec, if that's not what we want.

[1] https://www.w3.org/TR/CSS22/tables.html#dynamic-effects

@Loirooriol
Copy link
Contributor Author

Loirooriol commented Feb 12, 2025

so that it also affects intrinsic size contributions

The implications seem wrong to me:

<!DOCTYPE html>
<style>td div { float: left; width: 50px; height: 50px; }</style>
<div style="display: inline-block; border: solid">
  <table cellspacing="0" cellpadding="0">
    <col style="visibility: collapse"></col>
    <td><div></div><div></div></td>
    <td><div></div><div></div></td>
  </table>
</div>

Without collapsing, the max-content contribution of the table is 200px.
If we shrink that to 100px because of the collapsed column, then the inline-block will be 100px wide.
So when laying out the table, we will only have 100px of available space, each column will be 50px wide, and then we will remove the first one.
So the result will be that:

  • The table will still be smaller (50px) than its intrinsic contribution (100px)
  • The 2nd column will be smaller than ideal, even though the inline-block could have been bigger.

@mstensho
Copy link
Contributor

(your example: assuming COL moved inside TABLE)

OMG! You're right. Contributions have to remain the same. Then, the "space normally taken up by the row or column to be made available for other content" [1] is not something we can do, then.

[1] https://www.w3.org/TR/CSS22/tables.html#dynamic-effects

The rendering of the test is also completely messed up in Blink, FWIW, if you add some colors to the boxes. From the looks of it (the border), the intrinsic size propagation remains unchanged in this case, though, but the table box itself is affected by it.

<!DOCTYPE html>
<style>
  td div { float: left; width: 50px; height: 50px; }
</style>
<div style="margin-top:100px; width:fit-content; border:solid;">
  <table cellspacing="0" cellpadding="0" style=" height:200px; background:gray;">
    <col id="elm" style="visibility: collapse"></col>
    <td>
      <div style="background:blue;"></div>
      <div style="background:yellow;"></div>
    </td>
    <td>
      <div style="background:cyan;"></div>
      <div style="background:hotpink;"></div>
    </td>
  </table>
</div>

Image

🤣

@Loirooriol
Copy link
Contributor Author

assuming COL moved inside TABLE

Ah 🤦

I guess you just set the width of the collapsed column to 0, and then lay out its contents within that space, overflowing and overlapping the other column?

Servo and Firefox are like:

@mstensho
Copy link
Contributor

We just fail to skip painting of things inside table cells, if the things are either floated or if they establish a paint layer (position:relative, for instance).

I filed https://issues.chromium.org/issues/396060182

@w3c w3c deleted a comment from css-meeting-bot Feb 12, 2025
@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css2][css-tables] Do collapsed tracks also shrink the table wrapper box or only the table grid box?.

The full IRC log of that discussion <bramus> … first you layout the table without collapse, and then remove th ecollapsed tracks
<bramus> … this is about collapsing of rows and cols
<bramus> … typically it is ht eparent formatting context that decides th esize of a box, but here it is like the table and this can confus the parent FC
<bramus> … was investigating what browsers do
<bramus> … only checked gecko and blink
<oriol> https://github.com//issues/11408#issuecomment-2563995794
<iank_> q+
<bramus> … there is a table in this comment I linked to
<bramus> … some shrink or do not shrink
<bramus> … ?? they dont collapse which I think is right. would otherwise be bad if table is inside an inline-block
<bramus> … when actually deciding final size of the table ther eare diferences
<bramus> … gecko has wrapper table box and ?? box, and blink only has single box.
<bramus> … in the inline axis gecko does not shrink the table wrapper box, only the table grid box
<bramus> … this has nice properties lik avoiding conflicts with PFC
<bramus> … some slightlly surprinsg things like cnetering with auto margins it only cneters the wrapper so could be off center
<bramus> … blink has a single box and tries to shrink “both” things
<bramus> …but it does not shrink in a flex row bc it could conflict with flex sizing algo I think
<bramus> … what does it mean if the table is suddenly shrinking?
<bramus> … does not shrhink for tables that have flex items in a row or if the table is abspos
<bramus> … otherwise it behaves a if table wrapper shrinks
<bramus> … for table grid gecko ??? it shrinks except for flex rows and abspos boxes
<bramus> … things that are more itneresting in the block axis: both try to shrink as much as possible
<bramus> … but in flex columns no browsers shrinks the intrinsic block contributions
<bramus> … for final size of the tbl wrapper blocks gecko ???, blink doe snot shirnk the wrapper but doe shrink the grid
<bramus> … not sure whatis going on.
<bramus> … I like gecko’s inline-axis behavior
<bramus> … not sure about the block
<bramus> … like that a box can decide to if inline size conficts with PFC it can shrink
<bramus> … there are several things to discuss here
<Rossen3> ack iank_
<bramus> iank_: 1 thing I dislike is that when we set a height 100px on a table it will shrink both ??? seems like a ?? on the wrapper box side
<bramus> … if we end up with resolution that keeps the wrapper box at 100px tha twould b egood
<bramus> … some complexity … if all ?? size up to the inner grid box
<bramus> … not sure what to do there
<bramus> fantasai: for the margin case I wonder we could prolly compensate for that by either having the auto margins also do sth to the tabl egrid box or just saying authors should use the alignment properties to align both boxes
<fantasai> s/should/can/
<Rossen3> ack fantasai
<Zakim> fantasai, you wanted to comment on alignment
<bramus> iank_: oriol, can you say why you don tlike affecting th eintrinsic contributions?
<oriol> https://github.com//issues/11408#issuecomment-2653101446
<bramus> oriol: see this link
<bramus> … if you have a table that is inside an inline-block and the table has 2 cols, one of which is collapsed, and each coll has a cell with min-content size of 50 and max content of 100
<bramus> … if you dont take collpased tracks into account the of the tbl is 200px
<bramus> … if we decided to change this, it could be 200 but removing 1 col, so 100px
<bramus> … problem is that when we lay out table for real, we only have 100px of avialbe space to give both cols
<bramus> … so each would be 50px instead of 100px
<bramus> … what will happen is that we end up with 1 col of 50px and its not the ideal size
<bramus> iank_: makes sense
<bramus> … making intrinsic block contributions match inline contributions would be the right way to go there for consistency
<bramus> … and we likely are not constrained too much bc webkit doe snot have this feature yeat
<bramus> … might need to think a bit more about the wrapper and grid box sizes
<bramus> … the way that they work could be funky
<bramus> Rossen3: Oriol, where do you want to take this?
<bramus> … the issue or try for a resolution?
<bramus> oriol: if Ian wants to think more about it, we can bring back to the issue
<bramus> … this even belongs to CSS2, so a bit weird that we have this
<bramus> … but can bring back to the issue
<bramus> iank_: if you (oriol) write down possible solutions, that would be helpful
<bramus> … what you think is the best
<bramus> … I can also propose something
<bramus> Rossen3: So let’s take it back to the issue
<bramus> … perhaps we can have a proposed resolution by the next time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: FTF agenda items
Development

No branches or pull requests

4 participants