Is there a "subgrid" feature, to position "grandchildren" of a grid container?
Asked Answered
C

2

27

All guides about CSS grid seem to imply a structure where the elements positioned in a grid are direct children of the grid element itself:

<div class="wrapper">
  <div>A</div>
  <div>B</div>
</div>

Where .wrapper has display: grid and a definition of the grid properties.

Does it make any sense if I want to position a element that is a "grandchild" of the grid, on the grid itself (instead of relying on its parent?)

<div class="wrapper">
  <div>A</div>
  <div>
    <div>B</div>
    <div>C</div>
  </div>
</div>

I want to place A, B & C each on their own row of the grid; would that even make sense?

Carmelo answered 21/12, 2017 at 16:49 Comment(3)
This would perfectly make sense, but the current grid implementations don't allow this:(. This is a well-known limitation, there was a subgrid proposal to solve it, but it was hard to implement, so it was postponed for the future CSS Grid Level 2 spec. To some extent, it can be solved by using display:contents for the child whose children should be placed in the grid, but it's currently supported only by Firefox, WebKit TP, and Chrome behind the flag.Degrading
@IlyaStreltsyn That's an answer, I'd post that. It's a good marker for similar questions.Demand
@IlyaStreltsyn I would also accept that as an answer. "In a grid, only direct children are grid items and can be positioned on the grid. " (a line from the igalia article) is what I wish was printed in red at the very top of every guide about grid. sighCarmelo
S
11

display: subgrid

From the CSS Grid Level 2 draft spec:

2. Grid Containers

Subgrids provide the ability to pass grid parameters down through nested elements, and content-based sizing information back up to their parent grid.

If the element is a grid item (i.e. it is in-flow and its parent is a grid container), display: subgrid makes the element a subgrid (which is a special type of grid container box) and consequently ignores its grid-template-* and grid-*-gap properties in favor of adopting the parent grid tracks that it spans.

3. Subgrids

A grid item can itself be a grid container by giving it display: grid. In this case the layout of its contents will be independent of the layout of the grid it participates in.

In some cases it might be necessary for the contents of multiple grid items to align to each other. A grid container that is itself a grid item can defer the definition of its rows and columns to its parent grid container by using display: subgrid, making it a subgrid.

In this case, the grid items of the subgrid participate in sizing the grid of the parent grid container, allowing the contents of both grids to align. Read more.

This feature has not yet been implemented in major browsers. Who knows when it will be.

In Grid, only the in-flow children of the container become grid items and can accept grid properties.

With display: subgrid on a grid item, the children of the item respect the lines of the container.

According to the Grid Level 1 spec, display: subgrid has been deferred to Level 2.

For now, display: grid on grid items (i.e., nested grid containers) may be useful in some cases.

Another possible workaround is display: contents. The method is explained here:

More information:

Sheila answered 21/12, 2017 at 20:47 Comment(4)
I accept for the "display: subgrid" part, which essentially means "no, that's not possible yet" :)Carmelo
Subgrid is now implemented in Firefox 69+. Nowhere else, though, so still not usable.Lora
As of today, subgrid is supported in Safari 16.0+ and is currently still in the development phase for ChromeGaselier
As of September 2023 subgrid is supported in all evergreen browsersStephine
L
8

Since subgrids are not supported at all, as of writing this answer, on browsers other than latest Firefox v71, and even if other browsers would start supporting it, still, users with older versions will be left behind for at least a year until enough users upgrade their browsers to be able to use such a new feature.

I've devised a method for aligning deeply-nested grid elements on an ancestor grid:

At its essence, this solution is about applying display:contents to all nested elements of the grid, up to the ones wished to be used as the grid items, which effectively does an inverse-inheritance, so every element set with display:contents is actually projecting its child's display, so ultimately the deeply-nested elements are treated as if they were direct children of the .container element.

.container {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  max-width: 500px;
  margin: auto;
}

.container div{
  display: contents; /* <-- makes the div elements "transparent" to the grid */
}

input{ height: 40px; }
label{ align-self: center; }
<div class="container">
  <div>
    <div>
      <div>
        <label contenteditable>very long label</label>
        <input>
      </div>
    </div>
  </div>
  <div>
    <div>
      <div>
        <label contenteditable>short</label>
        <input>
      </div>
    </div>
  </div>
</div>

This is treated by the browser as if:

<div class="container">
  <label contenteditable>very long label</label>
  <input>
  <label contenteditable>short</label>
  <input>
</div>

In the above example the labels are editable to showcase the dynamic nature of the grid tracks, so all grid items are aligned.

Codepen demo

Limnology answered 13/10, 2021 at 8:38 Comment(3)
This is really useful for satisfying certain grid layouts when used with loops in React. If a design requires each list item to output multiple elements but still stay aligned to the grid, React unfortunately will want an extra container for each item since each child requires a unique key. That extra container React wants will cause the children not to be aligned, but this fixes that. Thanks!Tristis
I don't understand what is "extra item" mean. Why would React would "want" that? I'm a React PRO and you do not need ever any extra container, unless you're returning raw string in the JSX iterationLimnology
I've gotten so used to the shorthand for React Fragments that I forgot we could set a key on the actual Fragment component if we import it. 😅 You pushing back on that just made me remember. Thank youTristis

© 2022 - 2024 — McMap. All rights reserved.