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-sizing] Last remembered size when fragmented? #7598

Open
Loirooriol opened this issue Aug 11, 2022 · 8 comments
Open

[css-sizing] Last remembered size when fragmented? #7598

Loirooriol opened this issue Aug 11, 2022 · 8 comments

Comments

@Loirooriol
Copy link
Contributor

https://drafts.csswg.org/css-sizing-4/#last-remembered

record the current inner dimensions of its principal box as its last remembered size.

What if the principal box is fragmented e.g. into different columns when inside a multicol container?

ResizeObserver only reports the size in the 1st column: https://drafts.csswg.org/resize-observer-1/#resize-observer-entry-interface

the current definitions of content rect and border box do not mention how those boxes are affected by multi-column layout. In this spec, there will only be a single ResizeObserverSize returned in the FrozenArray, which will correspond to the dimensions of the first column. A future version of this spec will extend the returned FrozenArray to contain the per-fragment size information.

So that's what Blink stores as the last remembered size.

Note that the last rememebred size is only used when the element has size containment, which makes it monolithic. So storing the sizes per fragment doesn't really make sense.

Just storing the size of the 1st fragment may be reasonable enough, but this should be clarified.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-sizing] Last remembered size when fragmented?.

The full IRC log of that discussion <fantasai> Topic: [css-sizing] Last remembered size when fragmented?
<fantasai> s/Topic/Subtopic/
<fantasai> github:
<astearns> github: https://github.com//issues/7598
<fantasai> github: [css-sizing] Last remembered size when fragmented?
<fantasai> github: [css-sizing] Last remembered size when fragmented?
<fantasai> oriol: This is about what we do when we are in multicol or printing
<fantasai> oriol: elements can get fragmented
<fantasai> oriol: in that case, what the ResizeObserver does
<fantasai> oriol: is it only provides the size of the first fragment
<fantasai> oriol: ResizeObserver spec has plans to add sizes of more fragments
<fantasai> oriol: but for now implementations are only storing the first fragment
<fantasai> oriol: I think this is reasonable, because we cannot try to keep the same number of fragments and size for each
<fantasai> oriol: because only used when size containment, and it is monolithic in that case
<fantasai> oriol: so using size of first fragment seems reasonable and easiest solution
<astearns> ack fantasai
<heycam> fantasai: monolithic elements can be split across multiple cols/pages
<heycam> ... not convinced using the first fragment makes any sense
<heycam> ... probably want to use the total size of the element, not just the first piece of it that prints on the first page
<heycam> astearns: when a monolithic element gets spliced, does it have multiple fragments? or one fragment that's been sliced into pieces
<heycam> florian: pieces and fragments are the same thing?
<heycam> fantasai: it does have multiple pieces
<heycam> ... not sure if we clarified we call them fragments or not
<heycam> ... two effects of being monolithic. we try to avoid breaking them across breaks
<heycam> ... other is that we don't fragment the content inside them, just graphically slice it
<heycam> ... still get a bunch of pieces of the element. I'd call them fragments
<heycam> ... I think you want the total height of all of those pieces, and not just the height of the first piece
<heycam> oriol: if you have multiple fragments, in strange cases, each fragment might have different width/height?
<TabAtkins> Specifically, my "strong agree" is to "do whatever ResizeObserver currently does"; I have no opinions on what that behavior actually *is* and *strongly* feel we shouldn't be litigating that topic here in this issue.
<heycam> fantasai: for the height, you add them. for the width, you can just take the width of the first one, because for a monolithic element you wont' have different widths on different pages
<heycam> florian: could have different widths, if expressed as a percent?
<heycam> fantasai: at that point you're doing something more sophisticated than just graphically slicing
<heycam> ... so going with the first one is perfectly fine
<heycam> astearns: might agree with Tab, that we agree ResizeObserver is not fragment aware. that current state, taking the first fragment might be fine for this edge case
<bradk> “Finally, if there are no possible break points below the top of the fragmentainer, and not all the content fits, the UA may break anywhere in order to avoid losing content off the edge of the fragmentainer. In such cases, the UA may also *fragment* the contents of monolithic elements by slicing the element’s graphical representation. “
<heycam> oriol: doing something different seems tricky for an implementation
<heycam> fantasai: I'm good with it, but it's not ideal, didn't we agree on fixing ResizeObserver like 6 years ago?
<heycam> astearns: probably, but work isn't done
<heycam> fantasai: would've hoped the second implementation would've fixed things instead of copying the broken stuff
<heycam> florian: especially since we said that dealing with fragmentation properly was a precondition for going FPWD
<florian> s/since we said/since I believe we said/
<fantasai> astearns: 2 ways forward
<fantasai> astearns: 1st option is to just have the size of the first fragment be recorded, to match everything else
<fantasai> astearns: and maybe put issue in the spec that when ResizeObserver gets fixed, we should do better here
<fantasai> astearns: Or we can define how we construct a size out of the entire height and width of a sliced monolithic element
<fantasai> astearns: I'm lazily inclined towards the first
<fantasai> astearns: Oriol, you mentioned that's what Blink does atm
<fantasai> oriol: Yes, they take the size of the first fragment since that's the information that ResizeObserver is providing
<fantasai> astearns: If we decide to go with the entire height and width of monolithic element, is there going to be a mismatch between last remembered size and what is available in resizeObserver?
<fantasai> oriol: At the time we record the size, the element might not be monolithic
<fantasai> oriol: it might be monolithic when using
<fantasai> oriol: having a mismatch, it's not a big deal
<fantasai> oriol: the deal is having to compute the size in a new way
<fantasai> oriol: it could be that only ResizeObserver in the page is the internal one
<fantasai> oriol: we'd have to calculate different sizes for this and for ResizeObserver
<fantasai> oriol: so a bit more work, and maybe trickier
<fantasai> oriol: but like you said about the mismatch, it's not like the other ResizeObservers are getting the last remembered size
<fantasai> oriol: they can use cotent-visibility to see it
<fantasai> oriol: but I don't think they are affected by the added complexity in the implementation
<fantasai> astearns: so, can people live with doing the easy thing for now and putting a note in that we should do better later?
<TabAtkins> +1
<heycam> fantasai: brings up the question of whether we want to do something better later?
<heycam> ... generally, people say we have to decide right now
<heycam> ... what's the point of the note if we've decided not to change anything?
<fantasai> astearns: Last time we put significant effort into fragmentation was when Bloomberg was interested
<fantasai> astearns: might require a non-browser team to care to improve
<heycam> fantasai: if the premise is we can't change behavior, then it doesn't matter if Bloomberg decides to fund fixing things 2 years from now
<heycam> ... if we're open for change int he future? that's one thing
<heycam> astearns: not sure that's the case for this API. can definitely see a path forward to not change current behavior, but add a fragment aware portion that gives you the same information in a fragment aware form
<heycam> fantasai: we agreed to do that when we discussed it, to be fixed for FPWD. but that's different for what we do for last remembered size
<heycam> ... the poitn of last remembered size is that it's the size of hte element. if you size the element to that size, it'll give a reasonabel result
<heycam> ... if you take the size of the first fragment, it won't make any sense
<heycam> ... if you set the first fragment size as the height, you'll get a very different result
<heycam> ... a ResizeObserver is trying to do something a bit different, we're changing stuff and we want to know
<heycam> ... but the point of ResizeObserver is to observer it, not to set the size back again to the element
<heycam> ... but last remembered size is about setting the size back again
<heycam> ... but if you chop off some percentage of it, due to fragments, it's not really preserving its remembered size
<bradk> +1
<heycam> astearns: that convinces me
<heycam> florian: me too
<TabAtkins> I'm just not happy about this diverging from ResizeObserver
<TabAtkins> They should do the same thing imo
<fantasai> They're not trying to solve the same problem
<heycam> oriol: I can try to take a look at the best way to implement this, see what different approaches there are
<fantasai> TabAtkins: okay with investigating, not with resolving on something problematic
<fantasai> astearns: [explains]
<fantasai> astearns: I would like to hear what the problems of mismatching, what problem will that cause?
<fantasai> TabAtkins: the use case is just as valid when done manually with ResizeObserver
<fantasai> TabAtkins: if we can do one way, should do it the other way
<fantasai> florian: I think that means we fix both this and ResizeObserver
<fantasai> TabAtkins: I'm fine with that
<TabAtkins> s/with that/with that, if implementable/
<fantasai> astearns: I suggest we resolve that last remembered size, when fragmented, returns the entire size of the unfragmented element
<fantasai> astearns: and get some implementation feedback
<fantasai> astearns: and come back to this if the implementation feedback raises problems
<fantasai> dholbert: is this specifically for monolithic elements? or anything fragmented
<fantasai> oriol: anything, since last remembered size can be recorded if element is not monolithic
<fantasai> dholbert: I'm concerned that the unfragmented size is not something we generally have or would generally be useful
<fantasai> dholbert: if you have line height extremely tall lands on the fragmentation point
<fantasai> dholbert: might have two pieces that aren't summing to the original total
<Rossen-phone> a+
<Rossen-phone> a+
<fantasai> dholbert: ...
<fantasai> astearns: that's only the case for non-monolithic elements
<fantasai> dholbert: Yes, for monolithic sum of parts should equal sum of pieces
<Rossen-phone> q+
<fantasai> florian: similar problem figuring out the height of a thing
<dholbert> s/thing/thing with getComputedStyle/
<astearns> ack Rossen-phone
<fantasai> Rossen-phone: What I wanted to ask here, does this discussion apply to variable-size fragments or to fragmentainers that are of regular fragment size or ???
<fantasai> astearns: discussed earlier, but didn't come to conclusion on the monolithic width
<fantasai> Rossen-phone: I think answer varies based on that
<fantasai> astearns: So if ppl have concerns we leave issue open and have Oriol investigate what can be implemented in at least one implementation
<fantasai> astearns: and see whether what he comes up with is an acceptable path forward
<florian> +1
<fantasai> oriol: that's fine
<fantasai> astearns: so not resolving today

@astearns astearns removed the Agenda+ label Sep 7, 2022
@Loirooriol
Copy link
Contributor Author

Loirooriol commented Sep 23, 2022

I was actually mistaken. It's true that in Blink a ResizeObserver exposes an array with a single size, which is then used as the last remembered size. But this size is not the one of the 1st fragment as the spec says, in the block axis it's the sum of the block sizes of all fragments. So even if by accident, the last remembered size behaves as desired in Blink.

In Gecko I have implemented multi-fragment support in ResizeObserver (behind a flag), and then the last remembered size can use that.

So now I think it's reasonable to resolve that the last remembered size should take all fragments into account:

  • The last remembered block size should be the sum of the block sizes of the fragments.
  • The last remembered inline size should be the maximum (?) among the inline sizes of the fragments.

Not sure if Blink is actually using the maximum for the inline axis, since I don't know how to get fragments with different inline sizes.

@Loirooriol
Copy link
Contributor Author

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Last remembered size when fragmented, and agreed to the following:

  • RESOLVED: Last remembered size uses the "stitch together in block axis" bounding box
The full IRC log of that discussion <TabAtkins> Topic: Last remembered size when fragmented
<TabAtkins> oriol: continuing discussion
<jcraig> s/@@@elika help?@@@/listed below/
<TabAtkins> oriol: what size to record as last remembered size when ther'e smultiple fragments?
<TabAtkins> oriol: in discussion, preferred behavior was taking all frags into account, but we weren't sure if that was possible
<TabAtkins> oriol: the ResizeObserver API supposedly only returned the frist fragment size
<TabAtkins> oriol: but in Blink, while a single size is exposed, it's not the first fragment size as the spec says; instead it's the sum of the block sizes of the fragments
<TabAtkins> oriol: So perhaps by accident, the last remembered size is behaving as we desired in blink already
<TabAtkins> oriol: So I implemented a way in RO to track size per fragments, not enabled yet but used by last remembered size
<TabAtkins> oriol: So impls have this behavior we thought was better in discussion, so I think we can resolve on this
<TabAtkins> oriol: Precisely, the last remembered block size will be the sum of the fragment block sizes, while last remembered inline size is the max of the fragment inline sizes
<TabAtkins> (As if pasting all the fragments together block-wise, then taking boudning box)
<iank_> that sounds good to me - its a long standing issue that we aren't taking the max.
<TabAtkins> Rossen_: I'm assuming that, without knowing current impl, what we used to have in Edge especially for variable-size frags was we used boudning box of all fragments as the size
<TabAtkins> Rossen_: What I'm hearing is matching that
<fantasai> TabAtkins: No, that's not right
<fantasai> TabAtkins: The summary that I put in is right, it's as if you too all the fragments, pasted them together, and then took the bounding box
<fantasai> TabAtkins: not take the bounding box as they exist on the page
<fantasai> Rossen_: That's what I meant to say
<TabAtkins> oriol: [missed, something about columsn]
<TabAtkins> iank_: This sounds good to me
<TabAtkins> iank_: Note that we need to ignore repeated things like table headers
<TabAtkins> fantasai: Do we?
<TabAtkins> Rossen_: And box-decoration?
<TabAtkins> iank_: Repeated table headers, for example, if you take the stitched size...
<TabAtkins> iank_: the table header won't vary between the fragmentainers
<TabAtkins> iank_: So if you have a repeated frag you just want to take the first
<TabAtkins> iank_: It's an edge case tho
<TabAtkins> Rossen_: what about border-decoration:repeat?
<TabAtkins> Rossen_: ARe you ignoring the borders along the slices?
<bradk> box-decoration: clone
<TabAtkins> oriol: Re: decos, we're remembering content size, so it's not including the borders
<TabAtkins> oriol: Re: tables, the last remembered size is only used when the element has size containment, and I think tables can't have size containment so it doesn't matter in practice
<TabAtkins> Rossen_: Stepping back, proposal lsounds good. Think there will be some details as we implement.
<TabAtkins> Rossen_: But I think the path forward sounds good
<TabAtkins> Rossen_: thoughts or objections?
<TabAtkins> RESOLVED: Last remembered size uses the "stitch together in block axis" bounding box
<TabAtkins> fantasai: We've had interesting convos about RO
<TabAtkins> fantasai: Many inconsistencies between planned and implemented
<TabAtkins> fantasai: Who's working on this?
<TabAtkins> TabAtkins: RO has new editors
<TabAtkins> oriol: I can try to drive something to make the spec handle different fragments, like what I impld in Firefox
<TabAtkins> oriol: But there are unclear details
<TabAtkins> fantasai: We also have a previous discussion, ,maybe from A Coruna, about this?
<TabAtkins> oriol: I think we have a resolution that API shoudl extend to expose fragments, it's just not clear how to do so in some cases
<TabAtkins> fantasai: Think we discussed an array of fragments, we just didn't do that in first version because it shipped before review
<TabAtkins> oriol: Yes, impl currently returns an array that has 1 item, in FF it's the first...
<TabAtkins> Rossen_: Wait is this part of the topic?
<TabAtkins> fantasai: My point is just that we're basing decisions on RO but RO is shaky, and we haven't followed up on resolutions we made for RO.
<TabAtkins> oriol: emilio
<TabAtkins> oriol: is the new editor
<fantasai> Having the first item in the array be the sum of all fragments makes *no sense*
<bradk> I gotta go. Bye.
<TabAtkins> oriol: I added some RO issues to the agenda, hopefully we can handle those
<TabAtkins> oriol: I can try to change the spec to handle fragments
<fantasai> Either it's not an array and it's the sum of all fragments, or its an array of multiple items each representing a fragment
<TabAtkins> Rossen_: Ok, please do that and raise issues if there are any new questions

@Loirooriol
Copy link
Contributor Author

Regarding box-decoration-break: clone, Blink doesn't support it in the block axis. And as I said Gecko only uses the content size, so e.g. in a multicol which is 100px tall, an element with a 10px border and a content height of 125px will have 2 fragments: one with a content height of 80px / border height of 100px, and another with a content height of 45px / border height of 65px. Then the last remembered height will be 80px + 45px = 125px. Then when using the last remembered size, it will keep a content height of 125px.

In other words, when "stitching together in block axis", cloned box decorations are removed, then we take the bounding content size.

@cathiechen
Copy link

cathiechen commented Dec 28, 2022

Should we split the content with last remembered size into different columns?

For instance, the first case in

Test in http://wpt.live/css/css-sizing/contain-intrinsic-size/auto-010.html

The last remembered size is 50 x 150, and the fragment container's height is 100px, the content could be split into two fragments 50 x 100 and 50 x 50, or like the expected 50 x 150.

I personally think two fragments makes more sense, the reason we use last remembered size is to reuse the old layout result. WDYT?

@Loirooriol
Copy link
Contributor Author

I made the test like that because both Gecko and Blink do not fragment elements with contain: size: testcase.

But from #7598 (comment) it can be fragmented by slicing the contents, so WebKit is not wrong.

I guess the test can be relaxed to only check clientHeight and clientWidth when the element has size containment.

@cathiechen
Copy link

@Loirooriol Thanks for the explanation. Just created a PR for it. web-platform-tests/wpt#37685

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants