w3c / csswg-drafts

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

[CSS2] What happens when a bfc height grows such that it intersects with a float that was not considered when choosing its width #2452

Open FremyCompany opened 6 years ago

FremyCompany commented 6 years ago

Synopsis:

When an element forming a block formatting context (eg <div overflow:hidden>) is sized next to floats, Edge only takes into account the available width at the location where the block is inserted. If its height makes it so that it intersects with a later float that is wider than the one it was sized against, the block cannot fit and is pushed after that wider float (left behavior).

Chrome and Firefox will restart the layout with a smaller width as many times as necessary* to make it avoid all floats, even if those floats come up only later in the flow (right behavior).

image https://wptest.center/#/z7itm9

Chrome and Firefox however disagree on the placement of resulting element:

http://jsfiddle.net/boggydigital/q1odh04p/show/

Chrome and Firefox also have different limits on how many times it is okay to restart (*):

https://wptest.center/#/unt789


Call to action:

We would like to resolve on a precise algorithm here, and get everyone onboard to implement that algorithm. It would be nice if other browser vendors could take a look at how this works in their browser, and whether they are aware of any problem with their current implementation.


About the same issue:

https://bugs.chromium.org/p/chromium/issues/detail?id=548033

Bugs 15673277 and 107363 if you work at Microsoft

emilio commented 6 years ago

cc @dbaron / @dholbert / @matspalmgren

bfgeek commented 6 years ago

We discovered this too for our current block layout work. cc/ @mstensho

We think[*] that our current block layout engine does a two pass thing which is first layout in the top-most area. Then if it doesn't fit, layout in the next area which has it's block-size unbounded.

[*] Our currently impl has hysteresis which makes this harder to determine, but happy to be wrong :D

css-meeting-bot commented 6 years ago

The Working Group just discussed Complex float shapes and bfc sizing.

The full IRC log of that discussion <dael> Topic: Complex float shapes and bfc sizing
<dael> github: https://github.com/w3c/csswg-drafts/issues/2452
<dael> fremy: [whiteboards]
<dael> fremy: Issue is pretty simple
<dael> fremy: When you have a float and another float later that has a different shape constraint. We try and size the BFC with the remaining space in the block. If your BFC is taller then the point where size constraint changes then you have to do something.
<dael> fremy: In FF every time this happens a new layout is drawn and we try to resize the BFC. It's repeated as many times and needed. It's an arbitrary number of relayouts.
<dael> fremy: Chrome looks like some weird behavior where they tried to do it but it broke websites.
<dael> fremy: We'd like to find something int he middle
<dael> Rossen: We'll layout in the first available space and then slide the other block down until we find space. We're optimizing for not relayout so we avoid overlap
<dael> astearns: But you're not using the width of the space.
<dael> Rossen: We are. The BFC might become wider and shorter so you don't intersect. When I wrote this in like IE9 you do an intersection with all yoru geometry until you fit the space in your initial BFC and you use that.
<dael> iank_: Did you change recently?
<dael> Rossen: Maybe but not so much
<dael> fremy: We do first layout and move the box at the first place you fit.
<dael> Rossen: We may not do relayout.
<dael> dbaron: One problem with the description. While making something wider generally makes it shorter, sometimes it makes it taller. Like when you have an overflow:hidden and the image has a fixed width if you make it wider the image get taller.
<dael> dbaron: You can't assume that it's going to not overlap.
<dael> dbaron: Other thing is these overlap cases happen on real websites, esp wikipeia. Browsers that get this wrong have overlapping content in wikipedia.
<dael> dbaron: FF in wikipedia cases have like 3 layouts.
<dael> iank_: We looked into this. We think our current impl is a little funky. One thing we can do is you look for next available area that is unbounded and doesn't have a float blocking it off at the bottom.
<dael> Rossen: You can have a zig zag of floats. If you want to start filling it with a zig zag you'd push the first BFC down in this case.
<dael> iank_: It will skip the zig zag. That's the best 2 pass.
<dael> fremy: 2 pass option, first we try and use the size. If you overflow with another float you can try to get the smallest distance that you have in the future and try to layout in that space. If that's more then the minimum space you do the usual.
<dael> Rossen: What do you mean it'll work in 2 passes?
<dael> fremy: If it doesn't work we do edge behavior, but if it does you find the smallest space in the future. You simplify the geometry and the remaining space is what you try to use.
<dael> Rossen: Furthest left and furthest right can be disjointed.
<dael> fremy: To get 2 passes. [missed]
<iank_> Here is a testcase I created a while ago... https://www.software.hixie.ch/utilities/js/live-dom-viewer/?saved=5370
<dael> florian: So furthest left and right, not shortest distance.
<dael> dbaron: There's one assumption about gecko you made that I think is wrong. I think you assumed we did a layout...let me check...
<dael> dbaron: I think we're using intrinisic min-content width and not doing layout.
<dael> dbaron: We're doing a layout to determine the height.
<dael> Rossen: That's the one we're talking about. THe widths are created by the geometry.
<dael> dbaron: I need to read it.
<dael> iank_: One thing to point out is when you introduce margin collapsing if the BFC 'smargin effects position of floats.
<dael> Rossen: If BFC psoitions after the floats it will have to be in content order. Only thing that could be effected is BFC position
<dael> iank_: Margins collapsing through in an empty div.
<dael> Rossen: But they're already committed.
<dael> iank_: Not until you know the final margins.
<dael> iank_: You can have a margin that's further down in the doc that effects where the floats re positioned.
<dael> Rossen: You'll have to show me the test case.
<dael> ??: top margin will collapse through?
<astearns> s/??/Rune
<dael> iank_: Yes.
<dael> Rossen: dbaron did you get this into your head?
<dael> dbaron: Kinda. There are a set of positions you can reject without layout.
<dael> Rossen: What does 2.1 spec suggest?
<dael> astearns: From my recollection when defining shapes, FF has the right behavior where you slide things until it fits.
<dael> Rossen: What do you mean by slide? In fremy picture, would you consiter sliding?
<dael> astearns: I recall line layout, not BFC.
<dael> Rossen: line layout is regid.
<dael> dbaron: Line layout has the same problem because the line can get longer.
<dael> astearns: And trying them at a lower position can change the width.
<dael> Rossen: [draws]
<dael> Rossen: Assuming this geometry is what you have to play with (large multi tiered box) what do you mean by sliding?
<dael> Rossen: Let's assume everything above is taken. First place you can position is here Then you arrive and get to some kind of layout. Is sliding on he x axis? one of the geometries?
<dael> dbaron: For both line layout and BFC you have 2 nested loops. If you fail to fit....the outer loop is over your y position and the inner is over your reduction in width.
<dael> dbaron: If you try and place here and fail because it intersects below you narrow your width to account for the intersection and try again. You go until you fit or you fail but there's no more floats.
<dael> dbaron: That's the inner loop. Outer loop is we failed to find a width for this vertical position so then we move down to the next vertical position with more room.
<dael> dbaron: In the simple case what we impl right now is look for next position where something changes.
<dael> dbaron: Traditional floats it's not that bad, in shappes we should loop
<dael> iank_: On shapes we switched shape sizes and BFC so shape has no effect on BFC.
<dael> dbaron: I hink you can exclude a decent amount of things.
<dael> astearns: Changing what you're doing depending on float or shape I don't think that makes that much sense. Everything you can do with hspaes you can do with floats.
<dael> iank_: We have use counters saying it's not used so we switched it off.
<fantasai> s/floats/sufficient number of floats/
<dael> astearns: I'm not that concerned with BFCs but everything we're discussing as a problem for BFCs is also a problem for placing first line of non-BFC content next to lfloats.
<dael> iank_: SLightly different.
<dael> Rossen: In general what you desc makes sense. I hope there's a spec where we can define this. I failed to find anything when I impl.
<dael> astearns: Section 9.5.1
<dael> dbaron: 2.1 defines it for lines but not well for BFC is my memory.
<dael> dbaron: All float rules in 2.1 are in terms on constraints and this is a case where constraints is a bad way of defining it.
<dael> fremy: This is potentially a lot of layout.
<dael> iank_: In our new impl of block layout we went with FF behavior going through each oppotuniry.
<dael> Rossen: From user POV tat's the better behavior.
<dael> iank_: I can describe the 2 pass method.
<dael> iank_: The 2 pass one is layout and the based on I think min-content you lay out in one of the areas.
<dael> fremy: I proposed you first try the first position. Then you try the furthest right space. If it's bigger then the min-width you put the element there. That's what Edge is doing. I'm faily confident that'll work almost all the time and then you don't have to layout again and again. As an author you don't expect this to be super expensive, but it can be.
<rego> this non-BFC example has overlapping issues on Blink/WebKit http://jsbin.com/yebelixowu/1/edit?html,css,output
<dael> florian: If I understand dbaron in the case without minimum the extra part you compress. But if you have the minimum you have to do a re-layout.
<dael> dbaron: Most expensive case is [whiteboards] a table and you're dealing with a shape that has a really rough uneven edge.
<dael> dbaron: So you keep having to relayout.
<dael> iank_: This is why we switched this off for shapes.
<dael> fremy: We only do this a few ties and then give up and overflow the floats.
<dael> fremy: What this would do is it would try to lay it out and if it doesn't work it would put the table under the shape.
<dael> astearns: I'm not sure the example of the narrowest place works for this example.
<dael> dbaron: Depends on what the shape is.
<dael> fremy: If the table fits it fits. If it's bigger it goes undermeath.
<dael> myIes: I think the point is it's valid, but not good.
<dael> astearns: I see the appeal from an impl side, but as an author I can't imagine wanting...if an author wants the content as far up in the layout as possible so FF and half of Chrome is what I expect an author would want.
<dael> astearns: If we have to have a strategy to avoid re-layouts, giving up and going past the floar may be better.
<dael> fremy: Chrome would like to remove this thing.
<dael> iank_: We've removed shapes. WE added counters to shapes and barely saw usage. I believe shapes now only effect line-boxes.
<dael> iank_: As people add lots of lfoats, sure. Shapes is easy to go into every max-length.
<dael> dbaron: I think saying shape-outside doesn't effect BFC is a reasonable comprimise.
<dael> astearns: We deferred to 2.1 in the spec.
<dael> fremy: [missed]
<dael> dbaron: I think wikipedia looks better with the algo.
<dael> fremy: In most cases you do it in 3 which gets you same result.
<dael> dbaron: It's reasonably common that the narrowest thing will be something narrow.
<dael> astearns: Because we counter with shapes and BFCs is small, a different rule for BFC is fine. But I'd hate that to be preceident for line layout.
<dael> iank_: That's easier because when you do the first pass you know the height.
<dael> astearns: I don't mind as long as it doesn't apply to line layout.
<dael> florian: Are you sure problem isn't for lines
<dael> dbaron: You don't change height of the line depending on it getting narrower. If you shrink the line it might shrink, but it might not increase in height. If you shorten the line and it gets shorter in height, but it fits, you leave it.
<dael> iank_: Always works in 2 passes.
<dael> Rossen: And BFC the norrow you make it the longer it gets usually.
<dael> dbaron: You can guar the shortening look is 2, the moving down can be more loops.
<dael> fremy: 2 proposal. 1 to say BFC....
<dael> Rossen: 1) Do all possible layouts which will optimize for the area.
<dael> myles: 2) layout to widest. If it doesn't fix calculate some numbers and if it doesn't fix push it.
<dael> myles: 3) is always push it.
<dael> Rossen: We try and find space for the layout and then push it.
<dael> fremy: Reason we're here is we've found 3 is not good on wikipedia.
<dael> myles: 1 is what user wants. astearns pointed out option 3 may be better then option 2 for user.
<dael> fremy: [missed]
<dael> astearns: Option 1 will often find a > min place to put the BFC.
<dael> fremy: Not as likely.
<dael> dbaron: Depends on the floats.
<dael> dbaron: If your floats are like this (smallest on top right) then you'll be find on the top.
<dael> iank_: [whiteboards]
<dael> Rossen: Can I make a proposal? I'm not sure we'll be able to resolve without wasting more paper. Holding the whole group on this prob. not very helpful. Let's take this over lunch with the people interested.
<dael> Rossen: So what we believe is best for user and impl and we'll come back after the break.
<fantasai> Iank drew two stepped sets of floats, one of decreasing widths on the left, on eof increasing widths on the right, leaving a diagonal channel
<dael> dbaron: I think one resolution that solves part of the problem is the interaction with shapes and BFC. Prop: BFC flow around floats don't care about shape-outside.
<dael> fremy: If you do shape-outside and you do a float BFC is wrong. If you do shape outside the entire element floats.
<dael> florian: For FC it's rare enough it's okay.
<dael> Rossen: Shapes with BFC is probably not common. Shapes with text is how feature was intended.
<dael> myles: why do we want this proposal
<dael> iank_: Impl complex.
<dael> dbaron: Gets rid of worst cases.
<dael> myles: You just look at mins and maxes
<dael> Rossen: Whatever you have with shape you can make with floats.
<dael> dbaron: Okay, I take back that we might be able to resolve.
css-meeting-bot commented 6 years ago

The Working Group just discussed Complex float shapes and bfc sizing, and agreed to the following resolutions:

The full IRC log of that discussion <dael> Topic: Complex float shapes and bfc sizing
<dael> github: https://github.com/w3c/csswg-drafts/issues/2452
<dael> Rossen: This is the picture we were trying to illustrate on the white board. It's intended to illustrate the 3 proposals.
<dael> action Rossen send the image of https://github.com/w3c/csswg-drafts/issues/2452 discussion to archives
<trackbot> Created ACTION-872 - Send the image of https://github.com/w3c/csswg-drafts/issues/2452 discussion to archives [on Rossen Atanassov - due 2018-04-17].
<dael> fremy: Proposal #3 is when you have an image that overflows you just push it down, but that was also leaving a lot of empty space. Edge is doing that right now.
<dael> Rossen: We do one layout. We're assuming inline is in top left.
<dael> astearns: BFC tried for full width and intersected with float.
<dael> Rossen: Right. If we don't fit because we intersect we try and fit and end up at the bottom (behavior #3)
<dael> florian: Width is full width of containing block?
<dael> Rossen: Might not. It doesn't fit.
<dael> fantasai: That's super weird.
<dael> Rossen: And super performant.
<dael> astearns: Edge is getting bugs on clearing and leaving the empty space above.
<fantasai> Rossen was explaining that once they've cleared past the floats into a larger-width area, they don't lay out into that larger area but keep the width of the initial reflow
<fantasai> This is what I thought was super weird
<dael> Rossen: Say you have a div and a tiny 0 width float and then another smaller float. In this case there's a 0 width which we layout the BFC next to the 0 width. BUt it intesects with the smaller float. Then we slide the BFC down. Say it doesn't fit and then it's before the small float.
<dael> Rossen: you can argue we can fix our bug with behavior #2 which has different drawbacks.
<dael> fremy: Proposal #2 is if it doesn't fit you try one more layout. You try to find first place you can fit the min content of the BFC you're trying to place. If you can fix the min-content you put it there. Downside is you may end up in a situation where it goes down if the min-width is too small. You try to find somewhere you can fit the min width. It doesn't require any layout. It's a guar valid. Drawback is it could be min width is very small so yo uget very tall.
<dael> florian: In this logic if there is several places you can fit do you try all?
<fantasai> s/fix the min-content/fit the min-content and there are no floats limiting the height below it/
<dael> iank_: The first one. In this case there's three areas. You start at the first and if it fits you put it there.
<dael> fremy: If it doesn't you try the second and then the third.
<dael> iank_: It's a 2 pass layout and you're trying all areas.
<dael> astearns: It fixes the floated UI issue.
<dael> fremy: Option 1 is Firefox. It's literally trying all possibilities.
<dael> fantasai: Nobody gets the rainbow where it is?
<dael> Rossen: Firefox is rainbow.
<dael> iank_: I posted a link at 1:22 pm of a test case for this.
<dael> myles: rainbow is FF, 3 is edge, no one does 2.
<dael> iank_: Blink and webkit is undefined.
<dael> fremy: There's one thing I don't like is that.
<dael> Rossen: People use offset flows. [missed] it's the only way to offset floats veritically.
<dael> fremy: No gap here (position the float, the then BFC) means that someone really wanted that space.
<dael> astearns: So we have 3 which goes below the floats. 2 which makes and attempt based on heuristics and 1 which does the best but is expensive.
<dael> fremy: Also will Chrome disable this for shapes.
<dael> astearns: Rossen said there was a conclusion.
<dael> fremy: [missed]
<dael> group decision: no conclusion
<dael> fremy: If people won't agree on #2...I thinkw e should resolve on 2.
<dael> Rossen: 2 is improvement for us and Chrome and reduced experience in FF.
<dael> iank_: The test case I dumped in IRC we do 2 in.
<gsnedders> what test case?
<dael> astearns: Would anyone objec to spec the second option?
<dael> dbaron: Who does it now?
<gsnedders> 12:22 < iank_> https://www.software.hixie.ch/utilities/js/live-dom-viewer/?saved=5879
<dael> many: no one
<dael> dbaron: I would object to spec something no one does.
<dael> fremy: We can't spec what Chrome is doing. Firefox is option 1. That's better then our version.
<dael> astearns: Sounds like we don't agree.
<dael> iank_: WE can see how expensive 1 is.
<dael> Rossen: We can resolve on 1, ask whomeever impl it to spec it. If this is performance we can ask to get some data back. In the meantime other impl...we'll do something to fix. For normative behavior it's hard to argue #1 isn't the best. It's up to us to figure out easy engineering tricks to optimize as much as possible.
<dael> Rossen: So is there objections to #1?
<dael> fantasai: Sounds better.
<dael> astearns: Objections to spec #1 for BFCs?
<dael> fremy: No special about shapes?
<dael> Rossen: No, nothing special about shapes.
<dael> astearns: If we spec we'd need a floats module.
<dael> Rossen: Let's get a resolution about the behavior we want.
<rego> https://github.com/w3c/csswg-drafts/issues/2452
<dael> astearns: Prop: The working group preference is to specify BFC float avoidance behavior to match what is spec in 2.1 for inline layout float avoidance behavior
<dael> Rossen: ish.
<dael> astearns: To follow those guidelines and spec it well.
<dael> astearns: Obj?
<dael> RESOLVED: The working group preference is to specify BFC float avoidance behavior to match the guidelines of what is spec in 2.1 for inline layout float avoidance behavior
<dael> Rossen: Where does this go?
<dael> florian: 2.1?
<dael> astearns: I think floats module. 2.1 is vague on inline.
<dael> Rossen: In CSS positioning the fork happened for floats and position.
<dael> fantasai: I'd rec not in the same module because psoitioning and floats are quite divergent.
<dael> Rossen: That's okay. We can take the line out of 2.1 and start a module.
<dael> Rossen: A resolution for that?
<dael> gsnedders: If we're removing a line from 2.1 we should have a resolution.
<dael> astearns: We're not taking out, we're making a module to refine.
<dael> astearns: objections to someone creating a css float module at some point?
<dael> Rossen: I can create the fork and start it.
<dael> dbaron: I can help, but I don't want to be only person
<dael> astearns: objections to rossen and dbaron creating a css float module?
<dael> smfr: This isn't about float layout, but wrapping behavior. So if shapes trigger same behavior doesn't make sense.
<dael> astearns: Shape outside is in relation to floats and exclusions would tie in.
<dael> fantasai: I think floats is right place.
<dael> dbaron: I think if I'm putting it with something it would be block layout and that doesn't really have a L3 for that.
<dael> myles: That's better then proposal. Rather then a new spec we should have someone take up stewardship of the block layout
<dael> fantasai: It has more stuff in it.
<dael> astearns: Like with any other module the bits and pieces that refer to other specs say it's defined over there.
<dael> astearns: Can be floats module, can be wrap. They're pretty synonymous for css so I don't care on the name.
<dael> Rossen: Floats is more specific and targeted.
<dael> astearns: Prop: Start a CSS 3 Floats Module with dbaron and fremy as co-editors
<dael> RESOLVED: Start a CSS 3 Floats Module with dbaron and fremy as co-editors
Loirooriol commented 1 year ago

@dbaron @FremyCompany Is CSS 3 Floats still under consideration?