w3c / csswg-drafts

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

[css-inline] fill out initial-letter/float interaction section #360

Closed astearns closed 6 years ago

astearns commented 8 years ago

https://drafts.csswg.org/css-inline/#initial-letter-floats needs more details.

One user of the dropcap.js polyfill has run into a problem where the float simulation of a dropcap interacts badly with multiple same-side floats:

https://github.com/adobe-webplatform/dropcap.js/issues/21

It would be good if we could define initial-letter in such a way that the floated widgets laid out as if the initial-letter did not exist, and the initial-letter would be placed at the top of the in-flow content without reference to the floats or any float clearing.

dbaron commented 7 years ago

I agree that the initial-letter's vertical position should not account for the floats. I think that's what the spec currently specifies, since it doesn't say otherwise, and doesn't define the initial letter as a float. (Though it could be moved down for floats if it actually doesn't fit next to them.)

The horizontal position, on the other hand, does definitely need to account for floats, and does, since the initial letter is placed horizontally relative to the line, which is affected by floats... at least modulo issues like #689.

Then there's the question of how the position of floats needs to account for the initial letter (the opposite direction of interaction from my previous two paragraphs), which is what the section currently covers. It could perhaps be retitled to make it clearer that it covers how floats move in response to initial letter, and not how initial letter moves in response to floats (which I believe is fully defined elsewhere).

I believe floats whose placeholder/anchor is in a line after the first line of the block with initial-letter but one that does intersect the initial letter do need to be pushed down vertically past floats. Otherwise you'd have to find a way to address the circularity of placing a float in a way that would need to shorten a prior line (assuming a sensible fix for #689). I think the short text currently in the spec came out of a rather long working group discussion we had on this topic some time ago, although I'm not completely convinced it does so adequately (e.g., for opposite-side floats), but I haven't considered this closely.

As the issue currently in the section notes, it's less clear whether we want that behavior for a float whose placeholder/anchor is in the first line of the block with initial-letter, since in that case it is entirely possible to displace the initial letter. (But is it desirable?)

/cc @chenpighead

dauwhe commented 7 years ago

If there's a float in the first line, ideally the float would be placed first, then the initial letter:

good-float

A major goal is to avoid a float coming between the initial letter and the subsequent line:

bad-float

As written, if there's a float on the first line I think we get this:

ok-float
dbaron commented 7 years ago

But what if the float is anchored in the second line? Do you want it to push the initial letter in (like your first picture above, but a line lower), or do you want the float to get pushed down to the third line (like your third picture above). My gut feeling is for the latter (pushing down).

dauwhe commented 7 years ago

I agree that pushing down would be best. The other alternatives are weird. If both the initial letter and the float are treated as ordinary floats, you get

2nd-line-float

If you place the float, and then the initial letter, it's maybe even worse:

2nd-line-float-weird

So I think the pushed-down version is best:

2nd-line-float-pushed-down
dauwhe commented 6 years ago

Link to F2F discussion: https://lists.w3.org/Archives/Public/www-style/2017Feb/0050.html

fantasai commented 6 years ago

OK, @dauwhe and I made edits based on the WG’s F2F discussion in Seattle. Flagging Agenda+ for formal review, and because the various points (below) weren't formally resolved during that meeting. The conclusions of the Seattle discussion were:

css-meeting-bot commented 6 years ago

The Working Group just discussed Interaction with Floats, and agreed to the following:

The full IRC log of that discussion <fantasai> Topic: Interaction with Floats
<tantek> no one does this yet right?
<fantasai> https://github.com/w3c/csswg-drafts/issues/689
<fantasai> https://github.com/w3c/csswg-drafts/issues/360
<TabAtkins> github: https://github.com/w3c/csswg-drafts/issues/360
<TabAtkins> fantasai: Based on minutes we made a bunch of changes to the spec.
<TabAtkins> fantasai: Specific things were:
<fantasai> https://github.com/w3c/csswg-drafts/issues/360#issuecomment-392128995
<TabAtkins> fantasai: clear doesn't apply to initial-letters, or clear them. (It's only for floats.)
<TabAtkins> fantasai: initial-letters don't overlap floats.
<TabAtkins> fantasai: If line box is moved or shortened, initial-letter moves with it.
<TabAtkins> fantasai: inline-start floats [something else, it's all in the issue]
<TabAtkins> fantasai: Ther'es a bunch of illustrations in the issue.
<fantasai> https://github.com/w3c/csswg-drafts/issues/360#issuecomment-270734813
<TabAtkins> astearns: For last one, if you consider initial-letter as part of the first line, it falls out of the float behavior.
<fantasai> https://github.com/w3c/csswg-drafts/issues/360#issuecomment-270760193
<TabAtkins> fantasai: For floats on first line, going with first illustration; for floats on subsequent lines, going with last.
<TabAtkins> dauwhe: The middle blue example is something we really want to avoid, so that's what we worked out the rules for.
<dbaron> proposal is the first example in the blue examples, and the last example in the green examples, right?
<TabAtkins> yes, dbaron
<TabAtkins> Rossen: What happens if there was a second left flaot that comes between "discontent" and "made"
<TabAtkins> fantasai: Depends on if it's on first or second line. Then just follow the rules.
<TabAtkins> fantasai: The floats will stack...
<TabAtkins> [rossen draws picture]
<fantasai> s/The floats/If on the second line, then the floats/
<fantasai> s/.../ because the float is taller than the initial letter. It clears the initial letter, but doesn't clear the float./
<TabAtkins> astearns: That flaot in that example - the top edge of the flaot can't be positioned above the bottom edge of the line box of preceding content, which includes the initial letter.
<TabAtkins> fantasai: No reason to clear it for right floats...
<TabAtkins> [multiple people] Oh no, that's bad.
<TabAtkins> iank_: You need to do it for both.
<TabAtkins> dbaron: You get into fun issues if you start getting right floats that actually fill most of the block
<TabAtkins> dbaron: You can then have a right float that bumps into the first letter.
<TabAtkins> fantasai: Then it wouldn't fit
<TabAtkins> dbaron: To say that, you have to rewrite a bunch of text to *say* it won't fit, because text is currently about line boxes, and per that, there's nothing there right now (initial letter isn' tin the line box)
<TabAtkins> Rossen: Positioning a large right float is the same as positioning a normal left float.
<TabAtkins> tantek: 2.1 algo assumes rectangel line boxes.
<TabAtkins> tantek: for fitting floats
<TabAtkins> tantek: A lot of it's reasoning is simplified as a result.
<TabAtkins> tantek: If you assume non-rectangular, you'll have to rethink those steps. Might be desirable, but we can't assume it'll "Just Work".
<TabAtkins> fantasai: line boxes stack with zero distance between them; if this was about line box getting taller, second line would have to clear the initial letter too, so that's false.
<tantek> yeah, I'm gonna need you to define non-rectangular line boxes
<TabAtkins> astearns: So we'd need to redefine some of the float behavior to say that, in the left-float case you set it as far left as you can without going above the line content (includes the initial letter), but for right float it can't go above the bottom of the actual line box.
<TabAtkins> astearns: If the float geometry doesn't intrude into the first-letter geometry.
<TabAtkins> dbaron: Elika said in Seattle we had said we wanted the right floats to still be able to have their top at one of th eintermediate lines.
<TabAtkins> dbaron: Som eof th ecomplexity is around that.
<TabAtkins> dbaron: I think there's an arg against that.
<TabAtkins> dbaron: If you ahve right and left floats, you still need to have the rule that a float's top can't be above the top of a previous floats.
<TabAtkins> dbaron: So sometimes if you have a left float, a right float will get pushed down anyway below the initial letter.
<TabAtkins> dbaron: So you're creating an inconsistent state where right floats are *sometimes* (indirectly) affected by the initial letter, so why not all the time?
<TabAtkins> tantek: Seems to be making the simple case bad so complex case works better.
<TabAtkins> dbaron: I think it's good both ways.
<TabAtkins> tantek: We need to decide what we want lineboxes to look like.
<TabAtkins> tantek: It sounds like people's expectations are (besides david) ?????
<TabAtkins> [trailed off]
<fantasai> Tantek draws two diagrams of line boxes, where the left side has a nonrectangular outline around the initial letter and its line box, with the second line tucked inside that L an subsequent lines
<TabAtkins> tantek: Start with a consistent linebox model, and figure out what consistent behaviors you get.
<TabAtkins> myles: If you use non-rectangular thing dont' call it a box...
<fantasai> Then another diagram where the first line box is rectangular, and the second line is inside it
<fantasai> tucked in the botom right corner
<TabAtkins> [mumbly discussion around the whiteboard]
<TabAtkins> dbaron: We have three diagrams here.
<TabAtkins> dbaron: A two-line dropcap.
<fantasai> dbaron draws another diagram where the first line box is rectangular, but only single-height high
<TabAtkins> dbaron: In all three, the second linebox is shorter as a result, third and fourth are full-length.
<fantasai> the second line box is shortened, so there's a gap on the left
<TabAtkins> dbaron: Question is first linebox.
<TabAtkins> dbaron: IN first, linebox is rectangle enclosing both lines.
<TabAtkins> dbaron: In second, linebox is sideways L enclosing drop-cap and first line text.
<TabAtkins> dbaron: In third, linebox is rectangle enclosing the entirety of first-line (only top half of drop cap)
<Rossen> https://lists.w3.org/Archives/Public/www-archive/2018Jul/0000.html
<TabAtkins> fantasai: I think we should use third.
<TabAtkins> tantek: That doesn't give you floating behavior rossen wants.
<TabAtkins> fantasai: We can define some behaviors for the initial letter, like it shortens the second linebox, or that floats can't hit it and must clear.
<TabAtkins> Rossen: Problem is that you want initial-letter to act like a float sometimes and not others, and that's weird.
<TabAtkins> tantek: Worse is that you sometimes want it to cause floats to clear after, and sometimes dont'
<dauwhe> q+
<TabAtkins> iank_: emil and I were discussing some tricky cases
<TabAtkins> iank_: A lot can be simplified if you treat the A as some special type of float, and also apply top-edge alignment rules, gets much simpler.
<TabAtkins> iank_: Apply top-edge alignment rule to initial letter, and additional rule that all subsequent floats will clear that initial letter.
<TabAtkins> iank_: (the rule that floats can't go higher the preceding floats)
<TabAtkins> iank_: [draws something on the whiteboard]
<TabAtkins> iank_: If you apply the additional constraint that the initial letter is always treated as a float, and has the top-edge alignment rule, it gets pushed down.
<TabAtkins> dbaron: I dont' think we want that blank space that'll result...
<TabAtkins> dbaron: You need to assert that there's enough room for the initial letter, but shouldn't need to assert that it's past all floats.
<dauwhe> q?
<TabAtkins> iank_: That's makes things very hard for us
<fantasai> iank drew a small right float followed by a large right float. Then tried to place initial-letter'ed line next to the floats.
<TabAtkins> Rossen: One thing to make impls easy...
<TabAtkins> Rossen: Three models for line box.
<TabAtkins> Rossen: If we go with the box that always includes the initial letter as part of its bounds (#1), then that's straightforward for impls.
<fantasai> iank asserted that since the initial-letter follows top edge alignment rule, it has to move down to at least the top edge of the second float
<fantasai> dbaron said we don't want to do that
<TabAtkins> Rossen: You have a line which is tall enough, it'll get cleared by either float.
<fantasai> that we don't want that extra space
<TabAtkins> Rossen: the one contentious case is that if we have a right float on second line, it could have fit, but it'll get pushed down to clear the initial-letter instead.
<TabAtkins> Rossen: But that's consistent with itself and with our current model, it's the 2.1 float algo.
<TabAtkins> Rossen: Only different is that there's a linebox that extends past its initial line of content.
<dauwhe> q?
<TabAtkins> dauwhe: The existing impl of this treats initial -letter as floats, and this gives a lot of bad behavior. If we can minimize bad behavior that's great, but these can't just be pure floats.
<TabAtkins> dbaron: Rossen convinced me that 1 is better model.
<TabAtkins> fantasai: That'll make weird alignment
<TabAtkins> dbaron: Going with model 1 - this is linebox for float rules - requires fewer edits to float rules, and produces pretty sensible results.
<TabAtkins> florian: Not the height of the linebox for *other* purposes, jsut for floats.
<TabAtkins> tantek: I see appeal, but it makes the feature potentially worse than using floats to fake first letter.
<TabAtkins> tantek: That would let right-floating items be fully up, not pushed down.
<TabAtkins> tantek: So subsequent left flaots would go beneath first letter, subsequent right floats wouldn't need to.
<TabAtkins> florian: Other things break when you do it like that tho.
<TabAtkins> fantasai: An issue I didn't want to get into was what dbaron raised - what's the linebox model for initial letters?d
<dauwhe> the drawing (for the minutes): https://lists.w3.org/Archives/Public/www-archive/2018Jul/att-0000/IMG_2701.JPG
<TabAtkins> fantasai: You need a linebox for the letter, it has styling and content.
<TabAtkins> fantasai: Need a linebox for it, for alignment.
<TabAtkins> fantasai: So I think we need two *overlapping* lineboxes. You can say they're same width (model 1), but we don't need to.
<TabAtkins> tantek: That works.
<TabAtkins> Rossen: So in that model, if you have a left float that would fit, why would it move down
<TabAtkins> fantasai: Rule is that you can't have linebox between float and the containing block, so it can't sit there next to the initial letter.
<fantasai> https://github.com/w3c/csswg-drafts/issues/360#issuecomment-270760193
<TabAtkins> fantasai: What you're looking at there is Dave's green examples, you just used a tiny float to make it look more confusing.
<TabAtkins> fantasai: So either we go with the first green image, and if you happen to make your float small enough it'll tuck under there, or we dont'.
<TabAtkins> fantasai: But I thought we discussed and agreed with taking the third green rendering.
<tantek> blue 1, green 3
<TabAtkins> iank_: The way we'd implement this is to treat the letter A as an exclusion, and then we have optimizations that assume you don't put an exlucsion above another one; this breaks that case.
<TabAtkins> iank_: Then you have to work out the layout areas...
<TabAtkins> iank_: You're asserting that the initial letter will go higher than other floats.
<TabAtkins> dbaron: I'd implement this not using the float mechanism.
<TabAtkins> Rossen: Another example case.
<fantasai> fantasai: which float is going higher than the initial latter, iank_ ?
<TabAtkins> Rossen: Take initial letter. Then a float-left and float-right at end of first line.
<TabAtkins> Rossen: So first float-left doesn't fit on the first line, so it goes below the initial letter.
<TabAtkins> Rossen: Then the float-right can't go above the float-left, so it gets pushed down as well.
<TabAtkins> Rossen: But if we reverse the order, then it would be okay for the float-right to be up in the corner? And you think that's not confusing?
<TabAtkins> fantasai: So imagine the first letter is a float with clear:left. This would clear the left float, then force the right float to go lower. If you reversed them the right float woudln't be pushed down. What's the difference?
<fantasai> fantasai: All we're saying here is that you cannot stack a float against the initial letter, you have to clear it.
<TabAtkins> Rossen: So the complexity in our impl comes from the current model assuming you have the bottom of your content, which is assumed to be a position in the block direction; none of this is allowed to b eintruded by floats.
<TabAtkins> Rossen: The rest is just geometry on both sides, it's not interesting.
<TabAtkins> Rossen: Float logic is simple in this case. There's a bottom defined as a position (*not* a geometry), then the only geometries to take into acount are those from floats.
<TabAtkins> dbaron: Reminder that the float rules do no in any way reference the bottom of line boxes, only the top.
<TabAtkins> dbaron: I think to fix this we should *introduce* such a rule.
<TabAtkins> dbaron: Right now the top of the flaot can't be higher than the top of th eline box containing preceding content.
<TabAtkins> dbaron: I think for initial letter the top of a float can't be higher than the bottom of a line box that is *prior* to a linebox containing preceding content.
<TabAtkins> dbaron: So if float is anchored in second line, current rules say it can't be above top of second line box, or first line box, or initial letter line box.
<TabAtkins> dbaron: We can fix it to say that it can't be above the top of second line box, or bottom of first line box, or bottom of initial letter line box.
<TabAtkins> dbaron: Then we can worry if we want this bottom rules to depend on what area the linebox covers, so we can see if right floats can pop up or not.
<TabAtkins> florian: And you're going on lineboxes rather than clearances so floats anchored on first line don't necessarily have to clear the initial letter?
<TabAtkins> dbaron: Yeah.
<TabAtkins> fantasai: Alternative is, in terms of clearances, the first line box includes the first letter, there's nothing to clear, but the part of th einitial letter that drops below the first line box is an exclusion area that needs to be cleared if you're floating to the start edge.
<TabAtkins> dauwhe: Seems straightforward to me.
<astearns> +1 from me
<fantasai> s/nothig to clear,/nothing to clear, it's just in-flow content;/
<TabAtkins> florian: So the effect of these two models in usage, both do the same thing for left floats, different for right floats.
<TabAtkins> florian: fantasai's lets right floats go high, david's doesn't.
<TabAtkins> dbaron: I prefer linebox model because I'm hesitant to tie it too much into the float model. I think too many things can go wrong if initial letters get tied into floats, should be associated with lines.
<TabAtkins> fantasai: I think we still need two lineboxes model.
<TabAtkins> Rossen: Exclusions by current definition - if I created A to be an exclusion positioned like that (bottom half), a left float on second line will still b enext to the initial letter.
<TabAtkins> florian: It's an exclusion you must clear.
<TabAtkins> Rossen: We don't have that right now. We hav exclusions that clear start, end, max.
<TabAtkins> Rossen: So if this was exclusions would it be exlude start or end?
<TabAtkins> fantasai: Whatever float would do.
<TabAtkins> Rossen: So start.
<TabAtkins> Rossen: So you're saying that nothing can be placed to the start of it.
<TabAtkins> fantasai: Right.
<TabAtkins> Rossen: So if you have a left float here, what rule makes it clear?
<TabAtkins> florian: The new rule we add, that left floats must clear it.
<TabAtkins> Rossen: I think what you need here is not exclusions, but a clear-after behavior - say "after me, I want to clear all left floats".
<TabAtkins> florian: So if dotted blue box has clear-after:left, left floats must clear it.
<TabAtkins> Rossen: And I assert that has nothing to do with exclusions.
<TabAtkins> TabAtkins: If the float is anchored in the middle of the first line, how does this give us Blue 1 rather than Blue 3?
<TabAtkins> fantasai: You do a hypothetical layout to figure out where the anchor is, then place the float, *then* place the initial letter (which establishes the exclusion/clear-after) which'll affect subsequent lines.
<TabAtkins> astearns: Two outcomes. One places right floats without caring about the initial letter, one does care. Can we resolve on which outcome we want ,then discuss behavior?
<TabAtkins> TabAtkins: No, objections are about the mechanics.
<TabAtkins> tantek: I think it's important to not degrade behavior from the legacy float stuff.
<TabAtkins> tantek: With a very tall initial letter, it'll look extra bad.
<TabAtkins> TabAtkins: If you put the float beofre your content, everything works fine.
<dbaron> Use of floats for what they were intended for is pretty rare on the Web, outside of wikipedia...
<TabAtkins> fantasai: Yeah, this is mostly about if the float shows up inside the content, such that it's on the second line. I think it's okay to treat that as an edge case.
<astearns> s/then discuss behavior/then work out how to specify it/
<astearns> q?
<fantasai> whiteboard photos: https://lists.w3.org/Archives/Public/www-archive/2018Jul/0000.html
<astearns> ack dauwhe
<fantasai> (this should go up much higher in the minutes)
<TabAtkins> [takes pictures]
<TabAtkins> florian: I don't know if this is a separate convo.
<TabAtkins> florian: If we take first blue, it looks good because the float is taller than the letter.
<TabAtkins> florian: If it's shorter, does it still look good?
<TabAtkins> fantasai: I think it's fine, and in most cases it'll be taller.
<TabAtkins> fantasai: I think we agree on the renderings here. We should resolve on that.
<TabAtkins> fantasai: We just disagree on whether right floats have to clear or not.
<Rossen> https://lists.w3.org/Archives/Public/www-archive/2018Jul/0001.html
<TabAtkins> fantasai: So for left floats: clear doesn't apply to initial letters
<TabAtkins> Rossen: Why doesn't it apply?
<TabAtkins> dbaron: I'ts an inline.
<TabAtkins> RESOLVED: clear doesn't apply to initial letters
<TabAtkins> fantasai: Initial letter mustn't overlap floats, just like lineboxes don't.
<TabAtkins> RESOLVED: Initial letters must not overlap floats (just like lineboxes don't).
<fantasai> https://github.com/w3c/csswg-drafts/issues/689
<TabAtkins> fantasai: If a linebox moves down or is shortened due to a float, initial letter moves with it, and vice versa.
<TabAtkins> florian: Not sure if there's space for initial letter but not rest of line, it should move down with the line...
<TabAtkins> tantek: This is just linebreaking rules. If you have [T]he, and Th fits but not e, the whole thing moves down. But if you have [A], then it can stay on the line by itself and subsequent content moves down to next line, because space introduces linebreaking opportunity.
<fantasai> Exact prose is in https://github.com/w3c/csswg-drafts/commit/71edb81b0d8b8781fec05e46ca05de2ed1d2d3ff btw
<TabAtkins> RESOLVED: If a linebox moves down or is shortened due to a float, initial letter moves with it, and vice versa.
<TabAtkins> fantasai: An inline-start float originating on first line goes between initial letter and containing block edge. (It doesn't split the initial letter and the subsequent text.)
<TabAtkins> florian: This is how flaots works, if the initial letter isn't a float.
<TabAtkins> RESOLVED: An inline-start float originating on first line can go between initial letter and containing block edge. (It can't split the initial letter and the subsequent text.)
<TabAtkins> fantasai: An inline-start float origining on subsequent impacted lines must clear the initial letter.
<TabAtkins> RESOLVED: An inline-start float origining on subsequent impacted lines must clear the initial letter.
<TabAtkins> fantasai: inline-end floats that start on subsequent impacted lines are still an open issue.
<TabAtkins> myles: first-line inline-end floats?
<TabAtkins> florian: I think they're the same.
<TabAtkins> myles: Let's talk about it later.
<TabAtkins> fantasai: Okay, so mark an open issue in the draft about inline-end floats.
<TabAtkins> fantasai: This should close #360 and #689.