Skip to content

[css-display] Make 'flow-root' an independent keyword #1496

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

Closed
Loirooriol opened this issue Jun 2, 2017 · 33 comments
Closed

[css-display] Make 'flow-root' an independent keyword #1496

Loirooriol opened this issue Jun 2, 2017 · 33 comments

Comments

@Loirooriol
Copy link
Contributor

Loirooriol commented Jun 2, 2017

I have already found multiple people (myself included) confused because display: block and display: inline have the same inner display type, flow.

Making flow-root an inner display type overlaps with flow, and saying that inline-block has a flow-root inner display type is not intuitive and does not work well (#1246, #1486).

Additionally, there is the problem of adding layout containment to a ruby element (#1457). I think the obvious fix is making the principal box generated around the ruby container to become a block container (of the specified outer display type) and establish a BFC. But currently no display value allows this.

So I propose:

  • Make flow-root an independent keyword (similarly to list-item) which forces the element to "become a formatting context", i.e an inline box becomes an inline-block, a block container establishes its own BFC, and for ruby this applies to the principal box around the ruby container.

  • Restore the block inner display type from 2014 WD, rename flow to auto, let auto behave like block inner display type when block-level. To avoid name clashes, rename the outer display types to inline-level and block-level. That is, undo most part of https://lists.w3.org/Archives/Public/www-style/2015May/0098.html

So #1246 is solved as such: inline-block is syntactically equivalent to inline-level block, which behaves like inline-level flow-root. The difference is that, when blockified, the formers serializes to block (and may no longer establish a BFC) and the latter serializes to flow-root (and continues establishing a BFC). And the answer to #1486 is that the equivalence between inline-block and inline-level block is preserved, and the flow-root-ness is also preserved.

Letting an auto inner display type compute as block if the outer display type is block-level after possible blockifications or inlinifications also addresses #1341. You can use display: block-level (block-level auto) if you want a block box which inlinifies to inline (inline-level auto), or you can use display: block (block-level block) if you want a block box which inlinifies to inline-block (inline-level block).

See my proposed specification and the bikeshed changes.

@tabatkins
Copy link
Member

Hmmm, okay. So the problem we're dealing with, basically, is that we split the "flow" types into a 2x2 grid of {inline, block}x{flow, flow-root}, but there's a very natural division that groups {block flow, block flow-root, inline flow-root} together separately from {inline flow}, rather than the naive 2/2 splits the syntax creates. This 3/1 split happens to be at least somewhat reflected in the legacy blockification behavior, and possibly in our desired inlinification behavior, too.

Your suggestion is to instead use a 2x2x2 {inline-level, block-level}x{auto, block}x{flow-root, ∅} split, giving us 8 options, with several of them effectively identical.

I think we can make a slightly simpler 2x3 split that gives us the same necessary distinctions and natural blockification/inlinification behavior, with less duplication: {inline-level, block-level}x{inline, block, block-root}. The mapping we obtain is thus:

inline => inline-level inline
block => block-level block
inline-block => inline-level block
block + BFC => block-level block-root

The two "leftover" combinations, block-level inline and inline-level block-root, are indistinguishable from block and inline-block, respectively, except for the blockification/inlinification behavior, where they preserve "looseness" or "FC-ness" respectively.

(I'm using inline as a display-inside because I really don't like using auto for something like this; it made me feel icky when I did it in an earlier draft, and I don't want to bring it back. It doesn't mean what auto traditionally means.)

This also avoids adding flow-root to the other display-inside values, where it's meaningless. Meaningless combinations are a grammar smell.

@tabatkins
Copy link
Member

The only reason imo to keep auto as a display-inside is if we can come up with different names for the inline and block display inside values, so we can return to using those terms as display-outside value. It would be slightly annoying to lose the nice inline-flex == inline flex correspondence, and instead have to write inline-level flex. Then we could have auto be the default when display-inside isn't specified, and have it computed to inline-inside or block-inside depending.

@tabatkins
Copy link
Member

Okay, more naming thoughts. The reason @fantasai and I went with flow/flow-root is that Block Layout and Inline Layout are pretty intimately intermingled, far more than any other layout modes are. They're only semi-independent, and can be thought of as two fairly distinct modes of a single layout mode: Flow Layout.

Under this idea, then, the 3-way split I propose above is more or less "how much do your children mingle with the surroundings?". So here's some non-serious naming suggestions that'll at least let us start usefully talking: {inline, block}x{flow-loose, flow-tight, flow-root}.

This gives us back inline/block as display-outside values, like I wanted, and groups all the "flow" layout types together explicitly again, just with informative names. Then auto computes to flow-loose if it's paired with inline, and to flow-tight if it's paired with block.

@Loirooriol
Copy link
Contributor Author

Loirooriol commented Jun 2, 2017

This also avoids adding flow-root to the other display-inside values, where it's meaningless.

Useless for table, flex and grid, yes. But I don't think it's useless for ruby. Something needs to be done with ruby when it becomes a formatting context, e.g. it has contain: layout (#1457). I think this could be manually triggered with flow-root.


Just to be sure I understand, you are proposing something like the following, right?

Full Short Generates Blockifies to Inlinifies to
inline flow-loose inline inline box block-level block container inline box
inline flow-tight inline-block inline-level block container (with BFC) block-level block container inline-level block container (with BFC)
inline flow-root inline-level block container (with BFC) block-level block container with BFC inline-level block container (with BFC)
block flow-loose flow-loose (?) block-level block container block-level block container inline box
block flow-tight block block-level block container block-level block container inline-level block container (with BFC)
block flow-root flow-root block-level block container with BFC block-level block container with BFC inline-level block container (with BFC)

Not bad, I like it :)

@tabatkins
Copy link
Member

But I don't think it's useless for ruby.

Good point, I'll have to give ruby some more thought.

Just to be sure I understand, you are proposing something like the following, right?

All correct, yes. And yes, display: flow-loose would end up being block flow-loose, since we default the display-inside to block when omitted.

@Loirooriol
Copy link
Contributor Author

This table is more clear. A blockification or inlinification is just a change of column.

Block-level Inline-level Run-in
Flow-loose Full block flow-loose inline flow-loose run-in flow-loose
Short flow-loose inline run-in
Box block-level block container inline box run-in inline box
Flow-tight Full block flow-tight inline flow-tight run-in flow-tight
Short block (synonym: flow-tight) inline-block run-in flow-tight
Box block-level block container inline-level block container (with BFC) run-in block container (with BFC)
Flow-root Full block flow-root inline flow-root run-in flow-root
Short flow-root inline flow-root run-in flow-root
Box block-level block container with BFC inline-level block container (with BFC) run-in block container (with BFC)

With this I don't think we need an auto inner type in order to decide between flow-loose and flow-tight when no inner type is specified. When no outer type is specified, the default also depends on whether the inner one is ruby or not, and no auto outer type is needed neither.

About the names, I think flow-block would be a better name for flow-tight, because it's the default for block containers like block or inline-block.

Analogously, flow-inline might work for flow-loose, but generating a block container in the block-level case seems strange with that name. So I would prefer something like flow-adapt, because it adapts to the outer type, producing different kinds of boxes. Or maybe leave it as flow-loose or just flow. Probably someone else has better ideas.

About ruby, maybe add a new inner type called ruby-root, that behaves like ruby but makes the principal box establish a BFC. And say that "becoming a formatting context" transforms a ruby inner type to ruby-root, just like flow-loose and flow-tight are changed to flow-root.

@FremyCompany
Copy link
Contributor

FremyCompany commented Jun 3, 2017

This recategorization is interesting, but I would want to see illustrated examples and how the various transforms render to convince me. I think I understand intuitively what flow-loose vs flow-tight vs flow-root do for inline and block, but it is less clear to me that flow-tight and flow-root are different in other cases like "table", "grid", or "flex". It is my impression we still have indistinguishable combinations with this proposal. Or do these concepts not apply at all in those cases?

@Loirooriol
Copy link
Contributor Author

@FremyCompany What Tab proposed is

<display-inside> = flow-loose | flow-tight | flow-root | table | flex | grid | ruby ;

So they are all mutually exclusive.

@FremyCompany
Copy link
Contributor

That seems interesting.

@tabatkins
Copy link
Member

Yeah, they're all display-inline types. Just replacing the current flow | flow-root pair (that ends up with complicated/special-cased block/inlinification rules) with a flow-loose | flow-tight | flow-root triple (that has easy rules).

With this I don't think we need an auto inner type in order to decide between flow-loose and flow-tight when no inner type is specified. When no outer type is specified, the default also depends on whether the inner one is ruby or not, and no auto outer type is needed neither.

Yeah, that's valid.

About ruby, maybe add a new inner type called ruby-root,

So I suppose the question is - what's the use-case for manually creating a FC-ified ruby? An FC-ified inline is an inline-block, and it's important to be able to trigger this in case you want to put arbitrary stuff inside the inline, like blocks, but still have it flow. But a ruby aggressively protects itself from internal blocks (whether thru recursive inlining or just FC-ifying, we'll determine later), and so isn't capable of the sorts of shenanigans an inline-block can get up to.

@Loirooriol
Copy link
Contributor Author

what's the use-case for manually creating a FC-ified ruby?

There is this contain thing which FC-ifies all things. Letting some feature to FC-ify ruby as a side-effect without allowing it manually via display is in my opinion undesirable. Reminds me of the good old overflow: hidden hack when there was no display: flow-root.

@tabatkins
Copy link
Member

That's reasonable.

@SelenIT
Copy link
Collaborator

SelenIT commented Jun 9, 2017

I don't like the idea of further splitting the flow value into obscurely-named subvalues that differ only in quite specific situations. The flow-root value itself had a lot of complaints about its name (e.g. #964), even though its effect is much more self-evident. Having two values that do the same thing most of the time but implicitly transform to completely different things in similar situations seems to be a very confusing perspective, especially for newcomers. Moreover, introducing new flow-* values wouldn't solve the original problem of inline-block/inline flow-* being incosistent with other inline-something/inline something pairs.

Isn't there any other option? For example, what is the worst implication of allowing block as both outer and inner display values? If we define block block the synonym of block flow, make inline-block compute as inline block (with inline flow-root as a used value) and naturally blockify as block, would it produce any ambiguity (given that other outer and inner display values are different and we would always be able to determine which part block is by the other part)?

And I still believe that a separate value, or maybe even a separate property, to switch on FC-ness of things explicitly would be useful. Maybe it actually has something to do with the scope of [css-containment], and introducing something like contain: formatting (as I suggested in the comment in #964) would make sense?

@Loirooriol
Copy link
Contributor Author

introducing new flow-* values wouldn't solve the original problem of inline-block/inline flow-* being incosistent

Yes, it would, because then we could have syntactical equivalences:

inline-block = inline flow-tight
inline-table = inline table
inline-flex = inline flex
inline-grid = inline grid

Now the spec says inline-block behaves like inline flow-root but they can't be syntactically equivalent because the former blockifies to block (for legacy reasons) and the latter blockifies to flow-root.

what is the worst implication of allowing block as both outer and inner display values?

I don't like overlaps between longhand properties, especially when the shorthand is not ordered. But given that both block and flow-tight would default to block flow-tight and there is no other overlap, I guess flow-tight might be renamed to block, yes. I would prefer flow-block, though.

I still believe that a separate value, or maybe even a separate property, to switch on FC-ness of things explicitly would be useful

Yes, this is what I attempted to address in my initial proposal. I don't care if it's via an independent flow-root, more inner display types, a new property or some contain value, but I think there should be some way to FC-ify things without other side-effects.

@SelenIT
Copy link
Collaborator

SelenIT commented Jun 9, 2017

then we could have syntactical equivalences

Yes, they would be functionally equivalent, but the clear and intuitive naming rule "for any X, inline-X becomes inline X, just replace hyphen with space" would still break, it would feel "unnatural" and it would perpetually confuse developers (especially beginners). Having block as an internal display value could restore this naming consistency and fix the blockification issue at the same time (but possibly introduce some parsing difficuilties, although I don't see big problem here).

I don't like the flow-abracadabra values because they seem to me contradicting the Priority of Constituencies principle (from HTML, but IMO it's applicable to CSS development as well). This name splitting effectively makes some technical things easier for the spec writers, but otherwise these names don't have much meaning for the average CSS author. I have an impression that even the "flow" concept itself is not very intuitive for many of them, people tend to think of inlines and blocks as of two clearly distinct layout modes. And it would be not easy to explain somebody who just started studying CSS why under the same circumstances inline-table becomes table, inline-grid becomes grid, but inline-block suddenly becomes some mumbo jumbo which, after some magic applied, still effectively converts to block. This "magical" step clearly feels a redundant entity to me.

The flow-root value has at least a practical meaning per se, it solves a real problem that many CSS authors often face. Unfortunately I can't say the same about the new proposals.

@tabatkins
Copy link
Member

Remember that my three flow-* names were explicitly called out as being non-serious, and just presented for the sake of having names for the 2x3 values. ^_^

Re: using block for the "middle" value - it's definitely got its benefits. The parsing isn't too bad; just a tiny bit of prose to disambiguate a lone display: block (to display: block block ^_^). block-root is also a good name. We'd just need a third name to mean "ordinary inline element, or a 'loose' block element".

I don't like the flow-abracadabra values because they seem to me contradicting the Priority of Constituencies principle

Yes, CSS roughly follows the Priority of Constituencies too. But don't be so quick to judge! This sort of thing is easy to dismiss as just spec authors faffing about with more aesthetically pleasing designs, but aesthetics is also an important part of intuitive APIs. If you have to litter an API with corner-cases, it's more difficult to learn and remember for users, and is generally worse. Splitting things out slightly more than the "simplest" case can sometimes lead to much better APIs overall.

(It can also lead to worse APIs, as it sometimes is just spec authors faffing about with aesthetics to the detriment of simplicity and usability. One must be ever vigilant!)

Often, naming is all it takes to shift something from "theoretically elegant, but overcomplicated" to "elegant and intuitive". I think the block/block-root naming might be what takes us there, if we can come up with a good name for the last value. Maybe that can be flow?

@Loirooriol
Copy link
Contributor Author

block-root is also a good name

I'm afraid this might need to stay as flow-root, given that it has already been shipped by Firefox and Chromium.

@tabatkins
Copy link
Member

Yeah, but quite recently. Probably still possible to change if we decided it was worth it.

@SelenIT
Copy link
Collaborator

SelenIT commented Jun 10, 2017

We'd just need a third name to mean "ordinary inline element, or a 'loose' block element".
Maybe that can be flow?

Agree! It also is currently defined almost that way, so little change will be needed).

By the way, if we re-introduce the block value as the inner display type and thus fix the issue with inline-block blockification, do we really still need the 2x3 matrix? Wouldn't the following be sufficient?

Short/legacy value Full value Result
inline inline flow Ordinary inline box that the parent formatting context "flows" into
inline-block inline block Ordinary inline block
block block flow Ordinary block box that the parent formatting context "flows" into
flow-root block block Block box with the new BFC

The inline-block value would be in line:) with other inline-* values. Other values could be unchanged. The flow-root value could stay a bit "special" because its primary use case is rather special, and it won't conflict with the existing inline-block behavior (although renaming it to block-root could be more intuitive).

@Loirooriol
Copy link
Contributor Author

@SelenIT Your proposal is only a rename of flow-root to block. But this does not solve #1246 and #1486, i.e. if you blockify an inline-block (inline block), either you get flow-root (block block), or inline-block and inline block are not syntactically equivalent.

Adding a third display type allows to preserve syntactic equivalence, which in my opinion is desirable. Moreover, I think it would be nice if inline-block and block had the same inner display type, just like inline-table and table, inline-flex and flex, or inline-grid and grid.

@SelenIT
Copy link
Collaborator

SelenIT commented Jun 10, 2017

this does not solve #1246 and #1486

@Loirooriol, you are right, I already realized this myself. This can be kind of worked around by changing the blockification rule from "preserve the inner display type, change the outer one to block" to "take the hyphened shorthand and drop the inline- prefix" (so that the block part in inline-block transparently changes its meaning and starts to refer to outer display type, but otherwise the conversion would look consistent visually, be easy to memorize and match the existing browsers behavior). Technically it will mean that, for legacy reasons, blockification of inline-block (and only this value) changes both its outer and inner display types. But I admit that it feels hacky.

it would be nice if inline-block and block had the same inner display type

Again, it's hard to disagree. As I was thinking about that, even a more crazy idea came to me: what if we reconsider the flow-root value as the outer display type? It effectively changes the way the block interacts with its surroundings, creating an "island" of different formatting context instead of continuing the same formatting context inside it. So it's different from 'block' outer behavior that doesn't create such an "island". And the outer display type of grid, table, and flex is effectively flow-root (in this interpretation) rather than block — an "island" of different formatting context inside the parent one.

Similarly, instead of one inline outer display type we could have two: ordinary inline, that continues the parent inline formatting, and, for example, inline-flow-root, that creates an "island" with new formatting context. Current inline and ruby values would have inline outer display, but inline-block and other inline-* values would have inline-flow-root. And the inner display of all current inline, block, inline-block and flow-root values would be the same (flow or its better-sounding synonym), as they differ primarily externally (which box they generate and whether they continue the parent FC or start a new one).

This would automatically solve #1457 by introducing inline-flow-root ruby. And it would allow things like multi-line flexboxes that join their lines with surrounding lines of text (like inline-blocks, but without rendering inter-element spaces and with all new shiny flexbox alignment/justification options), grids that flow around floats/shapes, etc., in future levels (e.g. inline flex instead of the current behavior that would be inline-flow-root flex).

But when I started think on this idea further, I realized that it also would require some non-intuitive rules for blockification (e.g. inline-flow-root would still blockify as block, which than would produce the flow-root used value). And yes, it's almost the same as to make a new keyword just for the FCness of the element:). But maybe that direction of thinking still may bring something useful?

@Loirooriol
Copy link
Contributor Author

what if we reconsider the flow-root value as the outer display type?

@SelenIT I also considered this possibility, but discarded the idea because inlines and run-ins may also want a FC. You addressed the former with inline-flow-root, but your proposal does not allow a run-in block container.

And yes, serialization is non-intuitive and will still have problem #1486, because you are still limited to 4 values: {inline, block, inline-flow-root, flow-root} x {flow} instead of the current {inline, block} x {flow, flow-root}.

You could add an inner display like {inline, block, inline-flow-root, flow-root} x {flow, block}, but that's 8 values, so {inline, block} x {flow, block} x {flow-root, ∅} seems better. This was basically my proposal.

But I like Tab's proposal with 6 values. Maybe the flow-abracadabra names were not the best, but they offer more flexibility to the users, because they can choose how the element will be blockified or inlinified. I don't think they are against that Priority of Constituencies principle. May be clearer with the new proposed names:

  • block-root: creates block container that is a BFC root.
  • block: creates block container.
  • flow: creates an inline box if the outer type is inline or run-in, otherwise behaves as block.

I think it's reasonably intuitive. There can by syntactic equivalences, and blockifications/inlinifications are simply a change of the outer type. Only some handwaving about blockifying inline to block is needed, e.g. block flow might always compute like block block, or the blockification could change the inner type only in this case.

@Loirooriol
Copy link
Contributor Author

I don't like the idea of further splitting the flow value into obscurely-named subvalues that differ only in quite specific situations.

I was thinking... if the main concern is that a block-level inline box does not make much sense and thus behaves like a block box, maybe that combination could be syntactically not allowed, at least for now.

For example, add a new inline inner display type, but don't expose it in <display-inside>. This means display: inline and display: run-in won't have a two-keyword equivalent.

Block-level Inline-level Run-in
Inline Full
Short inline run-in
Box inline box run-in inline box
Flow Full block flow inline flow run-in flow
Short block (synonym: flow) inline-block
Box block-level block container inline-level BFC root run-in BFC root
Flow-root Full block flow-root inline flow-root run-in flow-root
Short flow-root
Box block-level BFC root inline-level BFC root run-in BFC root

That's only 5 basic values. inline flow-root and inline-block still generate the same box, but they are syntactically different per WG resolution in #1246.

I reused flow and flow-root from the current spec, but they could be renamed to block and block-root, respectively. However, the term "block container" should have been called "flow container" because its contents are not required to be block-level, so flow makes sense for a flow container.

The spec would look like this

Syntax

[ <display-outside> || <display-inside> ] | ...
<display-outside>  = block | inline | run-in ;
<display-inside>   = flow | flow-root | table | flex | grid | ruby ;

Outer display roles

  • block: generates block-level box when placed in flow layout.
  • inline: generates inline-level box when placed in flow layout.
  • run-in: generates run-in box when placed in flow layout.

If a <display-outside> value is specified but <display-inside> is omitted, the element’s inner display type defaults to inline —except for block, which defaults to flow.

Inner display models

  • inline: generates an inline box. Note this value is not allowed in <display-inside>.
  • flow: generates a block container.
  • flow-root: generates a block container that is a BFC root.
  • ...

If a <display-inside> value is specified but <display-outside> is omitted, the element’s outer display type defaults to block —except for ruby, which defaults to inline.

Precomposed inline-level

  • inline-block: syntactically equivalent to inline flow
  • inline-table: syntactically equivalent to inline table
  • inline-flex: syntactically equivalent to inline flex
  • inline-grid: syntactically equivalent to inline grid

Transformations

  • Inlinification sets the outer display type to inline. If an inline box is inlinified, its in-flow children are recursively inlinified, so that no block-level descendants break up the inline.
  • Blockification sets the outer display type to block. It the inner display type is inline or layout-internal, it is set to flow so that it becomes a block container.

@SelenIT
Copy link
Collaborator

SelenIT commented Jun 12, 2017

will still have problem #1486, because you are still limited to 4 values

I supposed this limitation to be the key part of fixing that issue — there would be no syntactically different forms of inline block with too subtle difference. There is just one layout mechanism inside (the flow layout) and we have 4 options how to inject it into the parent flow (on inline or on block level and as continuation of the parent formatting context or as an "island" of the new one), only one of which corresponds to inline-block. And if we decide that inline-flow-root blockifies as block (probably not very intuitive, but IMHO less counter-intuitive than having two different syntaxes for virtually the same thing), we will have the consistency with the existing browser behavior (if I didn't miss something, and given that the used value of the outer display type of blockified items would become flow-root). Inlinification could still preserve flow-root-ness.

The run-in issue can be solved by adding a similar counterpart value to run-in that gives its content the flow-root-ness (run-in-flow-root?).

Also, all the existing inline-prefixed values would have the same meaning (inline-flow-root outer display) and wouldn't interfere with the only two values currently corresponding to the non-flow-root inline outer display (inline itself and ruby).

Your last proposal looks interesting, but it seems to me that having two syntactically different things that generate the same box and differ only in one very special case and in a very subtle technical way that doesn't make much sense for a typical CSS author is exactly the key question of #1486, the intent was to avoid this as much as possible. Also, if we selectively prohibit specific values from certain combinations, wouldn't it be simpler to selectively change just the blockification rule for flow-root, without adding any more complexity to the spec?

Also, all the proposals that affect only nuances of the flow transformations don't seem to solve the ruby FC-ness problem (#1457). Only your initial proposal (and perhaps flow-root-ness as outer display feature?) seem to do it.

@Loirooriol
Copy link
Contributor Author

given that the used value of the outer display type of blockified items would become flow-root

It seems our points of view are different because you take this for granted and I don't. Unless I'm missing something, this is not in the spec. But yes, making blockified elements "become a formatting context" would allow to preserve syntactic equivalence and flow-root-ness with just 4 flow values. (Well, flow-root-ness would be lost in inheritance).

However, I would still consider adding new inner types or an independent flow-root. I don't think that users will be confused by different values usually behaving the same if the behavior is different sometimes. For example, I don't see anybody confused about inline-flex and flex behaving the same inside a flex container, because in a block container they are different. The proposals here are the opposite, inline-block and inline flow-root behave the same in flow layout but would be different in a theoretical layout that blockifies without triggering "becoming a formatting context". I'm not sure this thing exists, but it might, unless "becoming a formatting context" ends up being triggered by blockification itself.

all the proposals that affect only nuances of the flow transformations don't seem to solve the ruby FC-ness problem

Yes, this could be addressed separately by adding a ruby-root internal type.

@SelenIT
Copy link
Collaborator

SelenIT commented Jun 14, 2017

I still believe that there is a significant difference between "usually obviously different, the same in specific conditions" and "indistinguishable in most cases, different in a yet theoretical specific case". And introducing such entities primarily as a workaround for an inconsistency occured because of legacy reasons looks a bit like trying to invent a sledgehammer in order to crack a nut.

Currently we have 4 flow layout options (FC-continuing inline box, FC-continuing block box, FC-changing inline box and FC-changing block box) that cover all cases that occur currently in practice, right? We have just a legacy requirement that FC-changing inline box, at least in one of it syntactical forms (which is at the moment the only available option in practice), has to blockify as FC-continuing block box. It seems that neither approach (current flow-root as an internal display type, as outer display type, and flow-rootness as a separate feature) solves that automatically without additional assumptions. And splitting the FC-changing internal flow type into different options (like "always new BFC" and "new BFC only if in other FC") inevitable creates several combinations that have little practical value and probably should be explicitly prohibited (as in your latest proposal).

Looking for the least complex solution, I came up with the following proposal that from the first glimpse seems to solve both #1457 and the inline-block dilemma:

  • Leave all inner display values as is;
  • Introduce just one new outer display value like atomic-inline (or even plain inline-block?).

For inner display values that automatically isolate their contents from the parent flow (table, flex, grid, and flow-root) this value would be effectively the alias of inline (and even may compute to it). But for flow and ruby, it would create an atomic inline box with the "island" of other FC, which could easily become layout-containing etc. And it would get blockified as block, exactly like inline does.

So we would still have 5 options of flow layout:

Short `display` Full `display` Box Blockifies as
`inline` `inline flow` inline box `block`
`block` `block flow` block-level flow container `block`
`inline-block` `atomic-inline flow` (`inline-block flow`) atomic inline-level flow container (effectively the same behavior as inline-level BFC container) `block`
`flow-root` `block flow-root` block-level BFC container `flow-root`
`inline flow-root` inline-level BFC container `flow-root`

There would still be two syntactically different ways to get the behavior or the inline-level BFC container, but their distinction would be more obvious (one isolated "from inside" and another "from outside"), and I suppose that inline flow-root option would be rarely used. And inline-block preserves the same inner display as block (unlike the current spec!) and blockifies as block, like it happens in browsers. Also, we would get the atomic-inline ruby/inline-block ruby option to solve the ruby layout containment issue. What have I missed?

@Loirooriol
Copy link
Contributor Author

introducing such entities primarily as a workaround for an inconsistency occurred because of legacy reasons

I don't agree with the analysis, it's not just because of legacy. inline-block just establishes one as a side-effect of participating in an IFC instead of another BFC. So for me it makes perfectly sense to blockify inline-block to block, and inlinify block to inline-block. Then flow-root was introduced as a manual way to establish a BFC, and the inner type of inline-block was mapped to that. But this is undesirable because explicitly requesting a BFC is different than generating one as a side-effect.

About your proposal, I'm confused that you are reticent to add more inner display types, which might produce some combinations that behave mostly the same, but instead you propose adding an outer display type, which would have no effect for table, flex, grid, and flow-root.

Note this would not solve the ruby problem entirely. When a block ruby becomes a formatting context, the principal wrapper box should become a block-level BFC root, and your proposal still does not allow this.

@fantasai
Copy link
Collaborator

I would just like to point out that block-level or inline-block-like ruby is not really an important use case (I've never seen anyone requesting it), so whatever we do here shouldn't be contingent on solving that problem. It's fine if it's not possible to specify.

@Loirooriol
Copy link
Contributor Author

I was thinking that it's a bit weird that flex items and grid items have a block outer display type if they are flex-level or grid-level instead of block-level. So if block becomes an inner display type, the outer display type could be renamed to normal or something like that. It would create an appropriate-level box depending on the parent formatting context. This way there would be no name clash.

@w3c w3c deleted a comment from css-meeting-bot Aug 3, 2017
@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed flow-root syntax, and agreed to the following resolutions:

  • RESOLVED: Leave 'display' syntax as-is for #1496
  • RESOLVED: For 1246, inlinification of 'block flow' goes to inline flow-root aka inline-block, blockfication of inline flow-root & inline-block go to 'block'
  • RESOLVED: For 1486, issue is moot because 1246 resolution was reverted (above)
  • RESOLVED: 'inline flow-root' serializes in getComputedStyle as 'inline-block'
The full IRC log of that discussion <surma> Topic: flow-root syntax
<astearns> github: https://github.com//issues/1496
<Florian> 1550 is not listed in the wiki, but also interconnected
<astearns> <whiteboarding again>
<fantasai> Tab draws a table with columns flow/flow-root, rows block/inline, and values block / BFC / inline-block / inline (clockwise)
<fantasai> Tab: block has to inlinify to inline-block, and inline-block has to blockify to block
<nainar> https://www.irccloud.com/pastebin/8vyC7bj7/
<nainar> TabAtkins: to make this happen properly - we check if the value is a special value
<nainar> TabAtkins: we could break the congruence between legacy values andthe keywrod values so that we define that inline blockifies to block and inline
<fantasai> ScribeNick: fantasai
<fantasai> TabAtkins: which would mean that inline-block won't behave the same as inline flow-root
<fantasai> TabAtkins: even though they're the same thing
<astearns> s/andthe keywrod values/and the two-keyword values/
<fantasai> TabAtkins: I have an alternate suggestion
<fantasai> TabAtkins: It's still a little confusing, but maybe better
<fantasai> TabAtkins: That would avoid breaking existing implementations of flow-root, which have already shipped
<fantasai> TabAtkins: First suggestion is that we stick with block and inline
<fantasai> TabAtkins: But rather than just two values of flow/flow-root, we have three, calling 1 2 and 3 atm
<fantasai> TabAtkins: in increasing order of BFCness
<fantasai> TabAtkins: Legacy inline is inline-1
<fantasai> s/inline-1/inline+1/
<fantasai> TabAtkins: legacy block is block+2
<fantasai> TabAtkins: inline-block is inline+2
<fantasai> TabAtkins: 2 is the "keep my children together" value
<fantasai> TabAtkins: 3 is the even stronger one, so flow-root is block+3
<nainar> fantasai:
<fantasai> TabAtkins: and inline+3 is inline-super-block
<fantasai> Florian: What is an inline-super-block?
<fantasai> Florian: In which cases do they behave differently?
<nainar> fantasai: when does that matter?
<fantasai> TabAtkins: If it blockifies it blockifies to flow-root
<fantasai> (swap last two)
<fantasai> TabAtkins: You contain floats and stuff
<fantasai> TabAtkins: So if you have a plain inline block
<fantasai> Rossen: You ahve two inline blocks, and they are inside a flex. They both get blockified
<fantasai> Rossen: If those have floats inside, those floats don't affect each other
<fantasai> Florian, fantasai: Flex items are BFCs
<fantasai> Florian, fantasai: When does CSS blockify something and not turn it into a BFC also?
<fantasai> TabAtkins: I can't think of any case...
<fantasai> Florian: What about the block+1 case?
<fantasai> TabAtkins: tiny-block
<fantasai> TabAtkins: tiny-block inlinifies to inline
<fantasai> Florian: concrete example?
<fantasai> TabAtkins: If you have a normal block inside of a ruby container. If you put a tiny-block into a ruby then it turns into a regular inline
<fantasai> TabAtkins: falls out of the 2x3 array
<fantasai> TabAtkins: I guess then we have two values that fall out and aren't really useful
<fantasai> TabAtkins: So in that case, I think we should have a diamond
<fantasai> Florian: So how's that different from 2x2?
<fantasai> TabAtkins: block and inline-block correspond
<fantasai> TabAtkins: I guess flow-root oesn't inlinfiie? Or maybe becomes inline-block?
<fantasai> TabAtkins draws a bunch of arrows
<fantasai> Florian: I don't know if this is useful.....
<fantasai> iank_: Why can't we ?
<fantasai> TabAtkins: Because block has to inlinifie to inline-block, and inline-block blockify to block.
<fantasai> fremy: getComputedStyle, right
<fantasai> Florian: that and display: inherit, which nobody does
<fantasai> Florian: Could we say that everything that BFCizes makes you go from block to flow-root ans independnetly from ...
<fantasai> Florian: Maybe?
<fantasai> TabAtkins: So given that block+1 doesn't have a use case, and neither does inline+3 ...
<nainar> fantasai: i think its silly to have a combo that is not useful - cant see how this is better
<nainar> s/combo/bunch of combos
<fantasai> TabAtkins: I want inlinification and blockification to be simple
<fantasai> TabAtkins: 2x2 grid doesn't work, have ot special case things
<nainar> fantasai: I think you're overex=hasizng th imp of inlinification of swapping a keyword in an onut
<nainar> fantasai: if we take arrows this set of 4 values correspond like that it will be better.
<nainar> fantasai: we either have to syntatically disallow or have them do nothing
<fantasai> TabAtkins: ....
<fantasai> TabAtkins redraws original 2x2 grid
<fantasai> TabAtkins draws arrows representing inlinification and blockification
<nainar> s/overex=hasizng/overemphasizing
<fantasai> TabAtkins: You don't have pairs, a flow-root inlinifies to an inline-block which then blockifies to a block
<fantasai> TabAtkins: But that doesn't seem to be a practical concern
<fantasai> Florian: ...
<fantasai> gregwhitworth: Can you please use words?
<fantasai> Florian: If the only dif between block and flow-root is being a BFC
<fantasai> Florian: becoming a block ...?
<Rossen> [Florian frantically pointing at the whiteboard yelling "this"]
<fantasai> TabAtkins: Inline block currently becomes a block when it blockifies
<fantasai> TabAtkins: It just happens to be an BFC in all these cases, but its computed value is 'block'
<fantasai> TabAtkins: e.g. for flex items, if you specify 'display: inline-block' and ask for its computed display you get 'block'
<fantasai> TabAtkins: Generally the case, also for abspos etc.
<fantasai> TabAtkins: Because 'flow-root' didn't exist 15 years ago
<fantasai> TabAtkins: I don't like it, but I'd be okay with just doing this (points at 2x2)
<fantasai> TabAtkins: So it's fine.
<fantasai> TabAtkins: OK, so we can analyze the other things
<fantasai> TabAtkins: So if we have blockification /inlinification algos just explicitly map these values in the 2x2 grid
<fantasai> TabAtkins: Then the next issue is ...
<fantasai> TabAtkins: This solves 1246
<fantasai> TabAtkins: where bz points out we get the wrong computed style (get flow-root where breaks legacy)
<fantasai> (note to Dael, Rossen's comment goes into the Florian: ... line)
<fantasai> Florian: I believe the board is a re-resolution of 1246
<fantasai> TabAtkins: also resolves 1496
<fantasai> TabAtkins: Suggested resolution is that blockfiication of an inline flow-root aka inline-block is defined to go to 'block'
<fantasai> TabAtkins: And inlinification of block flow special cases to inline flow-root aka inline-block
<nainar> fantasai: 1486 is still open?
<fantasai> astearns: So sticking with 1496
<fantasai> RESOLVED: Leave 'display' syntax as-is for #1496
<fantasai> RESOLVED: For 1246, inlinification of 'block flow' goes to inline flow-root aka inline-block, blockfication of inline flow-root & inline-block go to 'block'
<fantasai> RESOLVED: For 1486, issue is moot because 1246 resolution was reverted (above)
<nainar> fantasai: inline flow-root what is the computed value if we arent blockifying?
<nainar> fantasai: the serialization?
<fantasai> RESOLVED: 'inline flow-root' serializes in getComputedStyle as 'inline-block'
<fantasai> Florian: https://github.com//issues/1550
<fantasai> TabAtkins: This is oriol asking, mechanisms that turn BFCs, why not make them all resolve to display: flow-root instead. And we can't due to web-compat
<fantasai> Florian: It's not that there are 2 behavior for flow, there are 4, and flow is way overloaded
<fantasai> TabAtkins: 2nd and 3rd are the same thing
<fantasai> (of some list that I missed, sorry)
<fantasai> TabAtkins: flow creates regular blocks and sometiems BFC
<fantasai> TabAtkins: That's just the way it is
<fantasai> TabAtkins: oh, I see
<fantasai> TabAtkins: Actual suggestion is to change the value at used value time
<fantasai> TabAtkins: That doesn't mean anything, because it's post box tree construction
<fantasai> TabAtkins: Used values are for turning box tree into fragment tree
<fantasai> dbaron: no, used values are just how we describe transformations that happen after inheritance
<fantasai> dbaron: i.e. anything that's post-computation
<nainar> fantasai: is this editorial? he si saying tha tinstead of describing things as we have it - we shoudl vocab and change flow to flow-root for used value
<fantasai> "This change should have no effect in practice."
<fantasai> TabAtkins: ...
<fantasai> TabAtkins: computed value is eveyrthing before you inherit, and used value is everything after inheritance
<fantasai> Florian: No way to distinguish, but you could say that box tree is computed off of used value of 'display'
<fantasai> Florian: introducing this concept as a way of explaining what happens
<fantasai> fremy: All the old specs we already have will be even more confusing
<fantasai> TabAtkins: We already have had to edit every spec
<fantasai> TabAtkins: e.g. "height behaves as auto" thing
<fantasai> TabAtkins: Not actually every spec anywya
<fantasai> TabAtkins: Seems okay
<fantasai> TabAtkins: dbaron?
<fantasai> astearns: Given item wasn't on agenda, and this is first time apparently anyone understood it...
<fantasai> TabAtkins: OK, can discuss later
<fantasai> Florian: It was sort of on the agenda, next issue links to this one
<fantasai> astearns: OK, let's switch the topic and get minutes posted to the correct issues.

@tabatkins
Copy link
Member

AKA: we'll make a special-case in "inlinification" and "blockification" to make block <=> inline-block; everything else just sets outer display type to "inline" or "block".

inline-block is now back to being identical to "inline flow-root".

@Loirooriol
Copy link
Contributor Author

OK, but then please make blockifications trigger becoming a formatting context in order to maintain flowrootness.

@tabatkins
Copy link
Member

We can't do that due to legacy reasons; "inline-block" has to become "block" when blockified. :(

In any case, this was fixed in 2278ea7

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

7 participants