Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-flexbox-1][css-position-3] static position of abspos flex children #5843

Open
fantasai opened this issue Jan 7, 2021 · 23 comments
Open
Labels

Comments

@fantasai
Copy link
Collaborator

fantasai commented Jan 7, 2021

@dholbert pointed out in #1432 (comment) #1432 (comment) and https://bugzilla.mozilla.org/show_bug.cgi?id=1682641#c9 that the newer CSS Positioned Layout model for handling the alignment properties and the flexbox spec conflict on a few points.

First, overall:

  • css-position defines abspos layout as creating an inset-modified containing block (where some of the insets are auto insets derived from the static position), and then applying alignment within that rectangle. It defines the auto offsets for a flex child to coincide with the content edges of its container.
  • css-flexbox sets the position of an abspos child more directly in https://drafts.csswg.org/css-flexbox/#abspos-items in normative prose by defining it as the position the item would have had as the sole flex item (but says something different, matching css-position, in the note in the same section).

A few places where this matters that @dholbert pointed out:

  • Per css-position, in a column flex container, the align-self property will apply in the block axis, not the main axis. But per css-flexbox, it will affect the static position in the main axis.
  • Per css-position, the justify-self property will affect the static position in the inline axis. Per css-flexbox, it can have no effect.
  • Per css-position, justify-content and align-content on the container have no effect on the child's static position. But per css-flexbox, they do.

We need to resolve these conflicts somehow.

@fantasai fantasai added css-flexbox-1 Current Work css-position-3 Current Work labels Jan 7, 2021
@tabatkins
Copy link
Member

Our preferred resolution is just to say that Position is correct, and Flexbox was written while we were still figuring things out. We suspect the compat impact of making the changes is minimal, especially since cross-browser behavior seems all over place.

@fantasai
Copy link
Collaborator Author

fantasai commented Jan 7, 2021

Mm, actually we have a fair amount of interop here. Test results for a statically-positioned abspos child of a flex container:

  • Neither Firefox nor Chrome applies justify-self to an abspos flex child.
  • Both Firefox and Chrome apply align-self to an abspos flex child, in the cross axis.
  • Both Firefox and Chrome apply justify-content on the container to the abspos, in the main axis.
  • Firefox applies align-content on the container to the abspos, but Chrome doesn't. (Note that align-content only has an effect if the flexbox is multiline.)

Note that these behaviors only apply to abspos that are statically-positioned.

@dholbert
Copy link
Member

dholbert commented Jan 8, 2021

Yeah, so the compat situation here (per fantasai's "test results" comment) seems to be that Firefox, Chromium, WebKit, and pre-Chromium Edge all directly implement the Flexbox normative prose (determining the static position as if the abspos thing were the flex container's sole flex item). The only deviation from that is that Chromium, WebKit & pre-Chromium Edge neglect to honor align-content when determining that position (which per the prose, they should honor iff the flex container is multi-line).

So browsers are mostly consistent on this right now, and have been for at least 3-4 years, which makes changes feel pretty risky from a webcompat perspective.

@fantasai
Copy link
Collaborator Author

fantasai commented Jan 8, 2021

OK, so proposal: define the static position rectangle of a flex child as:

  • In the main axis, the start and end margin edges of the child if it were the sole flex item in the container. [this will lock us to the position defined by justify-content on the flex container]
  • In the cross axis, we have a couple options:
    1. Use the start/end margin edges of the hypothetical flex item honoring both align-self and align-content per Firefox.
    2. Use the start/end margin edges of the hypothetical flex item pretending flex container is single-line OR use the content-box edges of the container and define that statically-positioned abspos flex children specially map their align/justify-self axes per the container's flex flow instead of the abspos containing block writing mode. (Same effect, different definition methods.)
    3. Use the content-box edges of the container, allow alignment properties to work within resulting range as for other abspos.

The first option is consistent with Firefox and the Flexbox spec.
The second option is consistent with Chrome and WebKit.
The third option is consistent with Chrome and WebKit in the case of row flex containers, but differs in column flex containers in whether align-self or justify-self controls the alignment. However, it means align/justify-self axis mapping would be consistent across all abspos, instead of making a special exception for statically-positioned flex child abspos.

I think if we can do the third option, in the long run (once alignment is implemented for all abspos), it will be better for authors. But we need to consider the compat impact, and would need data for that.

CC @bfgeek @cbiesinger

@fantasai fantasai removed the css-flexbox-1 Current Work label Jan 8, 2021
@fantasai fantasai added the css-flexbox-1 Current Work label Jan 16, 2021
@fantasai
Copy link
Collaborator Author

Related issue: #5061

@fantasai
Copy link
Collaborator Author

fantasai commented Jun 9, 2021

So the question we need an answer to is, would swapping the axes of align-self vs justify-self on an abspos child of a column flex container (i.e. making align/justify match the block/inline split of other abspos, rather than the cross/main of other flex items) break content.

@cbiesinger
Copy link

Maybe @davidsgrogan can help with adding a use counter for align-self/justify-self on abspos items in a column flexbox? I guess ideally limiting to items which don't have the corresponding left/top/right/bottom property specified...

@foolip
Copy link
Member

foolip commented Jun 10, 2021

I'm interested in this issue because it's a large chunk of failures in https://wpt.fyi/compat2021?feature=css-flexbox and am trying to understand, with the help of @svillar. I'm wondering about these two comments:

@tabatkins said:

cross-browser behavior seems all over place

@dholbert said:

browsers are mostly consistent on this right now, and have been for at least 3-4 years

Getting clarity on this would be great, and seems like it's what should determine the outcome here. If there is already a high degree of interop here, then unless the behavior creates problems for web developers, just sticking with it seems best. But there have been cases in the past when moving away from interop has been the only way to get to a sensible state, so it's not a hard rule. What should happen here?

@fantasai
Copy link
Collaborator Author

@foolip See #5843 (comment)

@foolip
Copy link
Member

foolip commented Jun 11, 2021

OK, so interpreting that, there's not interop currently, Firefox has one behavior and Chrome+Safari have a largely matching but different behavior. This matches the test results here:
https://wpt.fyi/results/css/css-flexbox/abspos?run_id=5121058602483712&run_id=5638952738357248&run_id=5721849096830976

Since someone will have to change to align, understanding the compat risk indeed sounds important. @bfgeek @cbiesinger do you know if there are use counters for this already?

@davidsgrogan
Copy link
Member

@foolip, apologies, I agreed to add use counters in another thread and didn't update here.

@foolip
Copy link
Member

foolip commented Jun 11, 2021

No worries, I'm just stalking this thread and don't really understand the background and context here. If use counters are being added, it seems like there's a clear next step at least: see if they're <0.01% or so and if we can figure out what kind of content triggers it.

@davidsgrogan
Copy link
Member

Question about proposed new behavior for which I'm gathering compat data.

  • css-flex tells engines to honor align-items when determining static position of abspos flex children
  • css-align-3 dictates ignoring align-items because the abspos children don't participate in this box's formatting context. (Right?)

Which behavior is being proposed here? E.g. These are rendered the same today. Are they rendered the same in this proposal?

<div class=column-flexbox>
  <div class=abspos-flex-child style="align-self: center;"></div>
</div>
<div class=column-flexbox style="align-items: center">
  <div class=abspos-flex-child></div>
</div>

fiddle version

Both FF and Chrome honor align-items today as can be seen in bottom flex box at the fiddle above.

@fantasai
Copy link
Collaborator Author

@davidsgrogan Hm, that's a separate question I think.

So I guess we have two questions:

  • For an abspos child of a flex container, would causing align-self and justify-self to swap axes (so they match the block/inline axis, like for abspos anywhere else) cause any breaking changes? This requires:

    • The flex container in question is a column flex container.
    • The align-self and justify-self map to different values in an absolute sense.
    • The abspos child has both insets in an axis set to auto (and is therefore statically positioned).
    • The static positioning rectangle is not equal in size to the abspos item’s margin box in that axis (thus the alignment properties can have an effect in this axis).
  • For an abspos child of any flex container, would disconnecting align-self from the parent’s align-items cause any breaking changes? This requires:

    • The abspos item is statically positioned in an axis (both insets = auto).
    • The static positioning rectangle is not equal in size to the abspos item’s margin box in that axis.
    • The align-self value is auto.
    • The parent’s align-items value is distinguishable from normal.

So I think those are the cases we need to count?

Note that if we don't disconnect align-items from abspos children, then having align-self take effect on non-statically-positioned abspos items (as specced in css-align-3) would be more likely to be a breaking change, because it would cause all of those absposes to start responding to the align-items value of their flex container parents.

@tabatkins
Copy link
Member

@davidsgrogan Is it possible to get counters looking at the above two sets of conditions?

@davidsgrogan
Copy link
Member

Yes. I have a local WIP patch. It is not as far along as #3052 though.

@davidsgrogan
Copy link
Member

Just update. I haven't worked on this since August but still intend to finish.

@davidsgrogan
Copy link
Member

@fantasai, question about this case:

<div style="display: flex; flex-flow: column; justify-content: end; width: 100px; height: 100px;">
  <div style="position: absolute; justify-self: end; align-self: start; inset-inline: 5px; width: 50px; height: 50px; "></div>
</div>

According to the first set of conditions (the "swap axis" conditions), this counts as a change in behavior, but I don't think this case would actually change under the proposal.

Applying the "swap axis" conditions to this case:

  • The flex container in question is a column flex container.

Check.

  • The align-self and justify-self map to different values in an absolute sense.

start and end are different. Check.

  • The abspos child has both insets in an axis set to auto (and is therefore statically positioned).

Yep, block axis insets are auto. Check.

  • The static positioning rectangle is not equal in size to the abspos item’s margin box in that axis (thus the alignment properties can have an effect in this axis).

50x50 and 100x100 are different. Check.

I think check 3 and check 4 need to be scoped to the cross axis, not an axis. Because the proposal only changes behavior for cross-axis positioning, I think, because this part of the proposal matches what engines already do today, right?

In the main axis, the start and end margin edges of the child if it were the sole flex item in the container. [this will lock us to the position defined by justify-content on the flex container]

@bfgeek
Copy link

bfgeek commented May 24, 2022

David and I chatted quickly about this case today. @fantasai am I correct in assuming that your preferred behaviour here is:

  • The static-pos rectangle for an abspos is the flexbox's content-box.
  • (and align-self / justify-self apply as described in css-align-3).
  • Then I'm confused about the desired behaviour for align-content and justify-content is it to:
    • Ignore align-content / justify-content for abspos (as the static-position rect can't "shift" for a flexbox).
    • Or to treat justify-conent similar to how flexbox is doing it today, but applied like align-self/justify-self in css-align-3? (ignoring align-content).

Ian

aarongable pushed a commit to chromium/chromium that referenced this issue May 25, 2022
There's a proposal in w3c/csswg-drafts#5843 to
change how the static position is calculated for abspos children of flex
containers. This CL is meant to measure how much potential breakage
there is.

But this CL overcounts the incompatibilities so we'll only get a ceiling
on the potential breakage. When the abspos element is the same size as
its static position rectangle, the proposed new behavior will match
existing behavior no matter the inset or alignment properties. But
because Blink never actually stores the static position rectangle, we
can't compare it against the abspos size. So even if the sizes match,
we don't know, so we just pretend they don't match, which causes
overestimating.

Note also that this CL checks what I think are the right conditions,
which slightly differ from fantasai's, as documented in
w3c/csswg-drafts#5843 (comment)

Change-Id: Ifc2fc750dd81871adb77eb8044d94e43482a6df0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3652587
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: David Grogan <dgrogan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1007226}
@davidsgrogan
Copy link
Member

The graph for the first issue from #5843 (comment) is at

https://chromestatus.com/metrics/feature/timeline/popularity/4237.

It overcounts because we don't have the machinery to check this condition:

The static positioning rectangle is not equal in size to the abspos item’s margin box in that axis (thus the alignment properties can have an effect in this axis).

So, even if the rectangle and margin box are equal, we count it as a behavior change.

That graph also implements the slightly different set of conditions from #5843 (comment), namely only checking the cross axis, not either axis.

For the second issue in #5843 (comment) (disconnecting align-self):

I didn't add a UseCounter because I don't really understand it. I don't think my example that prompted it (#5843 (comment)) is a good one. If you give an example that demonstrates the difference between current behavior and proposed behavior, and we still want a UseCounter for it, I can add one later.

Also, I'm confused by this, from the bottom of #5843 (comment)

[not disconnecting] would cause all of those absposes to start responding to the align-items value of their flex container parents.

Absposes currently respond to the align-items value of their flex container parents, so I don't get what you mean by "start".

@rreno
Copy link

rreno commented Aug 11, 2022

It would be great if this could be discussed at the next meeting. The issue @davidsgrogan linked (and this example in particular) is an instance of where the flexbox spec's requirements for align-content, justify-content, align-self, and align-items can cause surprising results.

No engine currently implements align-content: stretch or align-content: normal as written in css-flexbox so a resolution to the inconsistencies between the flexbox and positioning modules could help with browser interop as well.

@rreno
Copy link

rreno commented Aug 11, 2022

After sitting with this for awhile it looks like the issue with align-content isn't due to disagreement between [css-flexbox-1] and [css-position-3] since position defers to flexbox for this case: https://drafts.csswg.org/css-align-3/#distribution-flex

I filed #7596 to discuss resolving the inconsistency between browser implementations and the spec for align-content.

@nt1m nt1m removed the Agenda+ label Aug 11, 2022
fantasai added a commit that referenced this issue Aug 24, 2022
…on rectangle, matching Grid. #5843

Also move the historical note to CSS Positioned Layout.
@fantasai
Copy link
Collaborator Author

@bfgeek The ideal behavior would be to ignore align-content and justify-content, yes. Just like in Grid. That would allow the align-self and justify-self to consistently control alignment on absolutely-positioned descendants attached to the Flex/Grid container, and to allow the -content properties to focus on managing in-flow content.

(We might not be able to make that happen for Flexbox due to compat.)

mjfroman pushed a commit to mjfroman/moz-libwebrtc-third-party that referenced this issue Oct 14, 2022
There's a proposal in w3c/csswg-drafts#5843 to
change how the static position is calculated for abspos children of flex
containers. This CL is meant to measure how much potential breakage
there is.

But this CL overcounts the incompatibilities so we'll only get a ceiling
on the potential breakage. When the abspos element is the same size as
its static position rectangle, the proposed new behavior will match
existing behavior no matter the inset or alignment properties. But
because Blink never actually stores the static position rectangle, we
can't compare it against the abspos size. So even if the sizes match,
we don't know, so we just pretend they don't match, which causes
overestimating.

Note also that this CL checks what I think are the right conditions,
which slightly differ from fantasai's, as documented in
w3c/csswg-drafts#5843 (comment)

Change-Id: Ifc2fc750dd81871adb77eb8044d94e43482a6df0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3652587
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: David Grogan <dgrogan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1007226}
NOKEYCHECK=True
GitOrigin-RevId: 77e37a5f7cb0817f96c8be42fd3ec5518325d052
aarongable pushed a commit to chromium/chromium that referenced this issue Sep 18, 2024
This was added for:
w3c/csswg-drafts#5843

The graphs are at
https://chromestatus.com/metrics/feature/timeline/popularity/4237
https://chromestatus.com/metrics/feature/timeline/popularity/4330

10-20% of page loads so not web compatible. Or at least, the
overcounting version of this data collection is very insufficient.

Change-Id: I9e7f3aa40513cc05a7ffb44e778f2418ff7e98c5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5871801
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Commit-Queue: David Grogan <dgrogan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1356875}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants