CSS Subgrid: How It Works and When to Use It
CSS Subgrid lets nested content share a parent grid’s tracks. Learn the syntax, see a runnable card layout, and decide when Subgrid fits your design.
CSS Subgrid lets a nested grid use its parent grid’s tracks in the dimension where you specify it. Set grid-template-columns: subgrid to share columns, grid-template-rows: subgrid to share rows, or both when both dimensions must align. The nested element still lays out its own children; Subgrid makes those children participate in the ancestor’s track system.
Use it when nested content needs to line up with tracks outside its immediate container—for example, when headings, descriptions, and actions should align across cards with different amounts of text. Use a regular nested grid when the child needs an independent track system or implicit tracks.
MDN describes Subgrid as widely available across browsers since September 2023. Check the browser versions in your own support policy before relying on it. MDN’s Subgrid guide has the current compatibility summary.
1. What Subgrid shares
A regular nested grid defines its own tracks. Its columns and rows are sized within the nested grid, so they do not automatically line up with the parent’s columns or rows. Subgrid changes that in one dimension: the nested grid uses the parent’s track definitions across the grid lines it spans.
grid-template-columns: subgridshares the parent’s columns.grid-template-rows: subgridshares the parent’s rows.- Using both shares tracks in both dimensions.
The CSS Grid Layout Module Level 2 specification summarizes the purpose: “Essentially, subgrids provide the ability to pass grid parameters down through nested elements, and content-based sizing information back up to their parent grid.” This means the relationship can affect sizing as well as alignment: when the parent’s track sizing method allows content to influence size, content in the subgrid can contribute to that sizing.
The subgrid inherits the relevant track sizing and gap from its parent. The gap can be overridden. Parent line names are available within the subgrid, and the subgrid can introduce its own line names. The child’s own elements still determine what goes into its grid areas.
2. A complete card example
This example places several cards in one outer grid. Every card spans three parent rows, and each card uses those rows as a subgrid. The title, description, and action therefore occupy corresponding tracks across cards, even when the description lengths differ.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Subgrid card layout</title>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
padding: 2rem;
font: 1rem/1.5 system-ui, sans-serif;
color: #172033;
background: #f3f5f8;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
grid-template-rows: auto auto auto;
gap: 1rem;
max-width: 70rem;
margin-inline: auto;
align-items: stretch;
}
.card {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid;
gap: 1rem;
padding: 1.25rem;
border: 1px solid #dce2eb;
border-radius: 0.75rem;
background: white;
}
.card h2, .card p { margin: 0; }
.card a {
justify-self: start;
align-self: end;
padding: 0.5rem 0.75rem;
border-radius: 0.35rem;
color: white;
background: #2458c6;
text-decoration: none;
}
</style>
</head>
<body>
<main class="cards">
<article class="card">
<h2>Fast setup</h2>
<p>Start with a small change to an existing grid and keep the same markup.</p>
<a href="#setup">Read the guide</a>
</article>
<article class="card">
<h2>Shared alignment</h2>
<p>A longer explanation can wrap onto several lines. Its card’s action still aligns with the actions in the other cards because each card participates in the same parent row tracks.</p>
<a href="#alignment">See how it works</a>
</article>
<article class="card">
<h2>Clear structure</h2>
<p>The card remains a grid container, so its own children can be arranged in the shared tracks.</p>
<a href="#structure">Explore the layout</a>
</article>
</main>
</body>
</html>
The key declarations are on .card: grid-row: span 3 makes the card cover three parent row tracks, and grid-template-rows: subgrid maps its children onto those tracks. The outer grid’s three row tracks correspond to the title, description, and action positions.
For this arrangement, the parent must have the row tracks that the cards span. If the number of child rows changes, update the span and the outer grid structure together. At narrower widths, the auto-fit column definition changes how many cards fit per row; track alignment is scoped to the parent grid placement and its rows, so check the layout at the widths and card arrangements your design uses.
3. Share columns, rows, or both
Share columns
Use column Subgrid when nested elements need to follow the parent’s column boundaries. This is useful for a nested page section whose text and sidebar should follow the page-level columns.
.page {
display: grid;
grid-template-columns: 12rem 1fr 16rem;
gap: 1.5rem;
}
.section {
grid-column: 2 / 4;
display: grid;
grid-template-columns: subgrid;
}
.section-main { grid-column: 1; }
.section-aside { grid-column: 2; }
The section spans the parent’s second and third columns. Within that span, its own children use the shared tracks, so the section’s local column 1 and 2 correspond to the parent columns it covers.
Share rows
Use row Subgrid when nested content needs to align vertically with parent tracks, as in the card example. The parent’s row sizing rules still matter. With content-sensitive sizing such as auto-sized rows, content in the subgrid may contribute to the parent’s track sizing.
Share both dimensions
A nested component can use Subgrid in both dimensions when it needs to align its children to parent columns and rows:
.nested {
display: grid;
grid-column: 2 / 4;
grid-row: 2 / 5;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
}
Choose each dimension independently. Sharing columns does not require sharing rows, and vice versa. Only opt into the dimension whose parent tracks the component needs.
4. Decide whether Subgrid fits
| Question | Subgrid is a fit when… | Prefer a regular nested grid when… |
|---|---|---|
| Must child items align to ancestor tracks? | Yes; that shared alignment is the goal. | No; the component can size itself independently. |
| Which dimension needs alignment? | One or both parent dimensions need to be shared. | Neither parent dimension is relevant to the child layout. |
| Should child content affect parent sizing? | The parent’s sizing method should account for content in the subgrid. | The child should be sized independently of parent content sizing. |
| Are inherited gaps or parent line names useful? | They help keep nested spacing and placement consistent. | The child needs separate gaps and track naming. |
| Does the child need implicit tracks? | No; its items fit the shared tracks. | Yes; use a regular grid and set grid-auto-rows or other implicit track sizing as needed. |
Subgrid is most useful when the alignment requirement crosses a component boundary. If the nested grid has its own unrelated columns, or the content requires a flexible number of implicit rows, an independent nested grid is usually simpler.
5. Gaps, line names, and sizing details
Gaps
A subgrid inherits the parent gap for its shared axis. You can override the gap on the subgrid when the nested component needs different spacing. Consider whether changing it still produces the alignment and rhythm you want at the parent level.
.parent {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
.child {
display: grid;
grid-column: span 2;
grid-template-columns: subgrid;
column-gap: 0.75rem;
}
Line names
Named lines from the parent can be used in the subgrid. The subgrid can add names of its own, which helps components express local placement while retaining the parent’s shared boundaries. If placement is confusing, inspect the parent’s named lines and the exact span occupied by the nested grid.
Content-based sizing
Subgrid lets content-based sizing information flow toward the parent when its track sizing allows content to affect size. This can be useful when a shared row must accommodate the tallest card heading or description. It also means long, unbroken content can influence the overall layout; test realistic content lengths and add appropriate overflow and wrapping rules.
6. Browser support and progressive enhancement
MDN marks Subgrid as Baseline and widely available, with availability across browsers since September 2023. The label is a broad summary, not a substitute for your project’s browser matrix. Verify versions that matter to your users in MDN’s browser compatibility data.
If older browsers are in scope, provide a useful independent-grid fallback first, then override it in a feature query:
.card {
display: grid;
grid-template-rows: auto 1fr auto;
gap: 1rem;
}
@supports (grid-template-rows: subgrid) {
.card {
grid-template-rows: subgrid;
}
}
The fallback remains a regular grid. It can preserve a reasonable card layout, though it does not provide the same cross-card shared row sizing. Pick fallback tracks that preserve readable content and usable actions.
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Children do not line up with parent tracks | The nested element is not a grid container, does not span the intended parent tracks, or Subgrid is set on the wrong axis. | Set display: grid, place the subgrid across the correct parent lines, and use grid-template-columns or grid-template-rows for the axis that needs sharing. |
| Only part of the component aligns | The child spans fewer parent tracks than its content needs, or the shared axis does not match the desired alignment. | Check its grid placement and span. Share the other dimension only if that dimension also needs parent tracks. |
| Rows appear unexpectedly tall | Content in a subgrid is participating in the parent’s content-based track sizing. | Check the parent row sizing and inspect long content. If independent sizing is desired, use a regular nested grid. |
| Some items fall outside the expected row structure | The layout needs additional implicit tracks, which the chosen subgrid structure does not provide as an independent track system. | Use a regular nested grid for that axis and control implicit sizing with grid-auto-rows. |
| Spacing differs from the design | The subgrid inherits the parent gap, or a local override has changed the shared-axis spacing. | Inspect the parent gap and the subgrid’s gap, row-gap, and column-gap values. |
| A fallback browser ignores the intended alignment | That browser version does not support Subgrid. | Check the project’s supported versions and retain a useful regular-grid fallback, optionally enhanced with @supports. |
| Text pushes cards out of shape | Long words, URLs, or unusually long content affect track sizing or overflow. | Test real content; use suitable wrapping such as overflow-wrap: anywhere where appropriate, and define overflow behavior for constrained regions. |
8. Inspect a Subgrid layout with a screenshot
A screenshot can help review whether card headings and actions line up at a particular viewport. It shows the rendered result; it does not replace checking the DOM, computed grid tracks, or browser support. For a local HTML file, serve it from a local development server and capture the resulting page URL.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com/subgrid-demo \
-o subgrid.webp
Replace the example URL with a page you control. The response is an image when capture succeeds; use the image extension that matches the requested output format. See the ScreenshotNeo API documentation for request options, authentication, formats, and response details. ScreenshotNeo is a website screenshot API and MCP server from ScreenshotNeo.
Python
import requests
response = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={
"access_key": "YOUR_API_KEY",
"url": "https://example.com/subgrid-demo",
},
timeout=90,
)
response.raise_for_status()
with open("subgrid.webp", "wb") as image_file:
image_file.write(response.content)
Node.js
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com/subgrid-demo'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('subgrid.webp', bytes));
9. Or skip the browser setup
Use ScreenshotNeo to capture a page with one request. Replace the target URL with your rendered Subgrid demo. See the API docs for the available parameters.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed; response headers identify the page verdict and billing result. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Sign up for ScreenshotNeo’s free plan.
10. Performance, reliability, and cost
Subgrid is a CSS layout feature; the cited documentation and specification provide no benchmark or numerical performance claim. Keep the grid structure understandable, avoid adding nesting without a layout reason, and profile your actual page if rendering performance is a concern. For visual review, capture representative content and viewport sizes rather than inferring behavior from a single screenshot.
For screenshot requests, allow enough time for the page to load and its layout to settle, especially when fonts, images, or client-side content affect track sizing. A captured image is a snapshot, so it will not reveal every responsive state or prove that the layout works in all browsers. ScreenshotNeo reports page verdict and billing status in response headers; use those when distinguishing a successful clean capture from other outcomes.
ScreenshotNeo plans include 1,000 monthly shots free without a card, then Starter is $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000. Yearly billing gives two months free. Every feature is included on every plan. Only clean shots are billed; cache hits and unsuccessful or blank outcomes cost nothing.
11. Frequently asked questions
Does Subgrid create another grid?
The nested element remains a grid container for its children, but on the axis set to subgrid, it uses the parent’s tracks rather than defining an independent set of tracks.
Can I use Subgrid for columns but not rows?
Yes. Set only grid-template-columns: subgrid. The other axis can use its own track definition or normal grid behavior.
Can I name lines inside a subgrid?
Yes. Parent line names can be passed into the subgrid, and the subgrid can add its own line names for local placement.
Should every nested grid use Subgrid?
No. Use it when alignment to ancestor tracks is part of the requirement. An independent nested grid is a better fit when its tracks or implicit sizing belong to the component itself.


