Zum Inhalt springen

Moderne CSS-Layout-Patterns, die jeder Entwickler kennen sollte

Praktische CSS-Layout-Patterns mit Grid, Flexbox, Container Queries und logischen Eigenschaften — responsives Design ohne JavaScript.

4 Min. Lesezeit
Visuelle Übersicht über CSS-Layout-Patterns, darunter Holy Grail, Sidebar, Masonry und responsive Card-Grids

CSS-Layout hat sich radikal verändert. Muster, für die früher JavaScript-Bibliotheken, Float-Tricks oder tief verschachtelte Divs nötig waren, lassen sich heute mit wenigen Grid- oder Flexbox-Eigenschaften umsetzen. Trotzdem greifen viele Entwickler weiterhin zu komplexen Lösungen, obwohl es einfachere, wartbarere CSS-Ansätze gibt. Diese Muster lösen genau die Layouts, die du jede Woche baust.

Das responsive Sidebar-Layout

Eine Sidebar, die auf schmalen Bildschirmen ohne Media Queries zusammenklappt. Die Funktionen minmax und auto-fit von CSS Grid übernehmen das responsive Verhalten von Haus aus.

csscss
/* ❌ Fixed sidebar with media query breakpoint */
.layout {
  display: flex;
}
.sidebar {
  width: 300px;
  flex-shrink: 0;
}
.main {
  flex: 1;
}
@media (max-width: 768px) {
  .layout {
    flex-direction: column;
  }
  .sidebar {
    width: 100%;
  }
}
/* Problem: arbitrary breakpoint, doesn't respond to container */
csscss
/* ✅ Intrinsic responsive sidebar */
.layout {
  display: grid;
  grid-template-columns: fit-content(300px) minmax(50%, 1fr);
  gap: 1.5rem;
}
/* Sidebar takes content width up to 300px
   Main content gets at least 50% of the container
   When 50% < remaining space, columns stack naturally */
 
/* Even better with container queries */
.layout {
  container-type: inline-size;
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
}
 
@container (min-inline-size: 700px) {
  .layout {
    grid-template-columns: fit-content(300px) 1fr;
  }
}

Die Variante mit Container Queries reagiert auf die eigene Breite der Komponente statt auf das Viewport und ist dadurch unabhängig vom Einsatzort wirklich wiederverwendbar.

Das automatisch füllende Card-Grid

Ein Card-Grid, das die Spaltenanzahl automatisch an den verfügbaren Platz anpasst. Ganz ohne Media Queries, ganz ohne JavaScript.

csscss
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
  gap: 1.5rem;
}
/* auto-fill creates as many 280px+ columns as fit
   min(280px, 100%) prevents overflow on narrow containers
   Cards stretch equally to fill remaining space */
tstypescript
// The HTML is dead simple
function CardGrid({ items }: { items: CardItem[] }) {
  return (
    <div className="card-grid">
      {items.map(item => (
        <Card key={item.id} {...item} />
      ))}
    </div>
  );
}
 
// Compare to the JavaScript approach:
// ❌ const columns = Math.floor(containerWidth / 280);
// ❌ style={{ gridTemplateColumns: `repeat(${columns}, 1fr)` }}
// Requires ResizeObserver, re-renders on resize, SSR mismatch

Die Funktion min() ist dabei die entscheidende Neuerung. Ohne sie würde eine einzelne Karte auf einem schmalen Bildschirm versuchen, 280px breit zu sein, und dabei überlaufen. min(280px, 100%) sorgt dafür, dass Karten nie breiter als ihr Container werden.

Das Holy-Grail-Layout

Header, Footer, Sidebar und Hauptinhaltsbereich – responsiv, wobei der Hauptinhalt den verbleibenden vertikalen Platz einnimmt.

csscss
.page {
  min-height: 100dvh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  grid-template-columns: 1fr;
}
 
.header {
  grid-column: 1 / -1;
}
 
.body {
  display: grid;
  grid-template-columns: minmax(200px, 1fr) minmax(0, 3fr);
  gap: 1.5rem;
  padding: 1.5rem;
}
 
.footer {
  grid-column: 1 / -1;
}
 
/* Stack on narrow screens using container query */
.body {
  container-type: inline-size;
}
 
@container (max-inline-size: 600px) {
  .body {
    grid-template-columns: 1fr;
  }
}
csscss
/* The sticky sidebar bonus */
.sidebar {
  position: sticky;
  top: 1rem;
  align-self: start;
  max-height: calc(100dvh - 2rem);
  overflow-y: auto;
}
/* Sidebar scrolls independently and stays visible
   while main content scrolls normally */

100dvh statt 100vh zu verwenden berücksichtigt die Oberfläche mobiler Browser, die die Höhe des Viewports verändert.

Zentrierter Inhalt mit ausbrechenden Elementen

Blog-artiger Inhalt mit einer gut lesbaren maximalen Breite, bei dem einzelne Elemente (Bilder, Codeblöcke) auf die volle Breite ausbrechen.

csscss
.content {
  --content-width: 65ch;
  --breakout-width: 85ch;
  --full-width: 100%;
 
  display: grid;
  grid-template-columns:
    [full-start]
      minmax(1rem, 1fr)
      [breakout-start]
        minmax(0, calc((var(--breakout-width) - var(--content-width)) / 2))
        [content-start]
          min(var(--content-width), 100% - 2rem)
        [content-end]
        minmax(0, calc((var(--breakout-width) - var(--content-width)) / 2))
      [breakout-end]
      minmax(1rem, 1fr)
    [full-end];
}
 
.content > * {
  grid-column: content;
}
 
.content > .breakout {
  grid-column: breakout;
}
 
.content > .full-width {
  grid-column: full;
}
htmlhtml
<article class="content">
  <h2>Article Title</h2>
  <p>Regular paragraph content stays within the readable width.</p>
 
  <!-- This image breaks out wider -->
  <img class="breakout" src="diagram.webp" alt="Architecture diagram" />
 
  <p>More regular content.</p>
 
  <!-- This spans the full viewport width -->
  <pre class="full-width"><code>// Full-width code block</code></pre>
</article>

Dieses Muster macht negative Margins oder absolute Positionierung überflüssig, um Elemente aus einem zentrierten Container ausbrechen zu lassen.

Der flexible Stack mit logischen Eigenschaften

Ein vertikaler Stack, der sich dank logischer Eigenschaften automatisch sowohl an LTR- als auch an RTL-Layouts anpasst.

csscss
/* ❌ Physical properties break in RTL */
.stack > * + * {
  margin-top: 1rem;
}
.card {
  padding-left: 1.5rem;
  border-left: 3px solid var(--accent);
  text-align: left;
}
 
/* ✅ Logical properties work in any writing mode */
.stack > * + * {
  margin-block-start: 1rem;
}
.card {
  padding-inline-start: 1.5rem;
  border-inline-start: 3px solid var(--accent);
  text-align: start;
}
csscss
/* A complete token-based spacing system with logical properties */
.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  align-items: center;
}
 
.sidebar-layout {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-m);
}
 
.sidebar-layout > :first-child {
  flex-basis: 20rem;
  flex-grow: 1;
}
 
.sidebar-layout > :last-child {
  flex-basis: 0;
  flex-grow: 999;
  min-inline-size: 50%;
}
/* Sidebar wraps below main content when space is tight
   No media queries — responds to available space */

Komponenten mit Container Queries

Container Queries lassen Komponenten sich an die Größe ihres Containers anpassen statt an das Viewport. Das macht Komponenten wirklich portabel.

csscss
.product-card {
  container-type: inline-size;
  container-name: product;
}
 
.product-card__layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}
 
/* Horizontal layout when card is wide enough */
@container product (min-inline-size: 400px) {
  .product-card__layout {
    grid-template-columns: 150px 1fr;
  }
 
  .product-card__image {
    aspect-ratio: 1;
    object-fit: cover;
  }
}
 
/* Full featured layout in wide containers */
@container product (min-inline-size: 600px) {
  .product-card__layout {
    grid-template-columns: 200px 1fr auto;
  }
 
  .product-card__actions {
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
}
tstypescript
// Same component works in any width context
function ProductPage() {
  return (
    <main>
      {/* Card adapts to narrow sidebar */}
      <aside style={{ width: "300px" }}>
        <ProductCard product={featured} />
      </aside>
 
      {/* Same card adapts to wide main area */}
      <section>
        <ProductCard product={featured} />
      </section>
 
      {/* Same card adapts to full-width hero */}
      <div style={{ width: "100%" }}>
        <ProductCard product={featured} />
      </div>
    </main>
  );
}

Die wichtigsten Erkenntnisse

Modernes CSS ist leistungsfähig genug, um responsives Verhalten von Haus aus zu übernehmen – ganz ohne Media Queries, JavaScript-Messungen oder Framework-Hilfsmittel. Nutze Grids auto-fill zusammen mit minmax für Card-Grids, die sich selbst anpassen. Nutze Container Queries für Komponenten, die auf ihren Kontext statt auf das Viewport reagieren. Setze logische Eigenschaften (block-start, inline-end) ein, damit Layouts in jeder Schreibrichtung korrekt funktionieren. Die besten CSS-Muster sind deklarativ: Du beschreibst, was du willst, nicht wie es berechnet wird. Überlass dem Browser die Rechenarbeit. Schreibe weniger, warte weniger und liefere standardmäßig Layouts, die auf jeder Bildschirmgröße und in jedem Schriftsystem funktionieren.

Wilfredo Rujel

Wilfredo Rujel

Full-Stack-Softwareentwickler

Diesen Beitrag teilenX