w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.47k stars 658 forks source link

[css-conditional][css-anchor-position][scroll-animations] Snapshotting post-layout State #10796

Open lilles opened 1 month ago

lilles commented 1 month ago

Multiple CSS specifications now rely on post layout state, like scroll state, for doing style and layout:

The current state on the spec and implementation side:

The two-stage snapshotting happens to avoid a first rendering where there is one frame without a snapshot, since there is no previous frame, with a second frame that applies the state from the first frame, leading to flicker for the first rendering.

Instead of having multiple specs describing when this snapshotting happens, and how it interacts with the HTML spec, we could introduce common spec steps for doing post-layout state snapshots.

css-meeting-bot commented 2 weeks ago

The CSS Working Group just discussed [css-conditional][css-anchor-position][scroll-animations] Snapshotting post-layout State, and agreed to the following:

The full IRC log of that discussion <kbabbitt> futhark: there are multiple specs that do some sort of snapshotting of particular scroll state
<kbabbitt> ...some specs try to specify this timing and some have not
<kbabbitt> ...for scroll driven animations there is a spec that refers to the HTML spec
<kbabbitt> ...that scroll position is snapshotted in the HTML ? at the begining of the animation
<kbabbitt> ...there's a separate snapshotting that happens after resize observers
<kbabbitt> ...in order to have a stable first frame and avoid flickering
<kbabbitt> ...then there is the anchor positioning spec that emilio pointed out
<kbabbitt> ...that has an issue to specify when this scroll position / adjustment snapshotting happens
<kbabbitt> ...now we're working on state queries and I need the exact same thing for sticky pos state queries
<kbabbitt> ...in this issue I propose we try to unify scroll snapshotting to a common point
<kbabbitt> ...instead of referring to modified HTML ? from CSS spec
<kbabbitt> ...the CSS specs that need to do snapshotting can say it needs to be done during these steps in CSS
<kbabbitt> ...what I propose is that we introduce a new step called run snapshot
<TabAtkins> "run snapshot post-layout state steps"
<kbabbitt> ... do this between media query and ??
<kbabbitt> ...basically aligns with where scroll animations spec specifes to do it
<kbabbitt> ...and then update the snapshots again and if the snapshots have changed beacuse of layout change, there is a second run of style and layout
<emilio> q+
<TabAtkins> s/??/update animations/
<kbabbitt> ...that is my proposal
<Rossen4> ack futhark
<Rossen4> ack emilio
<kbabbitt> emilio: first, why do we need two steps?
<kbabbitt> ...could we do it as part of the resize observer step
<kbabbitt> ...do content visibility stuff to prevent unstable frame issue
<kbabbitt> .
<kbabbitt> ...I think that would be nice because you wouldn't need resize observer updates
<kbabbitt> futhark: right, that is actulaly what the current chrome implementation does
<kbabbitt> I talked to flackr and he said dieally in terms of the specification have it after the resize steps
<kbabbitt> flackr: it's fairly common that devs use resize observer to change the shape of something on screen
<kbabbitt> ...you expect that these things that respond to scroll or anchoring or other things to be able to anchor to the content or the size based on developer ?
<kbabbitt> emilio: the loop is basically: update style and layout, then figure out ??, then figure out for resize observers wehtehr something's changed
<kbabbitt> emilio: if you ? you would potentially run multiple layout loops
<kbabbitt> emilio: and you could make it so that you ? resize observations probably
<kbabbitt> flackr: I agree and that's probably better, you could have resize observers respond to updated snapshot
<kbabbitt> emilio: other question is why do we need snapshot at beginning?
<kbabbitt> flackr: usually the scroll position doesn't change and you need to do some layout in your initial pass
<kbabbitt> flackr: so in the case where the thing that you're responding to hasn't changed as a result of scrolll, we onlyl have one pass through style and layout
<kbabbitt> flackr: whereas if you did it after you'd always have second pass
<kbabbitt> flackr: [missed]
<kbabbitt> flackr: and unless the result of running that caused scroll position to change, you have your result
<kbabbitt> emilio: you are doing the thing right after scroll events get sent
<kbabbitt> ...but you have no guarantee that you have updated layout here right?
<kbabbitt> ...and you would snapshot a potentially dirty tree or you would run layout there
<emilio> https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model
<kbabbitt> emilio: proposal is iintroducing a step right after step 10 [in link above]
<kbabbitt> futhark: yes, that was our proposal, inspired by scroll animations spec
<kbabbitt> emilio: but you either run layout there, in which case it's not more efficient, or just snapshot ?
<kbabbitt> flackr: but there is a known scroll position at the least
<kbabbitt> ...I guess you're saying some of these things could have snapshot there
<kbabbitt> emilio: in order to get consistent bejavior and not depend on... you would get different behavior if a media query change had updated layout versus not which seems bad
<kbabbitt> ....so to get consistent behavior you need to update style and layout before doing snapshot
<kbabbitt> flackr: other reason to run at this time is I believe it's before rAF callbacks
<kbabbitt> emilio: no, it's after
<kbabbitt> emilio: nm, it's before
<kbabbitt> flackr: this also puts things in a correct animation state which is good for scroll driven animations
<kbabbitt> ...your animations are based on the correct input state
<kbabbitt> ...would be open to moving that around
<kbabbitt> emilio: if we put it before the update animations and send events you also need to update style & layout
<kbabbitt> ...that seems promising because rAF is something people use to move content around
<kbabbitt> ...so you want to update style & layout as late as possible
<kbabbitt> flackr: I think it might be okay to remove that early snapshot
<kbabbitt> emilio: that would be great because then snapshot the right thing, resize observer can react properluy
<kbabbitt> emilio: update events or animations can ? that snapshot
<kbabbitt> emilio: other than anchor positioning where the snapshot doesn't affect what the page can observe ...
<kbabbitt> flackr: I suppose if you had a rAF observer that was looking at the position of an anchor element, that observatio nwould forcea style and layout to make it correct
<kbabbitt> emilio: you would use the snapshot from your last frame
<kbabbitt> flackr: then it would be a correct ?
<kbabbitt> emilio: potentially
<kbabbitt> futhark: [missed]
<kbabbitt> emilio: yes and that's unfortunate because it causes inconsistent behavior if someone has updated style & layout before
<kbabbitt> ...anything that changes frame that updates style & layout causes different offsets
<kbabbitt> futhark: we use information from last frame
<kbabbitt> emilio: not necessarily, you use info from last layout update
<kbabbitt> futhark: should be information from ?
<kbabbitt> emilio: would prefer to move this only to resize observer, then you get that behavioor automatically
<kbabbitt> ...without changing depending on whether someone has updated ?
<kbabbitt> ...the whole frame sees the updated offsets until the resize observer
<kbabbitt> flackr: right, it makes these scroll dependent queries basically equivalent to a developer observer
<kbabbitt> emilio: if we decided that we need for some reason after the offsets from before rAF then I think we should update style & layout to be consistent
<kbabbitt> ...that's unfortunate
<kbabbitt> futhark: there are a couple of things I'd like to resolve on regardless of orderting
<kbabbitt> ...creating this new run steps where we collect all these kinds of snapshotting in the same space for CSS specs
<kbabbitt> emilio: think that's great
<kbabbitt> futhark: strictly this forum cannot decide the order of the HTML event loop
<kbabbitt> ...but creating that step is one resolution I'd lie to make
<kbabbitt> ...propose CSSOM-view for it
<kbabbitt> Rossen4: back to first resolution which is adding this step for snapshotting
<kbabbitt> ...is there anything else we need to discuss about it?
<kbabbitt> ...not sure if there was agreement
<kbabbitt> flackr: I think we have agreement, I think this is okay to draft
<kbabbitt> ...my only concern is things devs to in rAF
<kbabbitt> ...but that's also a problem with anything they do in resize observers
<kbabbitt> emilio: already the case if author has updated layout manually
<kbabbitt> flackr: I do think that case is less common, still common but majority of updates are scroll with no dirty layout
<kbabbitt> emilio: in that case we're observing a dirty tree because you haven't done layout yet
<kbabbitt> flackr: if the animation time is updated according to the new scroll position, then a rAF observing some style or layout property will force an update, getting the correct for now position
<kbabbitt> Rossen4: back to resolution, any objections?
<futhark> “run snapshot post-layout state steps”
<kbabbitt> RESOLVED: run snapshot post-layout state steps
<kbabbitt> Rossen4: second part was figuring out where this should go
<kbabbitt> ...was suggested to put in cssom-view
<kbabbitt> futhark: that's kind of arbitrary based on where scroll steps were
<kbabbitt> emilio: seems fine to me
<kbabbitt> RESOLVED: add it to cssom-view
<kbabbitt> futhark: the rest here is really WHATWG's HTML spec change