Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions css-grid-3/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,20 @@ Placement Precision: the 'item-tolerance' property</h3>
see <a href='https://github.com/w3c/csswg-drafts/issues/3071'>discussions</a>
on how that might work.

<h3 id="masonry-dense-packing">
Dense Placement: the ''item-pack/dense'' keyword</h3>

In [=grid layout=], ''grid-auto-flow: dense'' allows backtracking
during the [[css-grid-2#auto-placement-algo|grid item placement algorithm]].
The ''item-pack/dense'' keyword similarly allows backtracking
during the [[#masonry-layout-algorithm|masonry placement algorithm]].
However, because masonry placement and sizing are intertwined,
an item can only backtrack into a compatible empty slot if
the total used size of that slot’s tracks
matches the used size of the item’s normal-placement tracks.

Note: This restriction avoids laying out the item more than once.

<h3 id="masonry-layout-algorithm">
Masonry Layout and Placement Algorithm</h3>

Expand Down Expand Up @@ -873,6 +887,18 @@ Masonry Layout and Placement Algorithm</h3>
and then layout the item.
Set the [=running position=] of the spanned [=grid axis=] tracks
to <code><var>max_pos</var> + [=outer size=] + 'grid-gap'</code>.

<li>
If the [=masonry container=] uses ''item-pack/dense'' packing,
and there exists skipped empty space (e.g. due to spanning items)
in the layout into which the item, as it is sized now,
could have fit without impacting other items’ placement
if it were earlier in the placement order,
and the tracks it would have spanned at that point
have the same total used size as the tracks into which it is currently placed,
move the item into the earliest such position
and rewind the [=auto-placement cursor=] and the [=running position=]
to their values before this item’s placement.
Copy link
Collaborator

@alisonmaher alisonmaher Sep 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One open question I have is the order in which we break ties with openings of the same start offset. I presume it is using the auto-placement cursor, but do we start from the earlier openings in the current track, or the next track from the one we are currently starting in.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It follows the same rules as normal placement... in other words, we move the item into the earliest placement order that would not change the placement of items after it. Maybe I should clarify this text with that concept...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, tweaked the wording a bit. I'll merge this, and if you have suggestions on how to clarify more we can try for improvements. :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't tell what text changed since I think commits got squashed maybe, but interesting. I'm curious what "earliest in placement order" means - the order in which items get placed, or the earliest in terms of offset? Given that items can be explicitly placed, the former would be tough to track.

I would have guessed we follow the placement cursor to some degree (likely starting from the track the item is originally placed in), and then loop back around to find the opening with the earliest start offset. If there is a tie, you would choose the one closest to the original auto placement cursor.

Or are you saying we should always start looking for track openings at track 0 (i.e. prefer track openings in earlier tracks if there is a tie?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we don't have an in-built ordering such that we can just say "earliest". Individual items are ordered, but their gaps aren't, unlike Grid.

Also, I think this shouldn't change the ordering of things if there isn't a hole somewhere; that is, if your only valid choices are the ends of columns, we should continue to pack as normal, following the placement cursor.

So I recommend saying that, if there are holes that don't correspond to the existing non-dense placements, we choose the "highest" one, tie-breaking with simple layout direction order. No attention paid to or affect on the cursor when this happens.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have a placement order, so what this is saying is if there's a gap earlier than the current location, then you place it as if it were in the earliest possible position where it would satisfy these constraints.

If you have a clearer way to express that, sure, but I don't want to repeat the placement rules here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I recommend saying that, if there are holes that don't correspond to the existing non-dense placements, we choose the "highest" one, tie-breaking with simple layout direction order. No attention paid to or affect on the cursor when this happens.

This makes sense to me and I think is worth updating to clarify since in Chromium we just implemented it based on the placement cursor position for tie breaking, and the current text doesn't really make it clearer to me that the auto placement cursor is ignored when choosing the potential openings

Copy link
Member

@tabatkins tabatkins Sep 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we have a well-defined "placement order" that includes gaps, no. We have a set of possible placements within the threshold distance of the highest one, and cursor+placement direction breaks ties when that set is more than one. This isn't using that set, tho, or even modifying it - it first finds a standard placement as normal, then looks for gaps with the same track size and decides if it wants to move to one of those instead.

(@fantasai and I chatted offline) Ah, you're talking about "what hypothetical rearranging of this item in the list of children would have put it in that hole; choose the position with the earliest index". This implies replaying the placement algorithm to some extent, and at minimum requires recording the state of the auto-placement cursor after each placement; this hypothetical rearrangement could, I think, have had knock-on effects as well on the placement of other items.

Instead, I just want to choose the highest valid hole, and if there are multiple valid holes within the tie threshold of the highest, choose the start-most one. In almost all cases this'll be the same as your intended position, but it's stateless and requires no memory of how placement was performed originally. All you need to maintain is the size and position of the holes you form as placement occurs. (I've given you some proposed text in our shared doc.)

</ol>

Note: This algorithm chooses the track
Expand Down Expand Up @@ -1510,6 +1536,8 @@ Recent Changes</h3>
<a href="https://github.com/w3c/csswg-drafts/issues/12111">Issue 12111</a>)
* Added a placeholder for a [=masonry layout=] 'display' value.
(<a href="https://github.com/w3c/csswg-drafts/issues/12022">Issue 12022</a>)
* Defined [[#masonry-dense-packing|dense packing]] for [=masonry layout=].
(<a href="https://github.com/w3c/csswg-drafts/issues/9326">Issue 9326</a>)
* Tweak baseline alignment to export the highest/lowest among the first/last items of every track.
(<a href="https://github.com/w3c/csswg-drafts/issues/9530">Issue 9530</a>)

Expand Down