Csswg-drafts: [css-grid] Resolved values of grid-template-rows/columns don't round-trip

Created on 31 Oct 2019  Â·  24Comments  Â·  Source: w3c/csswg-drafts

According to @fantasai in https://github.com/w3c/csswg-drafts/issues/4444#issuecomment-548006702,

Roundtripping getComputedStyle() values is probably the most fundamental rule about defining them.

However, grid-template-rows and grid-template-columns don't always round-trip. That's because they set explicit tracks, which start just after the 1st grid line. However, when serialized, they also include implicit tracks, which may exist before the 1st grid line.

gridContainer.style.gridAutoRows = "1px";
gridContainer.style.gridTemplateRows = "2px";
var cs = getComputedStyle(gridContainer);
cs.gridTemplateRows; // "2px"
gridItem.style.gridRow = "auto / 1";
gridContainer.style.gridTemplateRows = cs.gridTemplateRows; // "1px 2px"
gridContainer.style.gridTemplateRows = cs.gridTemplateRows; // "1px 1px 2px"
gridContainer.style.gridTemplateRows = cs.gridTemplateRows; // "1px 1px 1px 2px"
gridContainer.style.gridTemplateRows = cs.gridTemplateRows; // "1px 1px 1px 1px 2px"

On the one hand, knowing the final size of these implicit tracks can be useful. On the other hand, failing to round-trip sucks.

Needs Design / Proposal Needs Testcase (WPT) css-grid-1

Most helpful comment

Hi! Just wanted to piggyback on @geddski's concern regarding breaking products that built a grid overlay — this is affecting our users today. The main issue is that we need to know how many implicit tracks are created, and without that information the user experience is completely broken. Please fix this or provide an API for us to access grid information soon 🙏. Better yet, is it possible to postpone (revert) the changes until we have an API to work with?

All 24 comments

I have been thinking that we may be able to keep leading implicit tracks in the resolved value and also ensure round-tripping. We only need to allow grid-template-rows and grid-template-columns to define explicit tracks before the grid line number 1.

The current basic syntax is

<explicit-track-list> = [ <line-names>? <track-size> ]+ <line-names>?
<line-names>          = '[' <custom-ident>* ']'

Maybe we could change <line-names> to '[' <custom-ident>* || 1? ']', with the constraint that this 1 can only appear once in the <explicit-track-list>.

This would define that line name to be the number 1. Tracks before that line would belong to the explicit grid, but items wouldn't be able to use integers in grid-row/column to be placed in such tracks (since 0 is invalid and negative integers refer to the end). Items could still reference line names in order to be placed there.

Then resolved values could preserve this 1 line name if it was specified, and otherwise it could be inserted when there are leading implicit tracks. The previous example would become

cs.gridTemplateRows; // "2px"
gridItem.style.gridRow = "auto / 1";
gridContainer.style.gridTemplateRows = cs.gridTemplateRows; // "1px [1] 2px"
gridContainer.style.gridTemplateRows = cs.gridTemplateRows; // "1px [1] 2px"

Whoa, that's definitely a bug; I see how the spec can easily be read to say that, but it is absolutely not the intention that the resolved value of those properties includes implicit tracks. That's just something completely different, not in any way a gridTemplateRows/Columns value.

(I believe it was meant to be referring to tracks created by, say, repeat(auto-fit), which aren't explicitly created by the author.)

Oh, the spec seemed pretty clear to me:

https://drafts.csswg.org/css-grid/#resolved-track-list

Every track listed individually, whether implicitly or explicitly created, without using the repeat() notation.

https://drafts.csswg.org/css-grid/#implicit-grids

The grid-template-rows, grid-template-columns, and grid-template-areas properties define a fixed number of tracks that form the explicit grid. When grid items are positioned outside of these bounds, the grid container generates implicit grid tracks

All Chromium, WebKit, Firefox and Edge implemented it this way. There are also various WPT tests that expect this behavior. Not sure if it may be too late to remove implicit tracks from the resolved value, there might be code relying on that.

It may be clear to you, but it's definitely not what we meant to write. ^_^ There's absolutely no world in which implicit tracks make any sense whatsoever to show up in the value of properties that solely define the explicit tracks. (Not unless we alter the properties themselves to allow defining implicit tracks, which muddies the water quite a bit...)

I doubt anyone's depending on this, and if they are, uh, too bad I guess? If anything breaks we'll have to go back and see if we can change grid-template-rows/columns as you suggest to allow sizing implicit tracks as well; the current situation is just utterly broken.

Maybe things like DevTools use that information to know the size of the implicit tracks and the number of them.

Agenda+ to discuss whatever needs to happen to make the resolved value of grid-template-rows/columns actually be a valid value for grid-template-rows/columns, either:

  1. clarify wording to not imply that the implicit grid is serialized as part of the value, going against all implementations
  2. add sufficient new features to grid-template-rows/columns to allow them to size implicit tracks too, and change the serialization of the resolved values to use those features, again going against all implementations.

We cannot stick with what we have today, where all implementations agree on serializating g-t-r/c as a value that is not valid for those properties (the serialization is accidentally valid, but as a different g-t-r/c value, not corresponding to the used value that's supposed to be serializing).

Because both possibilities require all implementations to change, and (2) is actually rather complicated and of fairly minimal value I think, I strongly support (1).

This edit was added in 4646eb1fde53b8f84583bc1c4d96a4f76056f325 in response to https://www.w3.org/Bugs/Public/show_bug.cgi?id=16906

It's very clear that including implicit tracks was intended. CC @atanassov

Oh jeez, so this dates back to the original MS draft, and we just rewrote it for phrasing correctness without thinking about the round-tripping implications.

Okay so this is still very wrong, and we have to choose either (1) or (2) from my previous comment; the status quo is utterly broken and unusable.

I think being able to define which grid line is the number 1 might have its usecases other than this, e.g. if you have 3 columns with auto min-content max-content but is there is enough space you want to add some spacing before the first column and after the last one. If you use grid-template-columns: 1fr auto min-content max-content 2fr then you have to alter the integer indices in placement properties. You can use grid-auto-columns: 2fr 1fr and place ::before and ::after in implicit tracks, but it looks a bit dirty. grid-template-columns: 1fr [1] auto min-content max-content [-1] 2fr seems easier and more elegant.

However, something like this would probably need some thought and should target css-grid-3 instead of css-grid-1, but for getComputedStyle we need to fix css-grid-1.

So choosing (1) sounds reasonable. But if in the future we end up adding (2), then it will be sad if now we choose (1), because we will be preventing authors from knowing the used size of the implicit tracks.

There are a number of things people want to get out of grids that can't be reflected via properties right now, like where a particular item was positioned, etc. Someday we may offer APIs for those.

But sizing implicit tracks is a complicated issue that I don't want to try and define here. Your use-case can be done by just adding padding to the grid container, btw. ^_^

Sure, padding works if you want a fixed amount, but you can't use padding-left: 1fr.

Another usecase could be having a grid with a main table, but also with some side comments per row in an extra column at the end. You may want to size this extra column explicitly, but not include it when using negative integers to place items in the main table. I guess subgrid can be an alternative solution for this, but it may not work that well depending on the HTML structure.

Anyways, I have written a quick draft patch for Chromium that would exclude implicit tracks from the resolved value. It produces failures in 13 WPT tests, see https://crrev.com/c/1897931

I haven't looked at them in detail but I expect some of them to be checking that the sizes of the implicit tracks are correct. This will be difficult to do if the sizes are not included... I guess they will need .getBoundingClientRect() on the grid items or something.

cc @MatsPalmgren

The CSS Working Group just discussed Resolved values of grid-template-rows/columns don't round-trip, and agreed to the following:

  • RESOLVED: Give the 2nd option a chance and see if there are compat reasons to instead keep current behavior

The full IRC log of that discussion
<dael> Topic: Resolved values of grid-template-rows/columns don't round-trip

<dael> github: https://github.com/w3c/csswg-drafts/issues/4475

<fantasai> See https://github.com/w3c/csswg-drafts/issues/4475#issuecomment-548908448

<dael> TabAtkins: Looks like reminant, as spec grid-template-row/column when you asked for resolved value you get width of implicit tracks as well as explicit. Given you can't spec implicit tracks this doesn't make any sense at all.

<dael> TabAtkins: Getting the width of implicit tracks is worthwhile. Functionality is reasonable, but a number of useful grid things it would be great to get from layout that aren't in properties right now.

<dael> TabAtkins: IN past proposed things that would require new grid API to get

<dael> TabAtkins: Resolved value of grid-templates does not round trip.

<dael> TabAtkins: Options; 1) leave as is. Resolved value is not a valid value and confusing because unless you know number of implicit rows you don't know where explicit starts

<dael> TabAtkins: 2) Change to only reflect explicit rows on resolved values. implicit we leave for a more explicit API

<dael> TabAtkins: 3) continue to allow grid-template-rows to express implicit but change grammar so it's valid. There is some value b/c only explicit are used for auto positioning by default. Being able to give bounds to auto while sizing outside could be worthwhile

<dael> TabAtkins: Would need to be able to spec when the explicit grid starts and stops which would also need to return in the resolved value

<dael> TabAtkins: We leave as is, change return of gCS for this so that it allows roundtripping either way

<dael> TabAtkins: Need to decide, this was an accident. If we leave as is need to be more explicit

<dael> TabAtkins: I prefer changing to be just explicit tracks. I could accept any of the 3.

<dael> fantasai: web compat is a substantial concern. Might be stuck with #1

<dael> emilio: Also [missed]

<emilio> s/[missed]/I also prefer 2 if we can get away with the compat issue/

<dael> TabAtkins: Web compat is alwyas a concern and we might be struck with 1. Between 2 and 3 is group okay if we try for 2 and revert if web compat proves otherwise?

<dael> oriol: In issue I propose feature which allows define where grid line could be. It could place it in another place. I think something like this could have its own uses outside this issue. However I agree this prob needs more thought and be in something like Grid 3.

<dael> oriol: If we want to fix roundtripping we need mroe urgent for L1 so it's reasonable to try and remove implicit tracks

<dael> TabAtkins: Youre suggestion was option 3, but as you say requires additional work. How it interacts is unclear right now and a breaking change anywya. If breaking, might as well do one that's easier to work with. If we ever want explicit/implicit we can do that later

<dael> TabAtkins: Any strong preference for keeping current behavior? Or is everyone okay with trying to change gCS and falling back to no change if there's web compat problems?

<dbaron> please make it round-trip correctly :-)

<florian> I like the proposal

<dael> Rossen_: Try it out. It makes sense.

<dael> fantasai: We don't have syntax for that right?

<dael> TabAtkins: Not for 3. No one is suggesting widen the grammar first. This is keep as is and have gCS report explicit only or have gCS report more accurately

<fantasai> sorry, I was confused

<dael> Rossen_: Resolution would be for give the 2nd option a chance and see if there are compat reasons to instead keep current

<dael> Rossen_: Other opinions or objections?

<dael> emilio: No obj but I want to makes ure both Geck oa nd Chromium...info from gCS is not useful. Both Chromium and FF have special dev tools b/c gCS is not enough.

<dael> Rossen_: We can look at extending OM for grid

<emilio> s/make sure/ note

<dael> Rossen_: I think you're pointing out more general issue. I don't disagree

<emilio> https://searchfox.org/mozilla-central/source/dom/webidl/Grid.webidl, fwiw

<dael> TabAtkins: Point is valid in that what's currently returned is not enough for current use cases. So w're not losing anything and we should look into more advanced on

<dael> Rossen_: agreed

<dael> Rossen_: Objectins?

<dael> RESOLVED: Give the 2nd option a chance and see if there are compat reasons to instead keep current behavior

This still needs edits in the spec.

BTW, the change has landed in

Let's hope it will be compatible.

I believe this change would be a mistake. How else would user-land be able to create Grid inspectors/overlays?

By no longer returning the implicit tracks, this change breaks every Grid overlay/inspector/generator tool on the web, including:

my Grid Critters game:
gc-example

Webflow's Grid Inspector
image

If this change is necessary, then we need some other way of getting all the grid track information. Firefox devtools' Grid Inspector uses a privileged element.getGridFragments() method that includes implicit grid tracks, but it's not available in user-land. getComputedStyle() is all we have ATM. Please don't break it.

Yes, we need a way to get more information out of the grid. There's a few requests for different types of information, which are all pretty reasonable.

However, serializations of values must round-trip; their entire purpose is to give you a property value that could reproduce the current world. So this change was necessary.

@tabatkins got it. Even though the current behavior is a bug, it's being relied on by many products. Any chance we could accelerate one of those proposals? Until then our web apps will be broken for a long time with no possible way to fix.

No work's been done on those yet, but I can put it into my "do soon" todo list.

@tabatkins thank you!

Hi! Just wanted to piggyback on @geddski's concern regarding breaking products that built a grid overlay — this is affecting our users today. The main issue is that we need to know how many implicit tracks are created, and without that information the user experience is completely broken. Please fix this or provide an API for us to access grid information soon 🙏. Better yet, is it possible to postpone (revert) the changes until we have an API to work with?

We are going to revert Chrome's behaviour change due to breakage on live sites. We won't change our behaviour in the future until an alternate way of accessing this information is provided.

Fair. I'll put together a proposal soon and get it front of the WG.

Thanks so much @bfgeek & @tabatkins, y'all are awesome.

Was this page helpful?
0 / 5 - 0 ratings