Vóór CSS Grid betekende een goede paginalayout bouwen floats, clearfixes, negatieve marges en de hoop dat je kolommen niet instortten. Flexbox hielp, maar is fundamenteel eendimensionaal — je krijgt een rij of een kolom, niet beide. CSS Grid is het eerste native CSS-layoutsysteem dat echt ontworpen is voor tweedimensionale layouts. De uitdaging is niet browserondersteuning — die is universeel sinds 2017. De uitdaging is dat de API veel oppervlakte heeft en de naamgeving inconsistent genoeg is om verwarrend te zijn als je het onderliggende model niet helder hebt. Dit artikel richt zich op de delen die je in echt werk zult gebruiken.
Rijen, Kolommen en de Grid-container
Alles begint met display: grid op de container. Eenmaal ingesteld worden de directe kinderen automatisch grid-items — er is geen klasse op hen nodig. Je definieert de kolom- en rijtracks met grid-template-columns en grid-template-rows.
De sleuteleenheid die je eerst moet begrijpen is fr — de fractionele eenheid. Het vertegenwoordigt een breuk van de beschikbare ruimte in de grid-container nadat tracks met vaste grootte zijn meegerekend. Eén 1fr betekent "neem één aandeel van de resterende ruimte." Twee kolommen van 1fr 1fr betekent gelijke helften. 2fr 1fr betekent dat de eerste kolom twee keer zoveel krijgt als de tweede. Dit is de eenheid die vloeiende grids natuurlijk laat aanvoelen.
/* 3-column blog card layout */
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto;
gap: 1.5rem;
}
/* repeat(3, 1fr) is shorthand for: 1fr 1fr 1fr */
/* auto rows size to their content */repeat(n, track) is een afkorting zodat je niet vijf keer dezelfde trackgrootte hoeft te schrijven. Het werkt ook met gemengde waarden: repeat(3, 1fr 2fr) geeft je een 6-koloms grid met afwisselend smalle en brede tracks. Voor rijen is auto bijna altijd wat je wilt — rijen passen aan hun inhoud tenzij je expliciet een vaste hoogte nodig hebt.
<div class="card-grid">
<article class="card">
<img src="/posts/grid-post-1.jpg" alt="CSS Grid post 1">
<h2>Getting Started with Grid</h2>
<p>A practical intro for developers moving from Flexbox.</p>
</article>
<article class="card">
<img src="/posts/grid-post-2.jpg" alt="CSS Grid post 2">
<h2>Grid vs Flexbox</h2>
<p>Which layout tool to reach for, and when.</p>
</article>
<article class="card">
<img src="/posts/grid-post-3.jpg" alt="CSS Grid post 3">
<h2>Responsive Grids Without Media Queries</h2>
<p>Using minmax() to handle reflow automatically.</p>
</article>
</div>De gap-eigenschap
Vóór Grid betekende ruimte toevoegen tussen layout-kinderen marges — en marges betekenden onthouden om het laatste kind te resetten, omgaan met collapsing, en negatieve marges op de container toevoegen om te compenseren. gap lost dit netjes op. Het voegt ruimte toe tussen tracks alleen, nooit op de buitenste randen van het grid.
/* Uniform gap between all rows and columns */
.card-grid {
gap: 1.5rem;
}
/* Different row and column gaps */
.dashboard {
row-gap: 2rem;
column-gap: 1rem;
}
/* gap is shorthand: row-gap then column-gap */
.dashboard {
gap: 2rem 1rem;
}gap werkt ook in Flexbox (het verving de oude grid-gap-alias). Als je al Flexbox gebruikt voor een component en alleen ruimte tussen items nodig hebt, kun je daar ook gap gebruiken zonder naar Grid over te schakelen.Items Expliciet Plaatsen
Standaard stromen grid-items naar de volgende beschikbare cel in bronvolgorde. Maar de echte kracht van Grid is dat je items overal kunt plaatsen — en ze zelfs meerdere tracks kunt laten overspannen. De eigenschappen zijn grid-column en grid-row, die verwijzen naar gridlijnen (de lijnen tussen tracks, genummerd vanaf 1).
/* Dashboard where the first card spans 2 columns */
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
}
.card--featured {
grid-column: 1 / 3; /* start at line 1, end at line 3 */
}
/* span keyword: simpler when you don't care about exact position */
.card--featured {
grid-column: span 2; /* occupy 2 column tracks from wherever it lands */
}
/* Spanning rows too */
.card--tall {
grid-row: span 2; /* occupy 2 row tracks */
}
/* Explicit positioning: place a panel in column 3-5, row 1-2 */
.sidebar {
grid-column: 3 / 5;
grid-row: 1 / 2;
}Lijnnummers beginnen bij 1 voor de linker-/bovenrand en lopen op tot n+1 waar n het aantal tracks is. Negatieve lijnnummers tellen vanaf rechts/onder: grid-column: 1 / -1 strekt een item over de volledige breedte van het grid uit, ongeacht hoeveel kolommen er zijn — een handige truc voor volledig-brede elementen in een container met meerdere kolommen.
grid-template-areas — Geef Je Layout een Naam
Dit is de functie die Grid werkelijk geweldig maakt voor paginalay-outs, en het is de meest leesbare API in heel CSS. In plaats van items te plaatsen op lijnnummers, teken je de lay-out als ASCII-kunst in het CSS en vertelt dan elk item welk benoemde gebied het bezet. De grid-template-areas-specificatie vereist dat elke rij hetzelfde aantal cellen heeft, en elk benoemd gebied moet rechthoekig zijn — geen L-vormen.
/* Full page layout: header, sidebar, main, footer */
.page-shell {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: 60px 1fr 50px;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
gap: 0;
}
.page-header { grid-area: header; }
.page-sidebar { grid-area: sidebar; }
.page-main { grid-area: main; }
.page-footer { grid-area: footer; }<div class="page-shell">
<header class="page-header">Site header / nav</header>
<nav class="page-sidebar">Sidebar navigation</nav>
<main class="page-main">Primary content</main>
<footer class="page-footer">Footer</footer>
</div>Een punt (.) in de sjabloonstring laat een cel opzettelijk leeg. Je kunt ook dezelfde naam over meerdere cellen stapelen om ze te overspannen — dat is precies wat "header header" hierboven doet. Wanneer je de lay-out vergroot, verkleint of herstructureert voor verschillende viewports, update je de sjabloonstring op één plek in plaats van te zoeken over meerdere grid-column-declaraties.
auto-fill vs auto-fit met minmax()
Het patroon achter responsieve grids zonder media queries is een van Grid's meest praktische trucs: repeat(auto-fill, minmax(250px, 1fr)). Opgedeeld — minmax(250px, 1fr) zegt dat elke kolom minimaal 250px breed moet zijn maar kan uitbreiden om beschikbare ruimte te vullen. auto-fill vertelt Grid om zoveel mogelijk kolommen te maken in de container gegeven die beperking. Het resultaat is een grid dat automatisch kolommen wint en verliest naarmate de viewport verandert.
/* Product card grid — reflows automatically, no media queries */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 1.5rem;
}
/* auto-fit collapses empty tracks — items stretch to fill the container */
.product-grid--stretch {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 1.5rem;
}Het verschil tussen auto-fill en auto-fit is subtiel maar telt als er minder items zijn dan kolommen. Met auto-fill reserveert Grid ruimte voor de potentiële tracks, zelfs als ze leeg zijn — items blijven op hun minimumbreedte. Met auto-fit storten lege tracks in naar nul en breiden items zich uit om de rij te vullen. Voor productgrids en galerijen waar je wilt dat items beschikbare ruimte gebruiken, ziet auto-fit er meestal beter uit. Voor grids waar consistente itemsbreedte meer telt dan het vullen van de container, is auto-fill de juiste keuze.
auto-fill en auto-fit met minmax() hebben uitstekende ondersteuning — 97%+ wereldwijd volgens caniuse. Je kunt dit patroon vandaag gebruiken zonder een fallback in elk modern project.Uitlijning in Grid
Grid gebruikt dezelfde Box Alignment-module als Flexbox, dus de eigenschapsnamen komen direct overeen als je Flexbox al kent. Het sleutelmentale model: justify werkt op de inline-as (horizontaal in de meeste schrijfmodi), align werkt op de blokas (verticaal).
justify-items/align-items— standaarduitlijning voor alle items binnen hun gridcel. Standaard isstretch, waardoor grid-items hun cel automatisch vullen.justify-content/align-content— verdeelt de tracks zelf binnen de container wanneer het grid kleiner is dan de container (vergelijkbaar met Flexboxjustify-contentop de flex-container).justify-self/align-self— overschrijft uitlijning voor één item. Nuttig wanneer één item gecentreerd moet zijn terwijl anderen uitrekken.- Waarden:
start,end,center,stretch,space-between,space-around,space-evenly(laatste drie alleen voor*-content).
/* Center all card content within its cell */
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
align-items: start; /* cards align to their cell top, not stretched */
gap: 1.5rem;
}
/* Center a single call-to-action card both ways */
.card--cta {
justify-self: center;
align-self: center;
}
/* Distribute tracks with space between — useful for nav bars */
.nav-grid {
display: grid;
grid-template-columns: auto auto auto;
justify-content: space-between;
}Als je van Flexbox komt, is het belangrijkste verschil dat Grid-uitlijning werkt op een tweedimensionale ruimte — je kunt beide assen tegelijkertijd besturen. In Flexbox geldt de dwarsasuitlijning voor een hele rij of kolom van items; in Grid heeft elk item zijn eigen cel, zodat justify-self en align-self je per-item controle geven zonder wrapper-elementen nodig te hebben.
Echt Layout: Complete Dashboard Shell
Hier is een complete CSS Grid-paginastructuur voor een dashboard-applicatie — koptekst, inklapbare nav-zijbalk, hoofdinhoudsgebied met zijn eigen interne grid, en voettekst. Dit is het patroon dat je zou gebruiken als de buitenste layoutshell voor een SaaS-dashboard of beheerpaneel.
/* ── Dashboard shell ──────────────────────────────────── */
.dashboard-shell {
display: grid;
grid-template-columns: 220px 1fr;
grid-template-rows: 56px 1fr 44px;
grid-template-areas:
"topbar topbar"
"sidenav content"
"sidenav footer";
min-height: 100vh;
}
.dashboard-topbar { grid-area: topbar; background: #1e293b; }
.dashboard-sidenav { grid-area: sidenav; background: #0f172a; overflow-y: auto; }
.dashboard-content { grid-area: content; padding: 1.5rem; overflow-y: auto; }
.dashboard-footer { grid-area: footer; background: #f8fafc; border-top: 1px solid #e2e8f0; }
/* ── Collapsed sidebar variant ────────────────────────── */
.dashboard-shell--collapsed {
grid-template-columns: 56px 1fr;
}
/* ── Content area — internal card grid ─────────────────── */
.dashboard-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
grid-template-rows: auto;
align-content: start;
gap: 1.25rem;
}
/* Stat cards take one column each; the main chart spans all */
.stat-card { /* auto-placed, one column */ }
.main-chart { grid-column: 1 / -1; } /* always full width */
/* ── Responsive: collapse to single-column on small screens */
@media (max-width: 768px) {
.dashboard-shell {
grid-template-columns: 1fr;
grid-template-rows: 56px 1fr auto 44px;
grid-template-areas:
"topbar"
"content"
"sidenav"
"footer";
}
}<div class="dashboard-shell">
<header class="dashboard-topbar">
<a href="/dashboard" class="brand">AppName</a>
<nav class="topbar-actions">
<button class="btn-icon" aria-label="Notifications">
<span class="icon-bell"></span>
</button>
<img src="/avatar/user.png" class="user-avatar" alt="User menu">
</nav>
</header>
<nav class="dashboard-sidenav">
<ul>
<li><a href="/dashboard">Overview</a></li>
<li><a href="/dashboard/analytics">Analytics</a></li>
<li><a href="/dashboard/users">Users</a></li>
<li><a href="/dashboard/settings">Settings</a></li>
</ul>
</nav>
<main class="dashboard-content">
<div class="stat-card">Monthly Revenue</div>
<div class="stat-card">Active Users</div>
<div class="stat-card">Churn Rate</div>
<div class="main-chart">Revenue Chart (full width)</div>
</main>
<footer class="dashboard-footer">
<p>AppName v2.4.1 — <a href="/status">System Status</a></p>
</footer>
</div>Een paar dingen die het vermelden waard zijn in dit voorbeeld. De voettekst wordt op grote schermen in de sidenav-kolom geplaatst met behulp van de sjabloongebied-definitie, waardoor het visueel gescheiden blijft van het scrollende hoofdinhoudsgebied. De 1fr op rijen en overflow-y: auto op het inhoudsvenster betekent dat het inhoudsgebied onafhankelijk scrollt — de topbar en sidenav blijven op hun plaats, wat de standaard dashboard-UX is. De @media-query onderaan herordent de gebieden voor mobiel zonder de HTML aan te raken.
Samenvatting
De leercurve van CSS Grid komt voornamelijk van de naamgeving — lijnen, tracks, gebieden, fr-eenheden — maar zodra het model duidelijk wordt, is het opmerkelijk direct. Voor echte layouts: gebruik grid-template-areas voor paginashells (het leest als een wireframe), gebruik repeat(auto-fit, minmax()) voor responsieve kaartgrids, en gebruik expliciete grid-column: span N voor items die de standaardstroom doorbreken. Je hebt niet alle API van Grid nodig voor 90% van het echte werk — deze patronen dekken de meeste gevallen.
Voor verdere lectuur: de Complete Gids voor Grid van CSS-Tricks is de beste referentie op één pagina; de MDN CSS Grid-documentatie gaat diep op elke eigenschap; en de W3C CSS Grid Level 1-specificatie is verrassend leesbaar als je het exacte gedrag van randgevallen wilt begrijpen. Browsercompatibiliteit is uitstekend — controleer caniuse.com/css-grid voor actuele cijfers. Als je aan een live project werkt en je CSS wilt opschonen, maakt de CSS Formatter op deze site je stylesheets netter en mooier.