Subgrid is an additional feature to CSS Grid introduced in Level 2 of the specification which allows nested grids to participate in the sizing of their parent grids.
When CSS Grid was initially released in 2017, designers and developers were very excited about the prospect of a layout system that was designed and optimised for doing two-dimensional layout on the web. CSS Grid allowed us to do many things with an ease that was not possible before.
However, it also came a certain limitations. One of the bigger ones was the fact that nested grids were unable to participate in the sizing of their parent grids. This was a feature which was deemed important from the start, however, due to its complexity, it was deferred to Level 2 of the CSS Grid specification to allow implementors and specification editors more time to work through the various use-cases to ensure more robust implementation.
This entry will cover subgrid capabilities only. For information about CSS Grid, please refer to the entry on Grid.
Establishing a subgrid
The CSS Grid Layout Module Level 2 introduces 2 new values to the grid-template-columns
and grid-template-rows
properties, which allow us to establish a subgrid within an existing grid container.
grid-template-columns: subgrid <line-name-list>? grid-template-rows: subgrid <line-name-list>?
The keyword subgrid
indicates to the browser that the nested grid will use the same sizing as its parent grid for the portion occupied along the relevant axis. Hence the subgrid’s items will placed and sized according to its parent grid’s track sizing. Subgrids can take the track sizing of their parent grid along a single axis (row or column), or along both axes.
When an element has a display
value of grid
, an independent grid formatting context is established. A subgrid’s contents participate in its parent grid formatting context, and does not establish a new grid formatting context.
The syntax of <line-name-list> is defined as follows:
<line-name-list> = [ <line-names> | <name-repeat> ]+ <line-names> = '[' <custom-ident>* ']' <name-repeat> = repeat( [ <positive-integer> | auto-fill ], <line-names>+)
If you have used the repeat()
function when using Grid, one thing to note is that there is a slight difference when using it in the context of a subgrid, as in this case, only line names are repeated.
.subgrid-container {
display: grid; /* you must still apply a display: grid to the subgrid */
grid-template-columns: subgrid;
grid-template-rows: subgrid;
}
The subgrid will not have any implicit grid tracks in the subgridded axis (or axes) because its grid tracks match up to that of the parent grid. Line numbers on the subgrid start from 1, and do not follow that of the parent grid.
However, if there are any line names on the parent grid, they will be inherited by the subgrid, but it is also possible to provide line names local to the subgrid. The parent grid will not be able to use those line names as they only apply to the subgrid.
Say we have the following markup for a page with a sidebar and some content, and within the content, there is an article and an aside:
<body class="grid-container">
<nav class="sidebar"></nav>
<main class="content">
<article>
…
</article>
<aside>
…
</aside>
</main>
</body>
We can allow the children within the main
element to participate in the parent grid with the following CSS, as well as assign local grid line names to the columns of the subgrid as well.
.grid-container {
display: grid;
grid-template-columns: [gridcol-1] 1fr [gridcol-2] 1fr [gridcol-3] 1fr [gridcol-4] 1fr [gridcol-5];
}
.content {
/* placement for the subgrid container itself */
grid-column: gridcol-2 / gridcol-5;
display: grid;
/* number of line names must match number of lines from parent grid */
/* excess names are ignored */
grid-template-columns: subgrid [subcol-1] [subcol-2] [subcol-3] [subcol-4];
}
article {
grid-column: subcol-1 / subcol-3;
}
aside {
grid-column: subcol-3 / subcol-4;
}
The number of line names declared on the subgrid should match the number of lines which the subgrid spans across the parent grid. Any excess names declared will simply be ignored.
Understanding subgrid item sizing behaviour
There are a number of additional things to note with regards to other layout CSS properties. Line numbering and placement rules obey the subgrid’s own writing-mode
, which is also the case for a normal nested grid.
As mentioned earlier, a subgrid will not have any implicit grid tracks along the subgridded axis (or axes). In the event a subgrid item is placed outside the explicit grid or spans an area larger than the explicit, the subgrid item will be “clamped” to the explicit grid.
.grid {
display: grid;
grid-template-columns: repeat(5, minmax(2em, 1fr));
}
.subgrid {
grid-column: 2 / 4;
display: grid;
grid-template-columns: subgrid;
}
.subgrid__item-1 {
grid-column: span 3;
}
.subgrid__item-2 {
grid-column: 4;
}
In the above code example, the first subgrid item should span 3 grid columns, however, the subgrid only takes up 2 columns, as such, the browser will clamp the size of this item to the 2 columns of the subgrid. Similarly, the second subgrid item has been placed outside the explicit grid, and again, it ends up being placed into the last grid column of the subgrid.
Any margins, borders and paddings applied to each edge of the subgrid will manifest themselves as an extra layer of margin to the subgrid items at those edges. This extra “layer” of margin will accumulate if there are additional nested subgrids.
The above diagram shows a subgrid within a subgrid, and both are participating in the outermost grid’s column sizing only. The outermost grid also has a grid gap applied. Item 2 and Item 3 are nested subgrid items, in other words, grandchildren of the outermost grid.
Item 2 is aligned according to the outermost grid’s columns but its size is reduced by the margin, border and padding of its parent grid and grandparent grid. Item 3 does not have this issue because it is not at an edge.
Grid gaps set on the parent grid are inherited by the subgrid. However, it is possible to override this with a grid gap value that is local to the subgrid. This will also impact the sizing of the subgrid items.
In the above diagram, the parent grid has a gap
of 1.5em
, while the subgrid has a gap
of 2em
. Even though the subgrid items are still aligned to the parent grid, when compared to a grid item that spans the same column size, the subgrid item is 0.5em smaller.
Understanding subgrid item alignment behaviour
A subgrid will always be stretched in the subgridded dimension. This means any align-self
or justify-self
properties will be ignored. Any height or width constraints on the subgrid are also ignored.
The subgrid will always be aligned with the section of the parent grid that it spans. Any justify-content
or align-content
properties on it will be ignored in the subgridded dimension.
If the total width of subgrid items exceed the width of the subgrid container, and the overflow
value is set to scroll, additional items can be scrolled into view. But note that the act of scrolling will not impact the layout.
Examples
A rather common use-case that subgrid solves is making it easier for nested grid items to align to the outermost parent grid. Before subgrid, we could make our nested grids to match up to the parent grid but that required quite a bit of math to get the sizing just right. Subgrid solves this issue.
Let’s take look at this example of a list of speakers displayed in a card style layout.
Each speaker card has a title, image, description and 3 links. In order to get the 3 links to align with each other across speaker cards, we can make each speaker card a subgrid of the parent grid and allow each speaker link to participate in the outermost grid sizing.
If we size the grid tracks for the speaker links with a value of max-content
, all the speaker links for that track will take the size of the longest link across all the speakers, allowing the start of each link to align with each other.
Another example where subgrid comes in handy would be for a list of form fields, where we want the label to be inline with the input field. Let’s take a look at the following markup:
<form>
<ul>
<li>
<label for="name"></label>
<input id="name" name="name">
</li>
<li>
<label for="handle"></label>
<input id="handle" name="handle">
</li>
<li>
<label for="location"></label>
<input id="location" name="location">
</li>
<li>
<label for="website"></label>
<input id="website" name="website">
</li>
<li>
<label for="bio"></label>
<input id="bio" name="bio">
</li>
</ul>
</form>
Prior to subgrid, if we made the <ul>
element a grid container to layout each form field, the contents within the form field, i.e. the <label>
and the <input>
would not be able to participate in the parent grid’s track sizing.
With subgrid, aligning the labels and the input fields across every form field becomes a relatively trivial pursuit. The essential CSS for such a layout is as follows:
ul {
display: grid;
grid-template-columns: max-content auto;
gap: 1em;
}
li {
grid-column: 1 / -1;
display: grid;
grid-template-columns: subgrid;
}
View this demo on the Codrops Playground
Card-style layouts for lists of content is a fairly common design pattern on websites these days. It could be an e-commerce site with catalogues of items for sale or a news website showing a list of articles. Each item usually has multiple elements within the card, and subgrid lets us align these individual elements within the card with their corresponding elements across different cards.
For this particular example, each card item has 4 rows, which should take up just as much content as the card contains. We would then have to set the grid-row
property on the subgrid to span those 4 rows on the parent grid.
Because the size of the subgrid items will determine the size of the parent’s grid tracks, this allows us to have the different rows of content within our subgrid item to align with each other across cards.
View this demo on the Codrops PlaygroundBrowser Support
CSS Subgrid
Feature of the CSS Grid Layout Module Level 2 that allows a grid-item with its own grid to align in one or both dimensions with its parent grid.
W3C Candidate Recommendation
Supported from the following versions:
Desktop
- 117
- 71
- No
- 103
- 16
Mobile / Tablet
- 16
- 131
- No
- 131
- 132