Innan CSS Grid innebar att bygga en ordentlig sidlayout floats, clearfixes, negativa marginaler och en bön om att kolumnerna inte skulle kollapsa. Flexbox hjälpte, men det är fundamentalt endimensionellt — du får en rad eller en kolumn, inte båda. CSS Grid är det första layoutsystemet som är inbyggt i CSS och faktiskt är utformat för tvådimensionella layouter. Utmaningen är inte webbläsarstöd — det har varit universellt sedan 2017. Utmaningen är att API:et har ett stort ytområde och namngivningen är tillräckligt inkonsekvent för att vara förvirrande om du inte har den underliggande modellen klar. Den här artikeln fokuserar på de delar du använder i verkligt arbete.

Rader, kolumner och rutnätsbehållaren

Allt börjar med display: grid på behållaren. När det är inställt blir direkta barn automatiskt rutnätsobjekt — ingen klass behövs på dem. Du definierar kolumn- och radspår med grid-template-columns och grid-template-rows.

Nyckelenheten att förstå först är fr — bråkenheten. Den representerar en bråkdel av det tillgängliga utrymmet i rutnätsbehållaren efter att spår med fast storlek har beaktats. En 1fr betyder "ta en andel av det utrymme som är kvar." Två kolumner av 1fr 1fr innebär lika hälfter. 2fr 1fr innebär att den första kolumnen får dubbelt så mycket som den andra. Det är den enheten som gör flytande rutnät naturliga.

css
/* 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) är en kortform så att du inte behöver skriva samma spårstorlek fem gånger. Det fungerar också med blandade värden: repeat(3, 1fr 2fr) ger dig ett 6-kolumners rutnät med omväxlande smala och breda spår. För rader är auto nästan alltid vad du vill ha — rader anpassar sin storlek till sitt innehåll om du inte uttryckligen behöver en fast höjd.

html
<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>

gap-egenskapen

Innan Grid innebar att lägga till mellanrum mellan layoutbarn marginaler — och marginaler innebar att komma ihåg att återställa det sista barnet, hantera kollaps och lägga till negativa marginaler på behållaren för att kompensera. gap löser detta rent. Det lägger till utrymme enbart mellan spår, aldrig på de yttre kanterna av rutnätet.

css
/* 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;
}
Obs: gap fungerar också i Flexbox (det ersatte det gamla grid-gap-aliaset). Om du redan använder Flexbox för en komponent och bara behöver mellanrum mellan objekt, kan du använda gap där också utan att byta till Grid.

Placera objekt explicit

Som standard flödar rutnätsobjekt in i nästa tillgängliga cell i källordning. Men Grids verkliga kraft är att du kan placera objekt var som helst — och till och med få dem att sträcka sig över flera spår. Egenskaperna är grid-column och grid-row, som refererar till rutnätslinjer (linjerna mellan spår, numrerade från 1).

css
/* Dashboard där det första kortet sträcker sig över 2 kolumner */
.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;
}

Linjenummer börjar på 1 för vänster/överkant och går upp till n+1 där n är antalet spår. Negativa linjenummer räknas från höger/underkant: grid-column: 1 / -1 sträcker ett objekt över hela bredden på rutnätet oavsett hur många kolumner det finns — ett användbart trick för helbreddselement inuti en flerkolumnsbehållare.

grid-template-areas — namnge din layout

Det här är funktionen som gör Grid genuint bra för sidnivålayouter, och det är det mest läsbara API:et i hela CSS. Istället för att placera objekt med linjenummer ritar du layouten som ASCII-konst i CSS, och berättar sedan för varje objekt vilket namngivet område det upptar. grid-template-areas-specifikationen kräver att varje rad har samma antal celler, och varje namngivet område måste vara rektangulärt — inga L-former.

css
/* 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; }
html
<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>

En punkt (.) i mallträngen lämnar en cell avsiktligt tom. Du kan också stapla samma namn över flera celler för att sträcka dem — det är exakt vad "header header" gör ovan. När du ändrar storlek eller omstrukturerar layouten för olika visningspunkter uppdaterar du mallträngen på ett ställe istället för att jaga över flera grid-column-deklarationer.

auto-fill vs auto-fit med minmax()

Mönstret bakom responsiva rutnät utan mediafrågor är ett av Grids mest praktiska trick: repeat(auto-fill, minmax(250px, 1fr)). Dela upp det — minmax(250px, 1fr) säger att varje kolumn ska vara minst 250px bred men expandera för att fylla tillgängligt utrymme. auto-fill berättar för Grid att skapa så många kolumner som får plats i behållaren givet den begränsningen. Resultatet är ett rutnät som automatiskt får och tappar kolumner när visningsporten ändras.

css
/* 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;
}

Skillnaden mellan auto-fill och auto-fit är subtil men spelar roll när det finns färre objekt än kolumner. Med auto-fill reserverar Grid utrymme för de potentiella spåren även om de är tomma — objekt stannar vid sin minimumbredd. Med auto-fit kollapsas tomma spår till noll och objekten expanderar för att fylla raden. För produktrutnät och gallerier där du vill att objekt ska använda tillgängligt utrymme ser auto-fit vanligtvis bättre ut. För rutnät där konsekvent objektbredd spelar mer roll är auto-fill rätt val.

Webbläsarstödsanteckning: auto-fill och auto-fit med minmax() har utmärkt stöd — 97%+ globalt enligt caniuse. Du kan använda det här mönstret idag utan en fallback i vilket modernt projekt som helst.

Justering i Grid

Grid använder samma Box Alignment-modul som Flexbox, så egenskapsnamnen mappar direkt om du redan känner till Flexbox. Den mentala nyckelmodellen: justify verkar på inline-axeln (horisontell i de flesta skrivlägen), align verkar på blockaxeln (vertikal).

  • justify-items / align-items — standardjustering för alla objekt inom sin rutnätscell. Standard är stretch, vilket är anledningen till att rutnätsobjekt automatiskt fyller sin cell.
  • justify-content / align-content — distribuerar spåren själva inom behållaren när rutnätet är mindre än behållaren (liknande Flexbox justify-content på flex-behållaren).
  • justify-self / align-self — åsidosätter justering för ett enda objekt. Användbart när ett objekt behöver centreras medan andra sträcks.
  • Värden: start, end, center, stretch, space-between, space-around, space-evenly (de tre sista för enbart *-content).
css
/* 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;
}

Om du kommer från Flexbox är den viktigaste skillnaden att Grid-justering fungerar i ett tvådimensionellt utrymme — du kan kontrollera båda axlarna samtidigt. I Flexbox gäller korsaxeljusteringen en hel rad eller kolumn med objekt; i Grid har varje objekt sin egen cell, så justify-self och align-self ger dig per-objektkontroll utan att behöva omslagselement.

Verklig layout: komplett instrumentpanelsskal

Här är en komplett CSS Grid-sidstruktur för en instrumentpanelsapplikation — sidhuvud, hopfällbar nav-sidofält, huvudinnehållsområde med ett eget internt rutnät och sidfot. Det här är mönstret du skulle använda som det yttersta layoutskalet för en SaaS-instrumentpanel eller adminpanel.

css
/* ── 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";
  }
}
html
<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 &mdash; <a href="/status">System Status</a></p>
  </footer>
</div>

Några saker värda att notera i det här exemplet. Sidfoten placeras i sidenav-kolumnen på stora skärmar med hjälp av mallområdesdefinitionen, vilket håller den visuellt separerad från det rullande huvudinnehållsområdet. 1fr på rader och overflow-y: auto på innehållspanelen betyder att innehållsområdet rullar oberoende — toppfältet och sidnavigationen stannar på plats, vilket är standard instrumentpanels-UX. @media-frågan längst ned omordnar rutnätsområdena för mobilt utan att röra HTML alls.

Sammanfattning

CSS Grids inlärningskurva kommer mest från namngivningen — linjer, spår, områden, fr-enheter — men när modellen klickar är det remarkabelt direkt. För verkliga layouter: använd grid-template-areas för sidskal (det läses som en trådram), använd repeat(auto-fit, minmax()) för responsiva kortnät, och använd explicit grid-column: span N för objekt som bryter det normala flödet. Du behöver inte hela Grids API för 90% av verkligt arbete — dessa mönster täcker det mesta.

För vidare läsning: CSS-Tricks komplett guide till Grid är den bästa ensidiga referensen; MDN:s CSS Grid-dokumentation går djupt in på varje egenskap; och W3C CSS Grid Level 1-specifikationen är förvånansvärt läsbar om du vill förstå det exakta beteendet hos kantfall. Webbläsarkompatibiliteten är utmärkt — kolla caniuse.com/css-grid för aktuella siffror. Om du arbetar med ett levande projekt och vill städa upp din CSS, kommer CSS-formateraren på den här webbplatsen att snygga till och prettifiera dina formatmallar.