Skip to content

[css-align] justify-items and anonymous block boxes #11461

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

Open
Loirooriol opened this issue Jan 8, 2025 · 28 comments
Open

[css-align] justify-items and anonymous block boxes #11461

Loirooriol opened this issue Jan 8, 2025 · 28 comments
Labels

Comments

@Loirooriol
Copy link
Contributor

Loirooriol commented Jan 8, 2025

<!DOCTYPE html>
<div style="width: 200px; justify-items: right; border: solid">
  foo
</div>
<div style="width: 200px; justify-items: right; border: solid">
  foo
  <div></div>
</div>

In Blink it looks like this:

In the 1st case, there is no block-level child to align. In the 2nd case, "foo" gets wrapped inside an anonymous block, which is then aligned by justify-items: right.

But it seems potentially unexpected that appending a block affects the alignment of the inline contents.

Maybe anonymous blocks should get assigned justify-self: startjustify-self: stretch (or normal)?

@gitspeaks
Copy link

gitspeaks commented Jan 9, 2025

Maybe anonymous blocks should get assigned justify-self: start?

But how would you allow aligning 'anonymous blocks' to the end if that's the desired behavior?
If the goal is to align only the 'anonymous blocks' to the end, what other option would you have besides setting justify-items: right on the parent, keeping the current Blink behavior, and explicitly setting justify-self: left on each child div?

@Loirooriol
Copy link
Contributor Author

But how would you allow aligning 'anonymous blocks' to the end if that's the desired behavior?

There is of course a trade-off, we need to think which option will be less confusing.
But the authors could just wrap the inline contents with a <div> rather than relying on an anonymous block, then the element-generated block would obey the justify-items of the parent.

@gitspeaks
Copy link

gitspeaks commented Jan 9, 2025

But the authors could just wrap the inline contents with a <div> rather than relying on an anonymous block, then the element-generated block would obey the justify-items of the parent.

That's beside the point since we're no longer dealing with anonymous block boxes in that case. I think keeping the justify-items behavior consistent for both anonymous and non-anonymous block boxes makes it simpler to reason about. That said, I recommend adding a note in the spec for justify-items as a helpful reminder of the existence of 'anonymous block boxes' and their conforming behavior, aligning with other block boxes.

@Loirooriol
Copy link
Contributor Author

I don't think most authors know about anonymous block boxes, and we typically pretend that they aren't there (see percentage resolution, #2595, etc.)

So I think we should either

  • set justify-self: normal/stretch on anonymous blocks so that they ignore justify-items of the parent, or
  • wrap the inline-level contents of a block container inside an anonymous block even if there is no block-level content, at least when justify-items computes to something different than normal/stretch or lone legacy.

@astearns astearns moved this to FTF agenda items in CSSWG January 2025 meeting Jan 22, 2025
@astearns astearns moved this from FTF agenda items to Regular agenda items in CSSWG January 2025 meeting Jan 22, 2025
@astearns astearns moved this from Regular agenda items to Thursday morning in CSSWG January 2025 meeting Jan 29, 2025
@astearns astearns moved this to Regular agenda in CSSWG April 2025 meeting agenda Mar 27, 2025
@mirisuzanne
Copy link
Contributor

When you add display:grid to the demos above, the anonymous grid item boxes are both aligned. I don't know about the theoretical precedent for pretending there's no box, but I think consistency would point towards always allowing us to align anonymous boxes - and I think that's the more useful answer for authors as well.

@Loirooriol
Copy link
Contributor Author

The big difference is that grid and flex formatting contexts create an anonymous box around each text run. Block formatting contexts only create an anonymous box when there is a mix of inline-level and block-level contents.

So saying that anonymous boxes can always be aligned is still not be enough for justify-items to have any effect here, since no anonymous block box is created:

<div style="width: 200px; justify-items: right; border: solid">foo</div>

@mirisuzanne
Copy link
Contributor

I see, sure. I guess then I'm suggesting that a box should be generated in this case, in order to have consistency. Though I'll admit I don't fully know the side-effects of that.

@gitspeaks
Copy link

gitspeaks commented Apr 29, 2025

I might be missing something, but I think the use of justify-items or justify-self in an inline formatting context isn't meaningful. Inline-level content is laid out using text-align for horizontal alignment and vertical-align for vertical alignment - these are part of a different alignment model than what's used in grid or BFC.

According to 6.1. Inline-Axis (or Main-Axis) Self-Alignment: the justify-self property, justify-self applies to block-level boxes, absolutely positioned boxes, and grid items. With respect to the recent example above, since no anonymous block-level box is created in this case, it's expected that these properties would have no effect for (anonymous) inline boxes within an inline formatting context.

@Loirooriol
Copy link
Contributor Author

Yes, that's the current situation, but it seems bad to me. Hence the 2 options I proposed in #11461 (comment): either prevent justify-items from affecting anonymous block boxes, or always create anonymous block boxes when justify-items is not initial.

Note in the 2nd option text-align and justify-items would still do different things, e.g.

<!DOCTYPE html>
<div style="justify-items: center; text-align: left; border: solid; width: 200px">
  lorem ipsum<br>sit amet
</div>

(avoiding the need to add an inner wrapper to get this effect)

@gitspeaks
Copy link

or always create anonymous block boxes when justify-items is not initial.

I don't follow. Per the spec:

Any text that is directly contained inside a block container element (not inside an inline element) must be treated as an anonymous inline element.

In particular, the text in <div style="width: 200px; justify-items: right; border: solid">foo</div> would be wrapped in anonymous inline box.

How does introducing an anonymous block box here align with the rules for inline formatting contexts? Are you proposing that justify-items implicitly "blockifies" these inline items - effectively changing the formatting context from inline to block? If so, that seems like a substantial semantic shift.

Note in the 2nd option text-align and justify-items would still do different things,

I suppose in cases where there are multiple lines of different lengths (e.g., due to a <br>), text-align can affect the alignment of shorter lines - like right-aligning a shorter second line within a shrink-to-fit box defined by the longer first line.

But that feels like a confusing corner case. The box is anonymous, unstyleable, and auto-sized, so people expect no room for alignment to matter.

I think discarding alignment properties like justify-items in inline formatting contexts including those defined by an anonymous text run is not a bad approach. It reduces ambiguity and preserve a clearer separation between inline and block layout behavior.

@Loirooriol
Copy link
Contributor Author

I'm not proposing to blockify anything.

effectively changing the formatting context from inline to block?

Yes, the 2nd option avoids establishing an inline formatting context on block containers with justify-items (the inline formatting context will instead be established by the anonymous block). But it doesn't force a new block formatting context, the parent BFC can be continued.

I think discarding alignment properties like justify-items in inline formatting contexts including those defined by an anonymous text run is not a bad approach.

I'm not sure if you are arguing for no change, or for my 1st proposed option.

@Loirooriol
Copy link
Contributor Author

Loirooriol commented Apr 30, 2025

<!DOCTYPE html>
<style>body { width: 250px } div { margin: 1em 0 }</style>
<div style="border: solid; justify-items: center">
  1st line<br>
  And another line
</div>
<div style="border: solid; justify-items: center">
  1st line<br>
  And another line
  <p style="border: solid cyan">Nested block</p>
  Foooo<br>
  Bar
</div>
Current Option 1 Option 2

@gitspeaks
Copy link

gitspeaks commented Apr 30, 2025

I'm not sure if you are arguing for no change, or for my 1st proposed option

  1. justify-items should be ignored on a block container that establishes an inline formatting context.
  2. justify-items should apply to anonymous block-level boxes within a block formatting context.

Option: "Current"

@bfgeek
Copy link

bfgeek commented Apr 30, 2025

IMO The current behaviour in Blink is a bug, and I'd prefer "Option 1"

@gitspeaks
Copy link

IMO The current behaviour in Blink is a bug, and I'd prefer "Option 1"

But "Option 1" is not compatible with the scenario described in #11461 (comment)

@Alohci
Copy link
Contributor

Alohci commented Apr 30, 2025

IMO The current behaviour in Blink is undesirable, and I'd prefer "Option 2". As a web author, I always prefer the more control option.

@mirisuzanne
Copy link
Contributor

I agree that:

  • the current behavior seems like a bug, and makes no sense as an author
  • at least option 1 is consistent
  • option 2 is my preference as an author because I like having alignment that works, and I don't need to create special boxes to do that in other formatting contexts

@gitspeaks
Copy link

gitspeaks commented Apr 30, 2025

How is the anonymous block in option 2 sized?

@Loirooriol
Copy link
Contributor Author

How is the anonymous box in option 2 sized?

Yes, both the current Blink behavior and option 2 raise some questions about that. So from an implementation point of view I prefer option 1, which is what I implemented in Servo (I didn't have to do anything special, I just got this behavior due to how we implement anonymous block boxes).

Presumably the anonymous box would be sized as fit-content instead of stretch. But percentages in the block axis skip anonymous block boxes, should it be the same in the inline axis? And what about stretch?

<!DOCTYPE html>
<style>
div { float: left; width: 100px; height: 100px;justify-items: right; border: solid; margin: 1em }
div::before { content: ""; display: block }
span { display: inline-block; border: solid magenta }
</style>
<div> <span style="width: 100%; height: 100%"></span> </div>
<div> <span style="width: stretch; height: stretch"></span> </div>

So Blink breaks the axis symmetry by allowing percentages and stretch to resolve against anonymous block boxes in the inline axis. This inconsistency doesn't sound great, so it solidifies option 1 as the best option for me.

@gitspeaks

This comment has been minimized.

@Loirooriol

This comment has been minimized.

@gitspeaks

This comment has been minimized.

@Loirooriol

This comment has been minimized.

@gitspeaks

This comment has been minimized.

@gitspeaks

This comment has been minimized.

@Loirooriol

This comment has been minimized.

@gitspeaks
Copy link

IMO, option 2 feels like a hack. justify-items sets the default justify-self for items, but under the current suggestion, it ends up applying to an injected anonymous block container that wraps all inline content in an inline formatting context. This effectively aligns the group as a whole, rather than the individual elements. I can easily see authors getting confused when they try to set justify-self on the inline elements themselves to override the default as they would expect in other formatting contexts only to find it has no effect. It's a very confusing API, to be honest.

@gitspeaks
Copy link

Also, I don’t think whether the current Blink behavior is a bug is a matter of opinion but rather it’s a question of whether it conforms to the specification, which it does. While justify-items applies to any element, justify-self does not apply to inline elements. In fact, the specification text for justify-items is explicit:

This property specifies the default justify-self for all of the child boxes (including anonymous boxes) participating in this box’s formatting context.

So it should come as no surprise that an anonymous block box in Blink derives its default value from justify-items, whereas anonymous inline boxes do not since justify-self doesn’t apply to them in the first place.

Similarly, consider how the height property works, it applies to block elements but not to inline non-replaced elements. Authors have come to understand and expect this behavior. So the current Blink behavior is not only consistent with the specification, but also aligned with how block-specific properties generally interact with inline non-replaced elements.

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue May 5, 2025
See: w3c/csswg-drafts#11461

Our current behaviour is (IMO) a bug, so tentatively change it to
"Option 1" in the issue.

Adds a tentative test as well.

Change-Id: I145d39d819347d3446dd08cdd98e055e40625b53
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue May 5, 2025
See: w3c/csswg-drafts#11461

Our current behaviour is (IMO) a bug, so tentatively change it to
"Option 1" in the issue.

Adds a tentative test as well.

Change-Id: I145d39d819347d3446dd08cdd98e055e40625b53
aarongable pushed a commit to chromium/chromium that referenced this issue May 5, 2025
See: w3c/csswg-drafts#11461

Our current behaviour is (IMO) a bug, so tentatively change it to
"Option 1" in the issue.

Adds a tentative test as well.

Change-Id: I145d39d819347d3446dd08cdd98e055e40625b53
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6512658
Reviewed-by: David Grogan <[email protected]>
Commit-Queue: Ian Kilpatrick <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1455957}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue May 5, 2025
See: w3c/csswg-drafts#11461

Our current behaviour is (IMO) a bug, so tentatively change it to
"Option 1" in the issue.

Adds a tentative test as well.

Change-Id: I145d39d819347d3446dd08cdd98e055e40625b53
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6512658
Reviewed-by: David Grogan <[email protected]>
Commit-Queue: Ian Kilpatrick <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1455957}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue May 5, 2025
See: w3c/csswg-drafts#11461

Our current behaviour is (IMO) a bug, so tentatively change it to
"Option 1" in the issue.

Adds a tentative test as well.

Change-Id: I145d39d819347d3446dd08cdd98e055e40625b53
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6512658
Reviewed-by: David Grogan <[email protected]>
Commit-Queue: Ian Kilpatrick <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1455957}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Regular agenda
Status: Thursday morning
Development

No branches or pull requests

5 participants