Skip to content

CSS Spickzettel

Stylesheet-Sprache zum Beschreiben der Präsentation von Webseiten.

01

Selektoren

Basis-Selektoren

CSS-Selektoren targeten HTML-Elemente zum Stylen. Typ-Selektoren matchen Element-Namen (p, div). Klassen-Selektoren (.) matchen class-Attribute und können wiederverwendet werden. ID-Selektoren (#) matchen ein einzelnes Element und sollten eindeutig sein. Der Universal-Selektor (*) matcht alles. Selektoren mit Kommas gruppieren, um Styles zu teilen.

css
/* Type selector - all <p> elements */
p { color: #333; }

/* Class selector - elements with class="btn" */
.btn { padding: 8px 16px; }

/* ID selector - element with id="header" */
#header { background: #fff; }

/* Universal selector - all elements */
* { box-sizing: border-box; }

/* Grouping selector */
h1, h2, h3 { font-family: Arial, sans-serif; }

Kombinatoren

Kombinatoren definieren Beziehungen zwischen Elementen. Descendant (Leerzeichen) matcht jedes verschachtelte Element. Child (>) matcht nur direkte Children. Adjacent sibling (+) matcht das Element unmittelbar danach. General sibling (~) matcht alle Siblings danach. Kombinatoren zu verstehen ist essenziell für präzises Stylen ohne extra Klassen.

css
/* Descendant - any <a> inside .nav */
.nav a { text-decoration: none; }

/* Child - direct <li> children of <ul> */
ul > li { list-style: none; }

/* Adjacent sibling - <p> right after <h1> */
h1 + p { font-size: 1.2em; }

/* General sibling - all <p> after <h1> */
h1 ~ p { color: gray; }

Attribut-Selektoren

Attribut-Selektoren matchen Elemente basierend auf Attribut-Werten. [attr] matcht Presence. [attr=val] matcht exakten Wert. ^= matcht Präfix, $= matcht Suffix, *= matcht Substring. Diese sind mächtig zum Stylen von Form-Inputs, Links nach Typ oder Elementen mit data-Attributen ohne extra Klassen hinzuzufügen.

css
/* Elements with type attribute */
[type] { border: 1px solid #ccc; }

/* Exact match */
[type="text"] { padding: 4px; }

/* Starts with */
a[href^="https"] { color: green; }

/* Ends with */
a[href$=".pdf"] { color: red; }

/* Contains */
a[href*="example"] { font-weight: bold; }

Pseudo-Klassen

Pseudo-Klassen selektieren Elemente basierend auf Zustand oder Position. Interaktiv: :hover, :focus, :active, :visited, :disabled. Strukturell: :first-child, :last-child, :nth-child(n), :nth-of-type(n). :not() negiert einen Selektor. :nth-child(odd/even) erstellt Zebra-Streifen. :nth-child(3n) selektiert jedes 3. Element. Diese reduzieren die Notwendigkeit für extra Klassen.

css
/* Interactive states */
a:hover { color: red; }
a:visited { color: purple; }
input:focus { border-color: blue; }
input:disabled { background: #eee; }
button:active { transform: scale(0.98); }

/* Structural */
li:first-child { font-weight: bold; }
li:last-child { border: none; }
li:nth-child(odd) { background: #f9f9f9; }
li:nth-child(3n) { color: blue; }
p:not(.highlight) { color: #333; }

Pseudo-Elemente

Pseudo-Elemente (::doppelter-Doppelpunkt) stylen spezifische Teile von Elementen. ::before und ::after fügen generierten Content ein (erfordert content-Eigenschaft). ::first-letter und ::first-line stylen Text-Teile. ::selection stylt hervorgehobenen Text. ::placeholder stylt Input-Placeholders. Hinweis: ::before/::after sind standardmäßig inline — display:block für Block-Verhalten setzen.

css
/* First line of a paragraph */
p::first-line { font-weight: bold; }

/* First letter (drop cap) */
p::first-letter { font-size: 3em; float: left; }

/* Insert content before/after */
.quote::before { content: "\201C"; }
.quote::after { content: "\201D"; }

/* Selection styling */
::selection { background: yellow; color: black; }

/* Placeholder styling */
input::placeholder { color: #999; }

Spezifität & !important

Spezifität bestimmt, welche Regel gilt, wenn Selektoren konfliktieren. Inline-Styles > IDs > Klassen > Typen. Bei Spezifitäts-Gleichstand gewinnt die letzte Regel. !important überschreibt alles, bricht aber die Cascade — vermeiden. DevTools verwenden, um Spezifität zu inspizieren. Klassen-basierte Selektoren für Wartbarkeit bevorzugen. Spezifität durch Wiederholen von Klassen (.btn.btn) zu erhöhen ist ein Hack — vermeiden.

css
/* Specificity hierarchy (low to high):
   1. Type selectors (p, div)         = 0,0,0,1
   2. Class selectors (.btn)          = 0,0,1,0
   3. ID selectors (#header)          = 0,1,0,0
   4. Inline styles (style="...")     = 1,0,0,0
   5. !important                      = overrides all
*/

/* ID beats class */
#nav .link { color: red; }   /* wins */
.nav .link { color: blue; }

/* Avoid !important unless necessary */
.critical { color: red !important; }
02

Box-Modell

Margin & Padding

Jedes Element ist eine Box mit Content, Padding, Border und Margin. Padding ist innerhalb der Border (beeinflusst Background), Margin ist außerhalb (transparent). Shorthand: 1 Wert = alle Seiten, 2 Werte = top/bottom left/right, 3 = top left/right bottom, 4 = top right bottom left (im Uhrzeigersinn). margin: 0 auto zentriert Block-Elemente mit definierter Breite.

css
.box {
  /* TRBL: top right bottom left */
  margin: 10px 20px 10px 20px;

  /* Shorthand: top/bottom  left/right */
  margin: 10px 20px;

  /* All sides */
  padding: 15px;

  /* Individual sides */
  margin-top: 0;
  padding-left: 24px;

  /* Center horizontally (block) */
  margin: 0 auto;
}

Border & Outline

border fügt eine Linie um Padding hinzu und beeinflusst Layout. outline zeichnet außerhalb der Border ohne Layout-Beeinflussung — nützlich für Focus-Indikatoren. border-radius rundet Ecken (einzelner Wert oder pro-Ecke: top-left top-right bottom-right bottom-left). outline-offset fügt Space zwischen Border und Outline hinzu. Immer sichtbare Focus-Styles für Accessibility bereitstellen.

css
.box {
  /* Shorthand: width style color */
  border: 2px solid #333;

  /* Individual sides */
  border-bottom: 3px dashed red;
  border-radius: 8px;

  /* Outline (doesn't affect layout) */
  outline: 2px solid blue;
  outline-offset: 4px;
}

/* Remove default focus, add custom */
button:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(0,123,255,0.5);
}

Box-Sizing

box-sizing: content-box (Default) bedeutet width/height gelten nur für Content — Padding und Border addieren sich zur Gesamtgröße. box-sizing: border-box inkludiert Padding und Border in width/height und macht Sizing vorhersehbar. Immer border-box global setzen für konsistente Layouts. Dies ist eines der wichtigsten CSS-Resets.

css
/* Default: width = content only */
.content-box {
  box-sizing: content-box;
  width: 200px;
  padding: 20px;
  border: 5px solid;
  /* Total width: 200 + 40 + 10 = 250px */
}

/* Recommended: width includes padding+border */
.border-box {
  box-sizing: border-box;
  width: 200px;
  padding: 20px;
  border: 5px solid;
  /* Total width: 200px */
}

/* Apply globally */
*, *::before, *::after {
  box-sizing: border-box;
}

Box-Shadow

box-shadow fügt Schatten-Effekte hinzu: offset-x offset-y blur-radius spread-radius color. Positive Offsets bewegen Schatten rechts/runter. inset erstellt einen inneren Schatten. Mehrere Schatten werden geschichtet (erste = oben). rgba für semi-transparente Schatten verwenden, die natürlich blenden. Schatten sind großartig für Depth, aber übermäßige Verwendung verletzt Performance — subtile Schatten bevorzugen.

css
/* offset-x offset-y blur spread color */
.card {
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

/* Multiple shadows */
.button {
  box-shadow:
    0 1px 2px rgba(0,0,0,0.1),
    0 4px 8px rgba(0,0,0,0.05);
}

/* Inset shadow */
.input:focus {
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
}

/* No shadow */
.no-shadow { box-shadow: none; }

Display & Visibility

display: none entfernt das Element komplett aus dem Layout (kein Space). visibility: hidden versteckt es, behält aber seinen Space. opacity: 0 macht es transparent, aber noch interaktiv. Block-Elemente nehmen volle Breite und brechen Zeilen. Inline-Elemente fließen mit Text. inline-block kombiniert Inline-Flow mit Block-Dimensionen (width, height). display: none für das Togglen von Content verwenden.

css
/* Display types */
div { display: block; }           /* full width, line break */
span { display: inline; }         /* content width, no break */
.inline-block { display: inline-block; } /* inline but block props */
.flex { display: flex; }          /* flex container */
.grid { display: grid; }          /* grid container */
.none { display: none; }          /* removed from layout */

/* Visibility (keeps space) */
.hidden { visibility: hidden; }

/* Opacity (keeps space, can interact) */
.fade { opacity: 0; }
03

Farben & Einheiten

Farbformate

CSS unterstützt mehrere Farbformate. Hex (#rrggbb) ist am häufigsten. RGB/RGBA fügt Alpha-Transparenz hinzu. HSL (Hue 0-360, Saturation%, Lightness%) ist intuitiv — Hue ändern, um Farbe zu verschieben, Lightness für Schattierungen. currentColor erbt die color-Eigenschaft des Elements. Modernes CSS unterstützt auch oklch() und color() für breitere Gamuts. rgba/hsla für Transparenz verwenden.

css
/* Named colors */
.color { color: red; background: tomato; }

/* Hexadecimal */
.hex { color: #ff6600; }        /* 6-digit */
.hex-short { color: #f60; }     /* 3-digit shorthand */

/* RGB / RGBA */
.rgb { color: rgb(255, 102, 0); }
.rgba { background: rgba(0, 0, 0, 0.5); }

/* HSL / HSLA (hue, saturation, lightness) */
.hsl { color: hsl(20, 100%, 50%); }
.hsla { background: hsla(120, 100%, 50%, 0.3); }

/* Current color keyword */
.box { color: blue; border: 2px solid currentColor; }

Längen-Einheiten

px ist absolut und vorhersehbar. em ist relativ zur font-size des Eltern-Elements (kumuliert beim Verschachteln). rem ist relativ zur root (html) font-size — konsistent und für Accessibility bevorzugt. % ist relativ zum Eltern-Element. vh/vw sind relativ zum Viewport (100vh = volle Höhe). rem für Font-Größen, % für Layouts und px für Borders/feine Details verwenden.

css
/* Absolute units */
.px { font-size: 16px; }     /* 1px = 1/96 inch */
.pt { font-size: 12pt; }     /* 1pt = 1/72 inch */

/* Relative to parent font-size */
.em { font-size: 1.5em; }    /* 1.5x parent */

/* Relative to root font-size (html) */
.rem { font-size: 1.2rem; }  /* 1.2x root (usually 16px) */

/* Relative to parent dimensions */
.pct { width: 50%; }         /* 50% of parent */

/* Viewport units */
.vh { height: 100vh; }       /* 100% of viewport height */
.vw { width: 50vw; }         /* 50% of viewport width */
.vmin { font-size: 2vmin; }  /* 2% of smaller dimension */

CSS-Funktionen

calc() führt Mathe mit gemischten Einheiten aus (z.B. 100% - 250px). min() wählt den kleinsten Wert (großartig für responsive max-widths). max() wählt den größten. clamp(min, preferred, max) erstellt fluide Werte, die zwischen Bounds skalieren — perfekt für responsive Typografie. var() referenziert Custom Properties mit einem optionalen Fallback. Diese Funktionen machen CSS dynamisch ohne Media-Queries.

css
/* calc() - mathematical calculations */
.sidebar { width: calc(100% - 250px); }
.gap { margin: calc(1rem + 10px); }

/* min() / max() - choose smaller/larger */
.responsive { width: min(90%, 1200px); }
.min-width { width: max(300px, 50%); }

/* clamp() - fluid sizing with bounds */
.title { font-size: clamp(1.5rem, 4vw, 3rem); }

/* var() - use custom properties */
.btn { color: var(--primary, #007bff); }

Gradients

Gradients erstellen sanfte Farbübergänge. linear-gradient(direction, color1, color2) geht in eine Richtung (to right, 45deg). radial-gradient expandiert von einem Mittelpunkt. conic-gradient rotiert um einen Mittelpunkt. Man kann Color-Stops mit Positionen hinzufügen: linear-gradient(to right, red 0%, blue 50%, green 100%). Gradients sind Images, keine Colors, und können überall verwendet werden, wo background-image akzeptiert wird.

css
/* Linear gradient */
.bg1 {
  background: linear-gradient(to right, #ff0000, #0000ff);
}

/* Diagonal with angle */
.bg2 {
  background: linear-gradient(45deg, #ff0000, #00ff00, #0000ff);
}

/* Radial gradient */
.bg3 {
  background: radial-gradient(circle, #ff0000, #0000ff);
}

/* Conic gradient */
.bg4 {
  background: conic-gradient(red, yellow, green, blue, red);
}

Filter & Blend-Modi

filter wendet visuelle Effekte an: blur(), brightness(), contrast(), grayscale(), sepia(), hue-rotate(), invert(), opacity(), saturate(). Mehrere Filter verketten zusammen. mix-blend-mode blendet ein Element mit dem, was dahinter liegt (multiply, screen, overlay usw.). backdrop-filter wendet Filter auf den Bereich hinter einem Element an (großartig für Glassmorphism). Filter können Performance beeinträchtigen — sparsam verwenden.

css
/* Filters */
img.bw { filter: grayscale(100%); }
img.blur { filter: blur(5px); }
img.bright { filter: brightness(1.5); }
img.sepia { filter: sepia(0.8); }

/* Multiple filters */
img.vintage {
  filter: sepia(0.5) contrast(1.2) brightness(0.9);
}

/* Blend mode */
.overlay {
  background: rgba(255,0,0,0.5);
  mix-blend-mode: multiply;
}
04

Typografie

Font-Eigenschaften

font-family akzeptiert eine Fallback-Liste — der Browser verwendet die erste verfügbare. Immer mit einer generischen Familie enden (serif, sans-serif, monospace). font-weight reicht von 100 (thin) bis 900 (black). line-height: 1.5 bedeutet 1.5x die Font-Größe — 1.4-1.6 ist ideal für Body-Text-Lesbarkeit. Das font-Shorthand muss mindestens size und family inkludieren.

css
body {
  /* Font shorthand: style weight size/line-height family */
  font: italic bold 16px/1.5 Arial, sans-serif;

  /* Individual properties */
  font-family: "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  font-weight: 400;  /* 100-900, normal=400, bold=700 */
  font-style: italic; /* normal, italic, oblique */
  line-height: 1.5;
}

Text-Styling

text-align steuert horizontale Ausrichtung. text-decoration fügt Linien hinzu (underline, overline, line-through). text-transform ändert Casing. letter-spacing (Tracking) und word-spacing adjustieren Spacing zwischen Zeichen und Wörtern. white-space: nowrap verhindert Text-Wrapping. Für vertikale Ausrichtung vertical-align (inline) oder Flexbox/Grid-Alignment (block) verwenden.

css
p {
  text-align: justify;        /* left, right, center, justify */
  text-decoration: underline; /* none, overline, line-through */
  text-transform: capitalize; /* uppercase, lowercase, capitalize */
  text-indent: 2em;           /* indent first line */
  letter-spacing: 0.05em;     /* tracking */
  word-spacing: 0.1em;
  white-space: nowrap;        /* prevent wrapping */
}

a {
  text-decoration: none;
  color: #0066cc;
}

Text-Overflow & Wrapping

Um Text mit Ellipsis abzuschneiden, werden drei Eigenschaften benötigt: white-space: nowrap, overflow: hidden und text-overflow: ellipsis. overflow-wrap: break-word bricht lange Wörter, um Overflow zu verhindern. word-break: break-all bricht an jedem Zeichen. text-wrap: balance (neuer) balanciert Zeilenlängen für Headings. Immer max-width oder width setzen, damit Truncation funktioniert.

css
/* Truncate with ellipsis */
.truncate {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
}

/* Break long words */
.break-word {
  overflow-wrap: break-word;
  word-break: break-all;
}

/* Balance text wrapping (newer) */
h1 {
  text-wrap: balance;
}

Web Fonts (@font-face)

@font-face lädt benutzerdefinierte Fonts. woff2 ist das moderne Format (beste Kompression). woff als Fallback bereitstellen. font-display: swap zeigt sofort Fallback-Text und tauscht dann, wenn der Font lädt (verhindert unsichtbaren Text). Immer eine Fallback-Font-Family deklarieren. Google Fonts bietet gehostete Fonts via @import oder <link>. Kritische Fonts für Performance preloaden.

css
@font-face {
  font-family: 'MyCustomFont';
  src: url('fonts/custom.woff2') format('woff2'),
       url('fonts/custom.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

body {
  font-family: 'MyCustomFont', Arial, sans-serif;
}

/* Google Fonts import */
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

Listen- & Link-Styling

list-style: none entfernt Default-Bullets für benutzerdefinierte Navigation oder gestylte Listen. list-style-type ändert den Bullet (disc, circle, square, decimal, none). list-style-position: inside setzt Bullets in den Content-Bereich. Für Links mattert die LVHA-Reihenfolge: :link, :visited, :hover, :active. Dies stellt proper Cascade von Link-Zuständen sicher.

css
/* Reset list styles */
ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

/* Custom bullets */
ul.custom {
  list-style-type: square;
  list-style-position: inside;
}

/* Image bullets */
ul.image {
  list-style-image: url('bullet.png');
}

/* Link states (order matters!) */
a:link { color: blue; }
a:visited { color: purple; }
a:hover { color: red; text-decoration: underline; }
a:active { color: orange; }
05

Flexbox-Layout

Flex-Container

display: flex erstellt einen Flex-Container. justify-content alignt Items entlang der Main-Axis (horizontal in row). align-items alignt entlang der Cross-Axis (vertikal). flex-direction ändert die Main-Axis. flex-wrap erlaubt Items, in neue Zeilen zu wrappen. gap setzt Spacing zwischen Items (ersetzt Margin-Hacks). Flexbox ist ideal für 1D-Layouts (Zeilen ODER Spalten).

css
.container {
  display: flex;

  /* Main axis alignment */
  justify-content: space-between;
  /* flex-start, center, flex-end, space-around, space-evenly */

  /* Cross axis alignment */
  align-items: center;
  /* flex-start, center, flex-end, stretch, baseline */

  /* Direction */
  flex-direction: row;
  /* row, row-reverse, column, column-reverse */

  /* Wrapping */
  flex-wrap: wrap;
  /* nowrap, wrap, wrap-reverse */

  /* Gap between items */
  gap: 16px;
}

Flex-Items

flex-grow steuert, wie Items extra Space teilen (0 = nicht wachsen, 1 = gleich wachsen). flex-shrink steuert, wie Items schrumpfen, wenn Space limitiert ist. flex-basis setzt die initiale Größe. Das Shorthand flex: 1 bedeutet flex-grow:1, flex-shrink:1, flex-basis:0%. align-self überschreibt die align-items des Containers für ein Item. order sortiert Items visuell, ohne DOM zu ändern.

css
.item {
  /* Grow: how much space to take (0 = don't grow) */
  flex-grow: 1;

  /* Shrink: how much to shrink when space is tight */
  flex-shrink: 0;

  /* Basis: initial size before growing/shrinking */
  flex-basis: 200px;

  /* Shorthand: flex: grow shrink basis */
  flex: 1 0 200px;

  /* Override align-items for this item */
  align-self: flex-end;

  /* Order (default 0, lower = earlier) */
  order: -1;
}

Häufige Flexbox-Patterns

Flexbox macht Zentrieren trivial: justify-content: center + align-items: center. Für einen Sticky Footer body als Flex-Column mit min-height: 100vh machen und Main-Content flex: 1 lassen. Für Navbars schiebt justify-content: space-between das erste und letzte Item an gegenüberliegende Enden. Diese Patterns lösen häufige Layout-Probleme, die vor Flexbox schwierig waren.

css
/* Center anything */
.center {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

/* Sticky footer */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.main { flex: 1; }

/* Navbar: logo left, links right */
.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

Flex-Direction & Wrap

flex-direction: column erstellt vertikale Layouts (nützlich zum Stapeln). flex-wrap: wrap erlaubt Items, in neue Zeilen zu fließen, wenn ihnen der Space ausgeht. flex: 1 1 300px bedeutet Items starten bei 300px, wachsen, um Space zu füllen, und schrumpfen nach Bedarf. align-content steuert Spacing zwischen gewrappten Zeilen (funktioniert nur mit wrap). Dieses Pattern erstellt responsive Card-Grids.

css
/* Horizontal (default) */
.row { display: flex; flex-direction: row; }

/* Vertical */
.column { display: flex; flex-direction: column; }

/* Reverse */
.row-rev { display: flex; flex-direction: row-reverse; }

/* Wrap to new lines */
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}
.card { flex: 1 1 300px; } /* grow, shrink, basis */

/* Align wrapped lines */
.cards { align-content: space-between; }

Flexbox-Alignment Deep Dive

In flex-direction: column ist die Main-Axis vertikal und die Cross-Axis horizontal — justify-content und align-items tauschen Rollen. margin: auto auf einem Flex-Item absorbiert allen verfügbaren Space und zentriert es perfekt. Dies ist eine Alternative zu justify-content/align-items. Zu verstehen, welche Axis 'main' vs. 'cross' ist, ist Schlüssel zum Meistern von Flexbox-Alignment.

css
.container {
  display: flex;
  flex-direction: column;

  /* Main axis = vertical (column) */
  justify-content: flex-start;
  /* push items to top, center, bottom, or spread */

  /* Cross axis = horizontal (column) */
  align-items: stretch;
  /* stretch items to full width */
}

/* Center a single item perfectly */
.wrapper {
  display: flex;
  min-height: 100vh;
}
.centered {
  margin: auto; /* centers in both axes */
}
06

CSS Grid Layout

Grid-Container

display: grid erzeugt ein 2D-Layout. grid-template-columns definiert die Spaltengrößen: fr-Einheiten verteilen freien Platz proportional. repeat(3, 1fr) erzeugt 3 gleich breite Spalten. repeat(auto-fit, minmax(250px, 1fr)) erzeugt ein responsives Grid, das die Spaltenanzahl automatisch anpasst — dies ist der 'heilige Gral' der responsiven Grids. gap ersetzt Margins für Abstände.

css
.grid {
  display: grid;

  /* Define columns */
  grid-template-columns: 200px 1fr 200px;
  /* fixed, flexible, fixed */

  /* Or repeat */
  grid-template-columns: repeat(3, 1fr);
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

  /* Define rows */
  grid-template-rows: auto 1fr auto;

  /* Gap (formerly grid-gap) */
  gap: 20px;
  row-gap: 10px;
  column-gap: 20px;
}

Grid-Item-Platzierung

Grid-Items können mehrere Zellen überspannen mit grid-column: span N. Man kann auch Liniennummern verwenden: grid-column: 1 / 3 bedeutet Start bei Linie 1, Ende bei Linie 3. Linien werden von 1 (links/oben) bis N+1 (rechts/unten) nummeriert. grid-area weist Items benannten Bereichen zu. Grid ermöglicht präzise 2D-Platzierung — Items können gleichzeitig Zeilen und Spalten überspannen.

css
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
}

/* Span multiple columns */
.featured {
  grid-column: span 2;
}

/* Explicit placement */
.sidebar {
  grid-column: 1 / 3;  /* start at line 1, end at line 3 */
  grid-row: 1 / 4;
}

/* Named areas */
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }

Grid Template Areas

grid-template-areas erstellt eine visuelle Karte des Layouts mit benannten Strings. Jeder String repräsentiert eine Zeile; jeder Name repräsentiert eine Spalte. Items werden platziert, indem grid-area auf den passenden Namen gesetzt wird. Dies ist die lesbarste Methode, um komplexe Layouts zu erstellen. Verwende '.' für leere Zellen. Derselbe Name kann mehrere Zellen überspannen. Ändere Areas in Media Queries für responsive Layouts.

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  gap: 10px;
  min-height: 100vh;
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }

Grid-Ausrichtung

Grid hat 6 Ausrichtungs-Eigenschaften. align-items/justify-items richten Items innerhalb ihrer Grid-Zellen aus. align-content/justify-content richten die gesamte Grid-Spur innerhalb des Containers aus (nur sichtbar, wenn das Grid kleiner ist). align-self/justify-self überschreiben pro Item. place-items: center ist die Kurzform für align-items + justify-items. place-content: center kombiniert beide Content-Ausrichtungen.

css
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);

  /* Align items within their cell (cross axis) */
  align-items: center;  /* start, center, end, stretch */

  /* Justify items within their cell (main axis) */
  justify-items: center;

  /* Align the entire grid (if smaller than container) */
  align-content: center;
  justify-content: center;
}

/* Override for individual item */
.item {
  align-self: end;
  justify-self: start;
}

Responsives Grid (Auto-fit)

repeat(auto-fit, minmax(300px, 1fr)) erzeugt ein Grid, das die Spaltenanzahl automatisch basierend auf dem verfügbaren Platz anpasst — Items sind mindestens 300px breit und wachsen, um zu füllen. Dies eliminiert Media Queries für Card-Layouts. auto-fill behält leere Spalten (Items bleiben links), auto-fit klappt sie zusammen (Items werden gestreckt). Verwende auto-fit für die meisten Fälle. Kombiniere mit max-width auf dem Container für optimale Ergebnisse.

css
/* Auto-responsive grid - no media queries needed! */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
}

/* Fixed number of columns per breakpoint */
@media (min-width: 768px) {
  .cards {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 1024px) {
  .cards {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Auto-fill vs auto-fit:
   auto-fit collapses empty tracks
   auto-fill keeps empty tracks */
07

Positioning

Positionstypen

static ist der Standard (normaler Dokumentfluss). relative verschiebt ab der normalen Position, ohne andere Elemente zu beeinflussen (erstellt einen Positionierungskontext). absolute entfernt aus dem Fluss und positioniert relativ zum nächsten positionierten Vorfahren. fixed positioniert relativ zum Viewport (bleibt beim Scrollen). sticky schaltet zwischen relative und fixed — scrollt normal und bleibt dann am Schwellenwert hängen.

css
/* Static (default) - normal flow */
.static { position: static; }

/* Relative - offset from normal position */
.relative {
  position: relative;
  top: 10px;
  left: 20px;
}

/* Absolute - positioned relative to nearest positioned ancestor */
.absolute {
  position: absolute;
  top: 0;
  right: 0;
}

/* Fixed - positioned relative to viewport */
.fixed {
  position: fixed;
  bottom: 0;
  width: 100%;
}

/* Sticky - scrolls then sticks */
.sticky {
  position: sticky;
  top: 0;
}

Absolute Positionierung

absolute Positionierung erfordert einen positionierten Vorfahren (relative, absolute, fixed oder sticky). Ohne einen solchen wird relativ zum Viewport positioniert. Die Eigenschaften top/right/bottom/left verschieben ab der entsprechenden Kante. Um ein absolut positioniertes Element zu zentrieren, verwende top:50%, left:50% mit transform: translate(-50%,-50%). Absolute Positionierung entfernt Elemente aus dem normalen Fluss.

css
/* Parent must be positioned */
.container {
  position: relative;
  width: 400px;
  height: 300px;
}

/* Position relative to container */
.badge {
  position: absolute;
  top: 10px;
  right: 10px;
}

/* Center absolutely positioned element */
.modal {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

Sticky Positionierung

position: sticky ist eine Mischung — Elemente scrollen normal, bis sie einen Schwellenwert erreichen (z. B. top: 0), und bleiben dann hängen. Ideal für Sticky-Header, Sidebars und Tabellen-Header. Das Element bleibt innerhalb seines Eltern-Containers hängen (hört auf zu kleben, wenn der Eltern-Container vorbeiscrollt). Sticky funktioniert nicht, wenn ein Vorfahre overflow: hidden/auto/scroll hat. Setze immer einen z-index, um Überlappungsprobleme zu vermeiden.

css
/* Sticky header */
.header {
  position: sticky;
  top: 0;
  background: white;
  z-index: 100;
  padding: 1rem;
}

/* Sticky sidebar */
.sidebar {
  position: sticky;
  top: 80px; /* offset for fixed header */
  height: calc(100vh - 80px);
  overflow-y: auto;
}

/* Note: sticky doesn't work if a parent has
   overflow: hidden or overflow: auto */

Z-index & Stacking Context

z-index steuert die Stapelreihenfolge positionierter Elemente (höher = oben). Es funktioniert nur bei positionierten Elementen (nicht static). Ein Stacking-Kontext wird durch positionierte Elemente mit z-index, opacity < 1, transform oder filter erstellt. Innerhalb eines Stacking-Kontexts sind Kind-z-index-Werte relativ zu diesem Kontext — ein Kind kann nie über einem Geschwister seines Eltern-Elements mit höherem z-index erscheinen. Dies ist eine häufige Quelle von Verwirrung.

css
/* Higher z-index = closer to viewer */
.modal-overlay {
  position: fixed;
  z-index: 9999;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(0,0,0,0.5);
}

.modal {
  position: fixed;
  z-index: 10000; /* above overlay */
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
}

/* Stacking context: z-index only works
   within the same stacking context */
.parent { position: relative; z-index: 1; }
.child { position: absolute; z-index: 9999; }
/* child can't exceed parent's stacking level */

Float & Clear (Legacy)

float war die primäre Layout-Methode vor Flexbox/Grid. Es entfernt Elemente aus dem normalen Fluss und schiebt sie nach links/rechts, wobei Text um sie herumfließt. clear verhindert, dass Elemente neben Floats erscheinen. Der Clearfix-Hack zwingt einen Container, gefloatete Kinder einzuschließen. Heute verwende float nur für seinen vorgesehenen Zweck: Text um Bilder fließen zu lassen. Für Layouts verwende Flexbox oder Grid.

css
/* Float text around an image */
img.float-left {
  float: left;
  margin: 0 1rem 1rem 0;
}

/* Clear floats */
.clear { clear: both; }
.clear-left { clear: left; }
.clear-right { clear: right; }

/* Clearfix hack for containers */
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}

/* Modern alternative: use flexbox or grid */
/* Float is mainly for text wrapping now */
08

Responsive Design

Media Queries

Media Queries wenden Stile basierend auf Bedingungen an. min-width (Mobile-First) wird bevorzugt — Basis-Stile zielen auf Mobile, dann wird für größere Bildschirme erweitert. max-width (Desktop-First) ist umgekehrt. Andere Bedingungen: prefers-color-scheme (Dark/Light), print, orientation (Portrait/Landscape), prefers-reduced-motion. Setze immer ein Viewport-Meta-Tag in HTML, damit Media Queries auf Mobile funktionieren.

css
/* Mobile-first: base styles first, then min-width */

/* Base (mobile) */
.container { flex-direction: column; }

/* Tablet and up */
@media (min-width: 768px) {
  .container { flex-direction: row; }
}

/* Desktop and up */
@media (min-width: 1024px) {
  .container { max-width: 1200px; margin: 0 auto; }
}

/* Print styles */
@media print {
  .no-print { display: none; }
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  body { background: #1a1a1a; color: #eee; }
}

Fluide Typografie

clamp(min, preferred, max) erzeugt fluide Typografie, die sich fließend mit der Viewport-Größe skaliert — keine Media Queries nötig. Der Preferred-Wert (oft vw-basiert) skaliert zwischen min- und max-Grenzen. min() wählt den kleineren Wert (ideal für responsive max-widths). Dieser Ansatz reduziert die Anzahl benötigter Media Queries und erzeugt flüssigere Skalierung. Setze immer sinnvolle min/max-Werte für die Lesbarkeit.

css
/* clamp() for fluid font sizes */
h1 {
  font-size: clamp(1.5rem, 5vw, 3rem);
  /* min: 1.5rem, preferred: 5vw, max: 3rem */
}

/* Fluid spacing */
.container {
  padding: clamp(1rem, 3vw, 3rem);
}

/* Fluid width */
.content {
  width: min(90%, 1200px);
  margin: 0 auto;
}

/* Viewport-based sizing */
.hero {
  height: 100vh;
  font-size: clamp(2rem, 8vw, 5rem);
}

Container Queries

Container Queries (CSS Containment Module Level 3) ermöglichen das Stylen von Elementen basierend auf der Größe ihres Eltern-Containers, nicht des Viewports. container-type: inline-size deklariert einen Container. @container wendet Stile an, wenn der Container die Bedingung erfüllt. Dies ist modularer als Media Queries — Komponenten passen sich an ihren Container an, nicht an den Bildschirm. Ideal für wiederverwendbare Komponenten in unterschiedlichen Layout-Kontexten.

css
/* Define a container */
.card-container {
  container-type: inline-size;
  /* or: container: sidebar / inline-size; */
}

/* Query the container's size */
@container (min-width: 400px) {
  .card {
    display: flex;
    flex-direction: row;
  }
}

@container (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
}

Responsive Bilder & Medien

max-width: 100% + height: auto macht Bilder responsiv (skaliert herunter, aber nie hoch). Der Padding-Bottom-Hack erzeugt responsive 16:9-Video-Einbettungen. Die moderne aspect-ratio-Eigenschaft ist sauberer — setze das Verhältnis und der Browser berechnet die Höhe. Setze immer width- und height-Attribute auf Bildern, um Layout-Verschiebungen (CLS) zu verhindern. Verwende object-fit: cover, um Bilder innerhalb fester Abmessungen zuzuschneiden.

css
/* Responsive image */
img {
  max-width: 100%;
  height: auto;
}

/* Responsive video (16:9 aspect ratio) */
.video-wrapper {
  position: relative;
  padding-bottom: 56.25%; /* 9/16 */
  height: 0;
}
.video-wrapper iframe {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  height: 100%;
}

/* Aspect ratio property */
.box {
  aspect-ratio: 16 / 9;
  width: 100%;
}

Mobile-First-Strategie

Mobile-First bedeutet, Mobile-Stile als Basis zu schreiben und dann mit min-width-Media-Queries für größere Bildschirme schrittweise zu erweitern. Dadurch laden Mobile-Nutzer (oft mit langsameren Verbindungen) weniger CSS herunter. Häufige Breakpoints: 768px (Tablet), 1024px (Desktop), 1440px (groß). Verwende relative Einheiten (rem, %, vw) statt fester px für bessere Skalierbarkeit. Teste auf echten Geräten, nicht nur in Browser-DevTools.

css
/* 1. Start with mobile base styles */
.nav { display: none; } /* hidden on mobile */
.menu-toggle { display: block; }

/* 2. Enhance for larger screens */
@media (min-width: 768px) {
  .nav { display: flex; }
  .menu-toggle { display: none; }
}

/* 3. Common breakpoints */
/* Mobile: < 768px */
/* Tablet: 768px - 1023px */
/* Desktop: 1024px - 1439px */
/* Large: >= 1440px */

/* 4. Use relative units */
body { font-size: 1rem; } /* not 16px */
09

Transitions & Animations

Transitions

transition erzeugt sanfte Übergänge zwischen Eigenschaftswerten. Syntax: transition: property duration timing-function delay. Timing-Funktionen: ease (Standard), linear, ease-in, ease-out, ease-in-out, cubic-bezier(). Nur animierbare Eigenschaften transitionieren. Vermeide transition: all (Performance). Transitions werden bei Pseudo-Klassen-Änderungen (:hover, :focus) oder Klassenänderungen via JavaScript ausgelöst.

css
.button {
  background: #007bff;
  transition: background 0.3s ease, transform 0.2s ease;
}

.button:hover {
  background: #0056b3;
  transform: translateY(-2px);
}

/* Transition all properties (use sparingly) */
.card {
  transition: all 0.3s ease;
}

/* Shorthand: property duration timing-function delay */
.box {
  transition: opacity 0.5s ease-in 0.2s;
}

Transform

transform verändert ein Element, ohne das Layout zu beeinflussen (im Gegensatz zu margin/position). translate verschiebt es (translateX, translateY oder translate(x,y)). scale ändert die Größe (1 = 100%). rotate dreht es (deg, rad, turn). skew verzerrt es. Mehrere Transforms verketten in Reihenfolge. Transforms sind GPU-beschleunigt — gut für die Performance. Kombiniere immer mit transition für sanfte Effekte. transform-origin ändert den Drehpunkt.

css
.box {
  transition: transform 0.3s ease;
}

/* Translate (move) */
.box:hover { transform: translate(10px, 20px); }
.box:hover { transform: translateX(50%); }

/* Scale (resize) */
.box:hover { transform: scale(1.1); }

/* Rotate */
.box:hover { transform: rotate(45deg); }

/* Skew */
.box:hover { transform: skew(10deg, 5deg); }

/* Combine transforms */
.box:hover {
  transform: translate(10px, 0) scale(1.1) rotate(5deg);
}

Keyframe-Animationen

@keyframes definiert Animations-Schritte. 0%/from ist der Start, 100%/to ist das Ende. Du kannst Zwischenschritte hinzufügen (25%, 50%, 75%). Die animation-Kurzform: name duration timing-function delay iteration-count direction fill-mode. infinite läuft endlos. direction: alternate kehrt bei geraden Iterationen um. fill-mode: forwards behält den Endzustand. Animationen laufen automatisch, im Gegensatz zu Transitions.

css
@keyframes bounce {
  0%   { transform: translateY(0); }
  50%  { transform: translateY(-20px); }
  100% { transform: translateY(0); }
}

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.ball {
  animation: bounce 0.5s ease infinite;
}

.element {
  animation: fadeIn 1s ease forwards;
  /* name duration timing delay iteration direction fill-mode */
}

Animations-Eigenschaften

Einzelne Animations-Eigenschaften bieten feine Kontrolle. animation-iteration-count kann eine Zahl oder infinite sein. animation-direction: alternate spielt vorwärts dann rückwärts ab (ideal für Ping-Pong-Effekte). animation-fill-mode: forwards behält den Endzustand nach Abschluss. animation-play-state: paused friert die Animation ein — nützlich für Hover-zum-Pausieren. Mehrere Animationen werden kommagetrennt: animation: spin 1s, fade 2s;.

css
.spinner {
  animation-name: spin;
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-delay: 0s;
  animation-iteration-count: infinite;
  animation-direction: normal; /* alternate, reverse */
  animation-fill-mode: none;   /* forwards, backwards, both */
  animation-play-state: running; /* paused */
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Pause on hover */
.spinner:hover {
  animation-play-state: paused;
}

Performance & Reduced Motion

Für flüssige 60fps-Animationen animiere nur transform und opacity — sie sind GPU-beschleunigt und lösen kein Layout (Reflow) aus. Das Animieren von width, margin, top usw. zwingt den Browser, für jedes Frame das Layout neu zu berechnen, was zu Ruckeln führt. Respektiere immer prefers-reduced-motion: reduce — einige Nutzer erleben Bewegungskrankheit oder haben vestibuläre Störungen. Biete diesen Nutzern sofortige Transitions oder deaktiviere Animationen.

css
/* Only animate transform and opacity for performance */
.good {
  transition: transform 0.3s, opacity 0.3s;
}

/* Avoid animating these (cause reflow/repaint): */
/* margin, padding, width, height, top, left */

/* Respect user's motion preference */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}
10

Variables & Advanced Functions

Custom Properties (Variablen)

Custom Properties (CSS-Variablen) speichern wiederverwendbare Werte. Definiere sie in :root für globalen Zugriff. Referenziere mit var(--name). Sie kaskadieren und können in jedem Scope überschrieben werden — perfekt für Theming (Dark/Light-Mode). Im Gegensatz zu Präprozessor-Variablen sind sie dynamisch (ändern sich zur Laufzeit) und können mit JavaScript manipuliert werden. Biete immer Fallbacks an: var(--primary, #007bff). Dies ist die moderne Art, Design-Tokens zu verwalten.

css
:root {
  /* Colors */
  --primary: #007bff;
  --primary-dark: #0056b3;
  --text: #333;
  --bg: #fff;

  /* Spacing scale */
  --space-sm: 0.5rem;
  --space-md: 1rem;
  --space-lg: 2rem;

  /* Font sizes */
  --font-base: 16px;
  --font-lg: 1.5rem;
}

.button {
  background: var(--primary);
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-base);
  color: white;
}

/* Override in a scope */
.dark-theme {
  --bg: #1a1a1a;
  --text: #eee;
}

calc() & Math-Funktionen

calc() führt Mathematik mit beliebigen Einheiten aus, einschließlich Mischung von px, %, em, rem, vw. Es ist essenziell für responsive Layouts. Du kannst calc() verschachteln, aber es ist unnötig — calc(100% - 2rem) / 3 funktioniert ohne inneres calc. min() gibt den kleinsten Wert, max() den größten, clamp() begrenzt einen Wert zwischen min und max. Diese Funktionen machen CSS dynamisch ohne JavaScript oder Media Queries.

css
/* Mixed unit calculations */
.sidebar {
  width: calc(100% - 250px);
}

/* With variables */
.box {
  padding: calc(var(--space-md) + 10px);
}

/* Nested calc */
.responsive {
  width: calc(calc(100% - 2rem) / 3);
}

/* min(), max(), clamp() */
.fluid {
  width: min(90%, 1200px);
  font-size: clamp(1rem, 2vw + 1rem, 2rem);
  height: max(200px, 50vh);
}

Object Fit & Position

object-fit steuert, wie Bilder/Video ihren Container füllen (wie background-size für <img>). cover füllt den Container und schneidet Überlauf ab (ideal für Avatare/Thumbnails). contain passt vollständig ein ohne Zuschneiden (kann leeren Raum lassen). fill streckt (verzerrt). object-position passt die Ausrichtung an (wie background-position). Dies ersetzt die Notwendigkeit von background-image-Hacks für responsive Bilder.

css
/* Cover: fill container, crop overflow */
.avatar {
  width: 100px;
  height: 100px;
  object-fit: cover;
  border-radius: 50%;
}

/* Contain: fit entirely, may letterbox */
.preview {
  width: 200px;
  height: 200px;
  object-fit: contain;
  background: #eee;
}

/* Position the image within the frame */
.image {
  object-fit: cover;
  object-position: top center;
}

Background-Eigenschaften

background ist eine mächtige Kurzform. background-size: cover füllt den Container (mit Zuschneiden); contain passt ein ohne Zuschneiden. background-attachment: fixed erzeugt einen Parallax-Effekt (Bild bleibt beim Scrollen stehen). Mehrere Hintergründe schichten sich mit Kommas (erste = oberste Schicht). Verwende linear-gradient als Hintergrund für Overlays: background: linear-gradient(rgba(0,0,0,0.5), transparent), url('image.jpg').

css
.hero {
  /* Shorthand */
  background: url('hero.jpg') center/cover no-repeat fixed;

  /* Individual properties */
  background-image: url('hero.jpg');
  background-size: cover;     /* cover, contain, or px/% */
  background-position: center; /* top, bottom, left, right, or x y */
  background-repeat: no-repeat;
  background-attachment: fixed; /* scroll, fixed, local */

  /* Multiple backgrounds */
  background:
    url('overlay.png') no-repeat center,
    url('hero.jpg') center/cover;
}

CSS Nesting (Modern)

Modernes CSS unterstützt natives Nesting (wie Sass/Less). Verwende &, um den Eltern-Selektor zu referenzieren. Nesting verbessert die Lesbarkeit und reduziert Wiederholungen. Media Queries können direkt innerhalb von Regeln verschachtelt werden. Die Browser-Unterstützung ist in modernen Browsern gut (2023+). Das & ist erforderlich für Pseudo-Klassen (&:hover) und Kombinatoren (& > .child). Vermeide tiefes Nesting (3+ Ebenen), da es die Spezifität erhöht und die Wartbarkeit reduziert.

css
/* Native CSS nesting (no preprocessor needed) */
.card {
  background: white;
  border-radius: 8px;

  & .title {
    font-size: 1.5rem;
    font-weight: bold;
  }

  & .body {
    padding: 1rem;

    & p {
      line-height: 1.6;
    }
  }

  &:hover {
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  }

  @media (max-width: 768px) {
    padding: 0.5rem;
  }
}
11

CSS Custom Properties (Variables) Deep Dive

Variablen definieren & verwenden

CSS Custom Properties (Variablen) werden mit --name definiert und mit var() verwendet. Definiere globale Variablen in :root für Theme-Werte. Im Gegensatz zu Sass-Variablen sind CSS-Variablen live — Änderungen aktualisieren sofort alle Verwendungen. Sie sind auf das Element scopeiert, auf dem sie definiert sind, und werden von Nachfahren geerbt. var() akzeptiert einen Fallback-Wert als zweites Argument, und Fallbacks können verkettet werden. Das macht sie weitaus mächtiger als Präprozessor-Variablen für dynamisches Theming.

css
:root {
  --primary: #3498db;
  --spacing: 16px;
  --radius: 8px;
  --max-width: 1200px;
}

.button {
  background: var(--primary);
  padding: var(--spacing);
  border-radius: var(--radius);
  max-width: var(--max-width);
}

/* Fallback values */
color: var(--text-color, #333);
/* Chained fallbacks */
color: var(--text, var(--default, black));

Dynamisches Theming mit JavaScript

CSS-Variablen ermöglichen Laufzeit-Theming, das Präprozessoren nicht leisten können. Setze data-theme auf <html> und überschreibe Variablen pro Theme. JavaScript kann Variablen zur Laufzeit lesen (getComputedStyle) und setzen (style.setProperty), was dynamische Color-Picker, Nutzereinstellungen und Live-Vorschauen ermöglicht. Dies ist der Standardansatz für Dark Mode, Brand-Anpassung und vom Nutzer wählbare Themes. Variablen kaskadieren und vererben, sodass das Überschreiben in einem Kind-Element nur diesen Teilbaum betrifft.

css
/* Define theme variables */
:root {
  --bg: #ffffff;
  --text: #333333;
}

[data-theme="dark"] {
  --bg: #1a1a1a;
  --text: #e0e0e0;
}

body {
  background: var(--bg);
  color: var(--text);
}

/* Toggle theme with JS */
<script>
document.documentElement.setAttribute(
  "data-theme",
  isDark ? "dark" : "light"
);

/* Or set a single variable directly */
document.documentElement.style
  .setProperty("--primary", "#e74c3c");
</script>

Scope-Variablen & Vererbung

CSS-Variablen vererben wie andere Eigenschaften. Eine auf :root definierte Variable ist überall verfügbar; eine auf .card definierte betrifft nur .card und seine Nachfahren. Dieses Scoping ermöglicht Anpassungen auf Komponenten-Ebene. Du kannst Variablen in Media Queries überschreiben, um responsive Variablenwerte zu erstellen — die Variable selbst kann nicht in @media-Bedingungen verwendet werden, aber du kannst ihren Wert innerhalb eines Media-Query-Blocks ändern. Dieses Muster ist mächtig für responsives Design ohne Wiederholung von Eigenschaftsdeklarationen.

css
:root {
  --padding: 20px;
}

.card {
  --padding: 12px; /* overrides only for .card subtree */
  padding: var(--padding);
}

.card .inner {
  padding: var(--padding); /* inherits 12px from .card */
}

/* Variables in media queries don't work, but... */
.sidebar {
  --width: 250px;
  width: var(--width);
}
@media (max-width: 768px) {
  .sidebar { --width: 100%; }
}

Variablen mit calc()

Die Kombination von CSS-Variablen mit calc() erzeugt mächtige Design-Systeme. Definiere eine Basisgröße und einen Skalierungsfaktor, dann berechne abgeleitete Größen. Dies ermöglicht konsistente typografische Skalen und Abstands-Systeme. calc() funktioniert mit gemischten Einheiten (px, %, em, vw) und Variablen. Du kannst sogar Variablen ohne Fallbacks verwenden (var(--nav-h, 60px) bietet einen Standardwert). Dieser Ansatz ist das Fundament moderner Design-Systeme — ändere eine Variable und die gesamte Skala passt sich proportional an.

css
:root {
  --base-size: 16px;
  --scale: 1.25;
}

h1 { font-size: calc(var(--base-size) * var(--scale) * 2); }
h2 { font-size: calc(var(--base-size) * var(--scale) * 1.5); }
p  { font-size: var(--base-size); }

/* Spacing scale */
:root {
  --space: 8px;
}
.margin { margin: calc(var(--space) * 2); }
.padding { padding: calc(var(--space) * 3); }

/* Mixed units */
.header { height: calc(var(--nav-h, 60px) + var(--content-h)); }

Custom Properties registrieren (@property)

@property registriert Custom Properties mit einem Typ (syntax), einem Initialwert und einem Vererbungs-Flag. Dies ermöglicht es CSS-Variablen, animiert und transitioniert zu werden — ohne @property werden Variablen als Strings behandelt und können nicht interpoliert werden. syntax akzeptiert Typen wie <angle>, <color>, <length>, <number>, <percentage> oder '*'. Dies erschließt sanfte Animationen von Gradienten, Transforms und Farben, gesteuert durch Variablen. Die Browser-Unterstützung ist gut in Chromium und Safari, Firefox fügt Unterstützung hinzu. Ein großer Fortschritt für CSS-Animationsfähigkeiten.

css
/* Type-safe custom properties */
@property --angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

@property --color {
  syntax: "<color>";
  initial-value: #3498db;
  inherits: false;
}

/* Now animatable! */
@keyframes spin {
  to { --angle: 360deg; }
}

.loader {
  --angle: 0deg;
  animation: spin 1s linear infinite;
  background: conic-gradient(
    from var(--angle),
    var(--color), transparent
  );
}
12

3D Transforms

3D-Transform-Funktionen

3D-Transforms fügen Elementen Tiefe hinzu. perspective() als Transform-Funktion gilt für ein einzelnes Element; die perspective-Eigenschaft auf einem Eltern-Element gilt einheitlich für alle Kinder. rotateX/rotateY/rotateZ rotieren um Achsen; translateZ bewegt entlang der Z-Achse (auf den Betrachter zu/weg). Niedrigere perspective-Werte erzeugen dramatischere 3D-Effekte (näherer Standpunkt). Setze immer perspective auf den Eltern-Container für einen konsistenten 3D-Raum über mehrere transformierte Kinder. Kombiniere mehrere Transforms für komplexe 3D-Positionierung.

css
.card {
  transform: perspective(1000px) rotateY(45deg) rotateX(15deg);
}

/* Using the perspective property instead */
.container {
  perspective: 1000px;
}
.container .card {
  transform: rotateY(45deg) rotateX(15deg);
}

/* translateZ moves toward/away from viewer */
.layer {
  transform: translateZ(100px);
}

/* scale3d for 3D scaling */
.box {
  transform: scale3d(1.5, 1.5, 1.5);
}

transform-style & backface-visibility

transform-style: preserve-3d erhält den 3D-Raum für Kind-Elemente (flat ist der Standard, der Kinder flachlegt). backface-visibility: hidden verbirgt die Rückseite eines Elements bei Rotation — essenziell für Flip-Card-Effekte. Die klassische Flip-Card verwendet zwei absolut positionierte Faces: Das vordere Face schaut nach vorne, das hintere ist vorrotiert um 180deg. Beim Hover rotiert der Eltern-Container um 180deg und tauscht, welches Face sichtbar ist. Dies ist eines der beliebtesten 3D-CSS-Muster.

css
.container {
  perspective: 1000px;
}

.flip-card {
  transform-style: preserve-3d;
  transition: transform 0.6s;
  position: relative;
}

.flip-card:hover {
  transform: rotateY(180deg);
}

.flip-card .front,
.flip-card .back {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
}

.flip-card .back {
  transform: rotateY(180deg);
}

3D-Würfel

Ein 3D-Würfel wird mit 6 Faces gebaut, jeweils positioniert mit rotate + translateZ. translateZ(100px) schiebt das Face um die halbe Würfelbreite nach außen. Jedes Face wird vorrotiert, um in seine Richtung zu schauen, bevor es herausgeschoben wird. transform-style: preserve-3d auf dem Würfel-Container ist essenziell — ohne es flachen die Faces ab. Die Animation rotiert den Würfel auf beiden Achsen X und Y. Dies demonstriert die volle Macht von CSS-3D-Transforms. Passe translateZ an die halbe Würfelgröße an für korrekte Geometrie.

css
.scene {
  perspective: 800px;
  width: 200px; height: 200px;
}
.cube {
  position: relative;
  width: 100%; height: 100%;
  transform-style: preserve-3d;
  animation: rotate 8s infinite linear;
}
@keyframes rotate {
  from { transform: rotateX(0) rotateY(0); }
  to   { transform: rotateX(360deg) rotateY(360deg); }
}
.face {
  position: absolute;
  width: 200px; height: 200px;
  opacity: 0.85;
}
.front  { transform: translateZ(100px); background: red; }
.back   { transform: rotateY(180deg) translateZ(100px); background: blue; }
.right  { transform: rotateY(90deg) translateZ(100px); background: green; }
.left   { transform: rotateY(-90deg) translateZ(100px); background: yellow; }
.top    { transform: rotateX(90deg) translateZ(100px); background: purple; }
.bottom { transform: rotateX(-90deg) translateZ(100px); background: orange; }

3D-Karten-Neigungseffekt

Der Karten-Neigungseffekt verfolgt die Mausposition und rotiert die Karte in 3D basierend auf dem Cursor-Offset vom Zentrum. Die Mathematik teilt den Offset durch einen Faktor (10), um den Rotationswinkel zu begrenzen. Bei mouseleave setzt sich die Karte zurück. Die transition erzeugt sanfte Bewegung. Ein Glanz-/Shine-Overlay mit einem radialen Gradienten, der der Maus folgt, verstärkt den Effekt. Dies ist ein beliebtes interaktives UI-Muster für Produktkarten und Hero-Sections. Die perspective im Transform-String stellt 3D-Rendering sicher, auch ohne eine Eltern-perspective-Eigenschaft.

css
.tilt-card {
  transition: transform 0.1s ease-out;
  transform-style: preserve-3d;
}

/* JavaScript-driven tilt */
<script>
const card = document.querySelector(".tilt-card");
card.addEventListener("mousemove", (e) => {
  const rect = card.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
  const centerX = rect.width / 2;
  const centerY = rect.height / 2;
  const rotateX = (y - centerY) / 10;
  const rotateY = (centerX - x) / 10;
  card.style.transform =
    `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
});
card.addEventListener("mouseleave", () => {
  card.style.transform = "perspective(1000px) rotateX(0) rotateY(0)";
});
</script>

perspective-origin & 3D-Abstände

perspective-origin setzt die Position des Fluchtpunkts (wie das Bewegen des Kopfes). Standard ist 50% 50% (Mitte). Ein Versatz erzeugt dynamische Blickwinkel. Für Parallax-Effekte bewegen sich Elemente bei unterschiedlichen translateZ-Werten mit unterschiedlichen Geschwindigkeiten, wenn der Container scrollt oder rotiert. Weiter hinten liegende Elemente (negatives translateZ) benötigen scale(), um das perspektivische Schrumpfen auszugleichen. Diese Technik erzeugt Tiefe in UI ohne JavaScript — reines CSS-Parallax. Kombiniert mit scroll-driven Animations erzeugt sie immersive Scroll-Erlebnisse.

css
.stage {
  perspective: 1200px;
  perspective-origin: 50% 30%; /* x y position of vanishing point */
  transform-style: preserve-3d;
}

.layer-1 { transform: translateZ(0); }
.layer-2 { transform: translateZ(50px); }
.layer-3 { transform: translateZ(100px); }

/* Parallax-like depth */
.depth-bg    { transform: translateZ(-200px) scale(1.2); }
.depth-mid   { transform: translateZ(-100px) scale(1.1); }
.depth-fg    { transform: translateZ(0); }
13

CSS Filters & Backdrop Filters

Filter-Funktionen

CSS-Filter wenden visuelle Effekte auf Elemente an. grayscale, sepia und invert ändern Farben; blur weicht auf; brightness/contrast/saturate passen Intensität an; hue-rotate verschiebt Farben. Mehrere Filter verketten von links nach rechts. drop-shadow ist box-shadow für PNG/SVG-Bilder überlegen, weil es der Alpha-Form folgt (transparente Bereiche erhalten keinen Schatten). Filter sind GPU-beschleunigt und performant. Häufige Verwendung: grayscale beim Hover für Bildergalerien, Vintage-Foto-Effekte und Accessibility (High-Contrast-Modi).

css
img.grayscale { filter: grayscale(100%); }
img.blur { filter: blur(5px); }
img.bright { filter: brightness(1.5); }
img.contrast { filter: contrast(200%); }
img.sepia { filter: sepia(80%); }
img.saturate { filter: saturate(2); }
img.hue { filter: hue-rotate(90deg); }
img.invert { filter: invert(100%); }

/* Combine multiple filters */
img.vintage {
  filter: sepia(50%) contrast(110%) brightness(90%) saturate(120%);
}

/* Drop shadow (follows alpha shape) */
img.png-shadow {
  filter: drop-shadow(2px 4px 6px rgba(0,0,0,0.4));
}

backdrop-filter (Glassmorphism)

backdrop-filter wendet Filter auf den Bereich hinter einem Element an (nicht auf das Element selbst) und erzeugt den Glassmorphism-Effekt. Das Element benötigt einen halbtransparenten Hintergrund, damit der Effekt sichtbar wird. blur ist der häufigste Backdrop-Filter für Frosted Glass. Schließe immer das -webkit-Präfix für Safari-Unterstützung ein. Kombiniere mit halbtransparenten Borders und dezenten box-shadows für einen polierten Glas-Look. Performance kann bei großen geblurten Flächen ein Problem sein — sparsam verwenden. Dies ist ein definierender Trend im modernen UI-Design (iOS, macOS, Windows Acrylic).

css
.glass {
  background: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px) saturate(180%);
  -webkit-backdrop-filter: blur(10px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
  padding: 24px;
}

.glass-dark {
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

SVG-Filter (url-Referenz)

CSS filter: url(#id) referenziert SVG-Filter für Effekte jenseits der eingebauten Funktionen. Der 'gooey'-Filter erzeugt blob-artiges Verschmelzen von Elementen (beliebt für Lade-Animationen und organische UI). feGaussianBlur + feColorMatrix mit einem hohen Alpha-Multiplikator erzeugt den Gooey-Effekt, indem geblurte Kanten geschärft werden. feTurbulence + feDisplacementMap erzeugt wellige/verzerrte Effekte. SVG-Filter sind mächtig, können aber performance-intensiv sein. Sie ermöglichen Effekte, die mit CSS allein unmöglich sind: flüssiges Morphen, Displacement, Beleuchtung und benutzerdefiniertes Compositing.

css
<!-- Define SVG filter -->
<svg style="display:none">
  <filter id="gooey">
    <feGaussianBlur in="SourceGraphic" stdDeviation="10" />
    <feColorMatrix values="
      1 0 0 0 0
      0 1 0 0 0
      0 0 1 0 0
      0 0 0 20 -10" />
  </filter>
</svg>

<!-- Apply via CSS -->
.gooey-container {
  filter: url(#gooey);
}

<!-- Displacement map for wavy text -->
<filter id="wavy">
  <feTurbulence baseFrequency="0.02" numOctaves="3" />
  <feDisplacementMap in="SourceGraphic" scale="10" />
</filter>

Filter-Animationen

Filter können animiert und sanft transitioniert werden. Der Pulse-Glow-Effekt kombiniert brightness und drop-shadow für einen Neon-Glow. Grayscale-zu-Farbe beim Hover ist eine klassische Galerie-Interaktion. Filter-Transitions sind GPU-beschleunigt und performen besser als das Animieren von box-shadow oder background-color. Allerdings kann das Animieren von blur oder komplexen Filtern teuer sein — teste auf Mobile. Der scroll-driven hue-rotate ist ein lustiger Effekt, kann aber bei langen Seiten Performance-Probleme verursachen; verwende will-change: filter, um den Browser für Optimierung zu hinweisen.

css
@keyframes pulse-glow {
  0%, 100% {
    filter: brightness(1) drop-shadow(0 0 5px #3498db);
  }
  50% {
    filter: brightness(1.3) drop-shadow(0 0 20px #3498db);
  }
}

.glow-button {
  animation: pulse-glow 2s ease-in-out infinite;
}

/* Hover filter transition */
.gallery img {
  filter: grayscale(100%);
  transition: filter 0.3s ease;
}
.gallery img:hover {
  filter: grayscale(0%);
}

/* Color shift on scroll (with JS) */
window.addEventListener("scroll", () => {
  const hue = window.scrollY * 0.5;
  document.body.style.filter = `hue-rotate(${hue}deg)`;
});

mix-blend-mode & background-blend-mode

mix-blend-mode bestimmt, wie die Pixel eines Elements mit dem Inhalt dahinter verschmelzen. multiply verdunkelt (gut für Schatten und Wasserzeichen); screen hellt auf (gut für Glows); difference erzeugt psychedelische Effekte; overlay kombiniert multiply und screen für Kontrast. background-blend-mode verschmilzt mehrere Hintergrund-Schichten (Bilder und Gradienten) auf demselben Element. Blend-Modi sind essenziell für kreatives Compositing, Duotone-Effekte und Text-über-Bild-Overlays. isolation: isolate erzeugt einen neuen Blending-Kontext, um Blend-Effekte einzudämmen.

css
/* mix-blend-mode: how element blends with backdrop */
.overlay {
  mix-blend-mode: multiply; /* darken */
}
.overlay-screen {
  mix-blend-mode: screen; /* lighten */
}
.overlay-difference {
  mix-blend-mode: difference; /* invert */
}

/* Common blend modes: multiply, screen, overlay,
   darken, lighten, color-dodge, color-burn,
   hard-light, soft-light, difference, exclusion,
   hue, saturation, color, luminosity */

/* background-blend-mode: blend background layers */
.gradient-texture {
  background-image: url(texture.png),
                    linear-gradient(45deg, red, blue);
  background-blend-mode: multiply;
}
14

Container Queries

Container-Query-Grundlagen

Container Queries ermöglichen es Komponenten, auf die Größe ihres Containers zu reagieren statt auf den Viewport. container-type: inline-size macht das Element zu einem Query-Container basierend auf seiner Inline-Dimension (Breite). Die @container-Regel wendet Stile an, wenn der Container die Bedingung erfüllt. Dies ist revolutionär für komponentenbasiertes Design — eine Karten-Komponente passt sich an, ob sie in einer Sidebar oder einem vollbreiten Main-Bereich ist, unabhängig von der Bildschirmgröße. Dies löst die grundlegende Einschränkung von Media Queries, die nur auf die Viewport-Größe reagieren.

css
/* Define a container */
.card-container {
  container-type: inline-size;
  /* or: container-type: size; (both dimensions) */
}

/* Query the container's size */
@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
  }
}

@container (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
}

Benannte Container

Benannte Container ermöglichen es, spezifische Container anzusteuern, wenn mehrere verschachtelt sind. container-name gibt dem Container ein Label; @container name (condition) fragt nur diesen Container ab. Dies verhindert Konflikte, wenn Komponenten mit unterschiedlichen Container-Kontexten verschachtelt sind. Die container-Kurzform kombiniert Name und Typ: container: panel / inline-size. Benannte Container sind essenziell für komplexe Layouts, in denen mehrere unabhängige Container-Queries koexistieren. Ohne Namen fragt @container den nächsten Vorfahren-Container ab.

css
/* Name a container for specific queries */
.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

.main-content {
  container-type: inline-size;
  container-name: main;
}

/* Query specific container by name */
@container sidebar (min-width: 300px) {
  .widget { display: grid; grid-template-columns: 1fr 1fr; }
}

@container main (min-width: 600px) {
  .article { columns: 2; }
}

/* Shorthand: container: name / type */
.panel {
  container: panel / inline-size;
}

Container-Query-Einheiten

Container-Query-Einheiten (cqw, cqh, cqmin, cqmax) sind wie Viewport-Einheiten (vw, vh), aber relativ zum Query-Container statt zum Viewport. 1cqw = 1% der Container-Breite. Dies ermöglicht wahrhaft komponenten-responsive Typografie und Abstände — Text skaliert mit der Breite der Komponente, nicht des Bildschirms. Kombiniert mit clamp() erhält man fluide Typografie, die sich an die Container-Größe mit min/max-Grenzen anpasst. Dies ist ideal für Design-Systeme, in denen Komponenten in verschiedenen Layout-Kontexten funktionieren müssen. Hinweis: cqh/cqmin/cqmax erfordern container-type: size (beide Dimensionen).

css
.card {
  container-type: inline-size;
}

.card-title {
  /* cqw: 1% of container width */
  font-size: 5cqw;

  /* cqh: 1% of container height (needs size type) */
  padding: 2cqh;

  /* cqmin: 1% of smaller container dimension */
  margin: 2cqmin;

  /* cqmax: 1% of larger container dimension */
  border-radius: 1cqmax;
}

/* Fluid typography that responds to container */
.headline {
  font-size: clamp(1rem, 8cqw, 3rem);
}

Container-Style-Queries

Container-Style-Queries (experimentell, Stand 2025 nur in Chromium) ermöglichen es, Custom-Property-Werte auf einem Container abzufragen, nicht nur Dimensionen. Dies ermöglicht stilbasiertes bedingtes Rendern: Eine Komponente kann ihr Aussehen basierend auf einer --theme-Variable ändern, die auf ihrem Container gesetzt ist. container-type: style (oder kein container-type nötig für Style-Queries) aktiviert dies. Dies ist mächtig für Theming — setze eine Variable auf ein Eltern-Element und alle Kinder passen sich an. Die volle Browser-Unterstützung steht noch aus; verwende Progressive Enhancement oder @supports-Checks.

css
/* Query custom property values on container */
.card-wrapper {
  container-type: style;
  container-name: card;
}

@container card style(--theme: dark) {
  .card {
    background: #1a1a1a;
    color: #fff;
  }
}

@container card style(--theme: light) {
  .card {
    background: #fff;
    color: #333;
  }
}

/* Set the theme variable */
<div class="card-wrapper" style="--theme: dark">
  <div class="card">...</div>
</div>

Responsive-Komponenten-Muster

Dieses Muster erzeugt eine wahrhaft wiederverwendbare Komponente, die sich an ihre Platzierung anpasst. Die Produktkarte zeigt ein vertikales Layout in schmalen Containern, horizontal in mittleren und ein 3-Spalten-Grid in breiten Containern. Dieselbe Komponente funktioniert in einer Sidebar (schmal), einem Grid (mittel) oder einem Hero (breit) ohne jegliche prop-basierte bedingte Logik. Dies ist der Killer-Use-Case für Container Queries — Komponenten, die genuinely kontextunabhängig sind. Kombiniert mit Container-Query-Einheiten für Typografie erhält man vollständig selbst-adaptierende Komponenten.

css
/* Component that adapts to any container */
.product-card {
  container-type: inline-size;
  container-name: product;
}

.product-card .layout {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Medium container: horizontal layout */
@container product (min-width: 350px) {
  .product-card .layout {
    flex-direction: row;
  }
  .product-card .image {
    width: 40%;
  }
}

/* Large container: full feature layout */
@container product (min-width: 600px) {
  .product-card .layout {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
  }
  .product-card .actions {
    display: flex;
    flex-direction: column;
  }
}
15

Scroll Snap & Scroll-Driven Animations

Scroll-Snap-Grundlagen

Scroll Snap erzeugt magnetisches Scrollen, das Elemente an Snap-Punkten ausrichtet. scroll-snap-type: x/y setzt die Achse; mandatory erzwingt Snapping (landet immer an einem Punkt); proximity snappt nur, wenn nah dran. scroll-snap-align: start/center/end definiert, wo das Kind im Container snappt. Vollseitige Scroll-Sections (wie Präsentationsfolien) verwenden y mandatory mit 100vh-Sections. Horizontale Karussells verwenden x mandatory. Teste immer auf Touch-Geräten — mandatory-Snapping kann restriktiv wirken, wenn Inhalt höher als der Viewport ist. Verwende proximity für nachsichtigeres Verhalten.

css
/* Container with scroll snapping */
.gallery {
  scroll-snap-type: x mandatory;
  overflow-x: auto;
  display: flex;
  gap: 1rem;
}

/* Children snap to positions */
.gallery section {
  scroll-snap-align: start;
  flex: 0 0 100%;
  height: 300px;
}

/* Vertical snapping */
.full-page {
  scroll-snap-type: y mandatory;
  height: 100vh;
  overflow-y: scroll;
}
.full-page section {
  scroll-snap-align: start;
  height: 100vh;
}

Scroll Snap mit Padding

scroll-padding versetzt Snap-Punkte von der Container-Kante — nützlich bei festen Headern oder wenn Rand um gesnappte Items gewünscht wird. scroll-snap-stop: always verhindert, dass schnelles Scrollen mehrere Items überspringt (erzwingt eins-nach-dem-anderen-Snapping). scroll-snap-align: center snappt Items in die Mitte des Containers und erzeugt einen Cover-Flow-Effekt. Diese Eigenschaften bieten feine Kontrolle über das Snap-Verhalten. Für Bildkarussells kombiniere mit scroll-behavior: smooth für animierte Übergänge zwischen Snaps.

css
.carousel {
  scroll-snap-type: x mandatory;
  scroll-padding: 0 20px; /* offset snap points */
  overflow-x: auto;
  display: flex;
  gap: 1rem;
  padding: 0 20px;
}

.carousel .item {
  scroll-snap-align: start;
  scroll-snap-stop: always; /* don't skip items */
  flex: 0 0 80%;
}

/* Center-aligned snapping */
.carousel-center .item {
  scroll-snap-align: center;
  flex: 0 0 60%;
}

Scroll-Driven Animations (animation-timeline)

Scroll-Driven Animations (nur CSS, kein JS!) verknüpfen Animationen mit der Scroll-Position. animation-timeline: scroll() bindet die Animation an den Seiten-Scroll-Fortschritt (0% oben, 100% unten). animation-timeline: view() bindet sie an das Eintreten/Verlassen des Elements im Viewport. animation-range definiert, wann die Animation startet/endet relativ zum Scroll (entry, exit, cover, contain). Dies ermöglicht Scroll-Fortschrittsbalken, Reveal-on-Scroll und Parallax-Effekte ohne JavaScript oder Scroll-Event-Listener. Unterstützt in Chrome 115+, Progressive Enhancement empfohlen für andere Browser.

css
/* Animate as user scrolls */
@keyframes fade-in {
  from { opacity: 0; transform: translateY(50px); }
  to   { opacity: 1; transform: translateY(0); }
}

.reveal {
  animation: fade-in linear;
  animation-timeline: view();
  animation-range: entry 0% cover 40%;
}

/* Progress bar based on scroll position */
.progress-bar {
  position: fixed;
  top: 0; left: 0;
  height: 4px;
  background: #3498db;
  width: 100%;
  transform-origin: left;
  animation: grow linear;
  animation-timeline: scroll();
}

@keyframes grow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

View-Timeline-Bereiche

View-Timeline-Bereiche steuern genau, wann die Animation erfolgt. 'entry' ist, wenn das Element in den Viewport eintritt; 'exit', wenn es ihn verlässt; 'cover' reicht vom Entry-Start bis zum Exit-Ende; 'contain' ist, wenn das Element vollständig sichtbar ist. Prozentangaben verfeinern innerhalb jedes Bereichs. animation-range: entry 10% entry 90% bedeutet, die Animation läuft von 10% in entry bis 90% in entry. Für Sticky-Header animiert scroll() mit einem Pixel-Bereich (0 200px) basierend auf absoluter Scroll-Distanz. Dies ersetzt komplexe JavaScript-Scroll-Handler durch deklaratives CSS.

css
/* Element animates as it enters viewport */
@keyframes slide-up {
  from { opacity: 0; transform: translateY(100px); }
  to   { opacity: 1; transform: translateY(0); }
}

.section {
  animation: slide-up linear both;
  animation-timeline: view();
  /* Ranges: entry, exit, cover, contain */
  animation-range: entry 10% entry 90%;
}

/* Sticky header that shrinks on scroll */
.header {
  position: sticky;
  top: 0;
  animation: shrink linear both;
  animation-timeline: scroll();
  animation-range: 0 200px;
}
@keyframes shrink {
  to { padding: 0.5rem 1rem; font-size: 0.9em; }
}

scroll-behavior & smooth scroll

scroll-behavior: smooth auf html (oder einem beliebigen Scroll-Container) lässt Anker-Link-Navigation und scrollIntoView() sanft animieren statt zu springen. Dies ist ein Einzeiler-Ersatz für JavaScript-Smooth-Scroll-Bibliotheken. Respektiere immer prefers-reduced-motion — einige Nutzer erleben Bewegungskrankheit, deaktiviere also für sie sanftes Scrollen. scroll-snap-type: proximity (vs. mandatory) passt gut zu sanftem Scrollen für ein natürliches Gefühl. scrollIntoView mit block: 'start'/'center'/'end' steuert die vertikale Ausrichtung des Ziels.

css
/* Smooth scrolling for anchor links */
html {
  scroll-behavior: smooth;
}

/* With scroll snap */
html {
  scroll-behavior: smooth;
  scroll-snap-type: y proximity;
}

/* Target specific elements */
.container {
  scroll-behavior: smooth;
  overflow-y: auto;
}

/* JavaScript: scroll to element */
<script>
document.querySelector(".section-3")
  .scrollIntoView({ behavior: "smooth", block: "start" });

/* Scroll to top */
window.scrollTo({ top: 0, behavior: "smooth" });
</script>

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
16

CSS Counters

Basis-Counter

CSS-Counter nummerieren Elemente automatisch ohne JavaScript. counter-reset initialisiert einen Counter (auf dem Eltern-Element oder einem Vorfahren). counter-increment erhöht ihn (normalerweise auf dem zu nummerierenden Element). counter(name) zeigt den aktuellen Wert in content an. Der Counter übernimmt automatisch die Nummerierung im gesamten Dokument. Dies ist ideal zum Nummerieren von Überschriften, Listen-Items, Abbildungen oder jedem sequenziellen Inhalt. Counter sind auf das Element scopeiert, auf dem sie zurückgesetzt werden, und seine Nachfahren.

css
/* Initialize counter on parent */
body {
  counter-reset: section;
}

/* Increment and display */
h2::before {
  counter-increment: section;
  content: "Section " counter(section) ": ";
  color: #3498db;
  font-weight: bold;
}

/* Result: Section 1: Introduction, Section 2: Methods... */

Verschachtelte Counter

Verschachtelte Counter erzeugen hierarchische Nummerierung (1.1, 1.2, 2.1 usw.). Setze den Unter-Counter auf der Eltern-Überschrift zurück (counter-reset: section auf h2). Jedes h2 startet ein neues Kapitel und setzt den Section-Counter zurück. Jedes h3 erhöht den Section-Counter innerhalb des aktuellen Kapitels. Die content-Eigenschaft kombiniert mehrere counter()-Aufrufe mit Trennzeichen. Dies spiegelt wider, wie Bücher und technische Dokumente nummeriert werden. Die Counter kaskadieren natürlich basierend auf DOM-Struktur und Reset-Punkten.

css
body {
  counter-reset: chapter;
}

h2 {
  counter-reset: section;
  counter-increment: chapter;
}
h2::before {
  content: "Chapter " counter(chapter) ". ";
}

h3 {
  counter-increment: section;
}
h3::before {
  content: counter(chapter) "." counter(section) " ";
}

/* Result: Chapter 1.  / 1.1 / 1.2 / Chapter 2. / 2.1 ... */

Counter-Stile

counter() akzeptiert ein style-Argument: decimal (Standard), decimal-leading-zero (01, 02), lower/upper-alpha (a/b oder A/B), lower/upper-roman (i/ii oder I/II). @counter-style definiert benutzerdefinierte Counter-Stile mit zyklischen Symbolen, additiven Systemen oder symbolischer Notation. system: cyclic wiederholt Symbole; system: additive erzeugt römisch-zahlen-ähnliche Systeme. Benutzerdefinierte Counter-Stile sind mächtig für internationalisierte Listen, benutzerdefinierte Aufzählungspunkte oder dekorative Nummerierung. Die Browser-Unterstützung für @counter-style ist in modernen Browsern gut.

css
/* Different number styles */
ol {
  counter-reset: item;
  list-style: none;
}
li::before {
  counter-increment: item;
  /* decimal, decimal-leading-zero, lower-alpha,
     upper-alpha, lower-roman, upper-roman */
  content: counter(item, upper-roman) ". ";
}

/* Leading zeros: 01, 02, 03... */
li::before {
  content: counter(item, decimal-leading-zero) ". ";
}

/* Custom @counter-style */
@counter-style thumbs {
  system: cyclic;
  symbols: "👍" "👎";
  suffix: " ";
}
.thumbs-list { list-style-type: thumbs; }

counters()-Funktion (verschachtelt)

Die counters()-Funktion (Plural) gibt den vollständigen Counter-Pfad als String zurück, mit Ebenen getrennt durch das angegebene Trennzeichen. Dies behandelt automatisch verschachtelte Counter-Scopes — jedes verschachtelte ol erzeugt einen neuen Counter-Scope. counters(nested, '.') erzeugt 1, 1.1, 1.1.1 für tief verschachtelte Listen. Dies unterscheidet sich von counter(), das nur die aktuelle Ebene anzeigt. Verwende counters() für Outline-artige Nummerierung verschachtelter Listen, Inhaltsverzeichnisse oder hierarchischer Menüs. Der Trennstring kann ein beliebiges Zeichen sein (. , - > usw.).

css
/* counters() creates full path string */
ol {
  counter-reset: nested;
  list-style: none;
}
li::before {
  counter-increment: nested;
  /* counters() returns all levels separated by a string */
  content: counters(nested, ".") " - ";
  font-weight: bold;
}

/* For nested <ol> elements:
   1 - Top level
   1.1 - Nested
   1.1.1 - Deeper
   2 - Top level again
*/

Counter für Abbildungen & Tabellen

Counter sind perfekt zum automatischen Nummerieren von Abbildungen, Tabellen und Gleichungen in Dokumentation. Setze pro Kapitel zurück (counter-reset auf h2), sodass die Nummerierung jedes Kapitel neu startet. Das ::before-Pseudo-Element auf figcaption/caption stellt die Nummer voran. Dies stellt konsistente, automatische Nummerierung sicher, die sich aktualisiert, wenn Inhalt umgeordnet wird. Für Querverweise ('siehe Abbildung 3') können CSS-Counter nicht direkt helfen — man bräuchte JS oder HTML-Anker. Aber für Anzeige-Nummerierung ist dies eine saubere, wartungsfreie Lösung.

css
body {
  counter-reset: figure table;
}

figure figcaption::before {
  counter-increment: figure;
  content: "Figure " counter(figure) ": ";
  font-weight: bold;
  color: #2c3e50;
}

table caption::before {
  counter-increment: table;
  content: "Table " counter(table) ": ";
  font-weight: bold;
  color: #2c3e50;
}

/* Reset figure counter per chapter */
h2 {
  counter-reset: figure;
}
18

Dark Mode & Color Schemes

prefers-color-scheme

prefers-color-scheme: dark erkennt die Dark-Mode-Präferenz des Nutzer-OS/Browsers. Definiere Theme-Variablen in :root für Light-Mode und überschreibe sie dann in der Dark-Media-Query. Die Verwendung von CSS-Variablen bedeutet, dass du nur die Variablenwerte änderst — alle Komponenten aktualisieren sich automatisch. Dies ist der Standardansatz für Dark Mode. Die Media-Query unterstützt auch 'light' und 'no-preference'. Teste durch Umschalten des OS-Dark-Mode oder über den Chrome-DevTools-Rendering-Tab (Emulate CSS prefers-color-scheme).

css
/* Light mode (default) */
:root {
  --bg: #ffffff;
  --text: #1a1a1a;
  --surface: #f5f5f5;
  --border: #e0e0e0;
  --accent: #3498db;
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1a1a1a;
    --text: #e0e0e0;
    --surface: #2a2a2a;
    --border: #404040;
    --accent: #5dade2;
  }
}

body {
  background: var(--bg);
  color: var(--text);
}

Manueller Theme-Toggle

Für manuellen Theme-Toggle verwende ein data-theme-Attribut auf <html>, das die System-Präferenz überschreibt. Speichere die Wahl des Nutzers in localStorage, damit sie persists. Prüfe beim Laden der Seite localStorage vor dem Rendern, um ein Flash des falschen Themes (FOUC) zu vermeiden. color-scheme: light dark teilt dem Browser mit, native UI-Elemente (Scrollbars, Form-Controls) im passenden Schema zu rendern. Für beste UX standardmäßig auf System-Präferenz setzen, wenn keine gespeicherte Wahl existiert: prüfe matchMedia('(prefers-color-scheme: dark)') als Fallback.

css
/* Default to system preference, allow override */
:root {
  color-scheme: light dark;
}

/* Manual dark mode via data attribute */
[data-theme="dark"] {
  --bg: #1a1a1a;
  --text: #e0e0e0;
}

[data-theme="light"] {
  --bg: #ffffff;
  --text: #1a1a1a;
}

/* Toggle button */
<button onclick="toggleTheme()">Toggle Theme</button>
<script>
function toggleTheme() {
  const current = document.documentElement.dataset.theme;
  const next = current === "dark" ? "light" : "dark";
  document.documentElement.dataset.theme = next;
  localStorage.setItem("theme", next);
}
// Load saved preference
const saved = localStorage.getItem("theme");
if (saved) document.documentElement.dataset.theme = saved;
</script>

color-scheme-Eigenschaft

Die color-scheme-Eigenschaft teilt dem Browser mit, welche Farbschemata die Seite unterstützt, und betrifft native UI-Elemente: Scrollbars, Form-Controls (Inputs, Buttons, Dropdowns), Standard-Hintergrund/Canvas-Farbe und die ::placeholder-Farbe. Ohne sie können Form-Controls selbst im Dark Mode hell erscheinen (störender Missklang). Setze color-scheme: light dark auf :root, um native Elemente automatisch adaptieren zu lassen. Dies ist ein Einzeiler-Fix, der die Dark-Mode-Politur drastisch verbessert. Es ist separat von deinem CSS-Variablen-Theming — es betrifft nur browser-natives Rendering.

css
:root {
  /* Tell browser this page supports both schemes */
  color-scheme: light dark;
}

/* Force light only */
.light-only {
  color-scheme: light;
}

/* Force dark only */
.dark-only {
  color-scheme: dark;
}

/* This affects native UI: scrollbars, form controls,
   default colors (canvas, text), and form elements */
input, textarea, select {
  /* Will use dark form controls in dark mode */
  color-scheme: dark;
}

Dark-Mode-Bilder & Medien

Bilder benötigen im Dark Mode besondere Behandlung. Diagramme mit weißem Hintergrund können mit filter: invert(1) hue-rotate(180deg) invertiert werden — der hue-rotate verhindert Farbverzerrung. Fotos von Personen sollten nie invertiert werden. Reduziere die Helligkeit leicht für weniger Augenbelastung. Für Logos und Icons verwende <picture> mit Media-Query-Quellen, um dark-optimierte Versionen zu servieren. SVGs mit currentColor adaptieren automatisch. Für Hintergrundbilder stelle Dark-Mode-Alternativen via Media Queries bereit. Teste Bilder immer in beiden Modi auf Lesbarkeit.

css
@media (prefers-color-scheme: dark) {
  /* Invert images that are essentially white-background */
  img[src*="logo"],
  img[src*="diagram"] {
    filter: invert(1) hue-rotate(180deg);
  }

  /* Reduce brightness of photos */
  img.photo {
    filter: brightness(0.85);
  }

  /* Don't invert photos with people */
  img[src*="photo"]:not(.invertable) {
    filter: none;
  }
}

/* Use dark-mode-friendly SVG */
<picture>
  <source srcset="logo-dark.svg"
          media="(prefers-color-scheme: dark)">
  <img src="logo-light.svg" alt="Logo">
</picture>

Sanfter Theme-Übergang

Das Hinzufügen von Farb-Transitions zu allen Elementen erzeugt eine sanfte Theme-Wechsel-Animation. Dies kann jedoch beim initialen Laden der Seite zu einem Flash animierter Farben führen. Die Lösung: Füge während Theme-Wechseln und beim initialen Laden eine .no-transition-Klasse zu <html> hinzu und entferne sie nach einem Frame. Respektiere immer prefers-reduced-motion, um Transitions für Nutzer zu deaktivieren, die reduzierte Bewegung anfordern. Sei selektiv — das Transitionieren aller Eigenschaften kann die Performance beeinträchtigen. Transitioniere nur farbbezogene Eigenschaften (background-color, color, border-color, box-shadow).

css
/* Transition colors when theme changes */
* {
  transition: background-color 0.3s ease,
              color 0.3s ease,
              border-color 0.3s ease;
}

/* But not during initial load (prevent flash) */
.no-transition * {
  transition: none !important;
}

<script>
// Disable transitions during theme switch
function toggleTheme() {
  document.documentElement.classList.add("no-transition");
  document.documentElement.dataset.theme = newTheme;
  // Re-enable after switch
  requestAnimationFrame(() => {
    document.documentElement.classList.remove("no-transition");
  });
}
</script>

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
19

CSS Functions Deep Dive

clamp(), min(), max()

clamp(min, preferred, max) ist der heilige Gral der fluiden Typografie und Abstände — es skaliert mit dem Preferred-Wert, überschreitet aber nie die min/max-Grenzen. min() wählt den kleineren Wert (ideal für responsives max-width). max() wählt den größeren Wert (ideal für Mindestgrößen). Diese eliminieren viele Media Queries durch kontinuierliche fluide Skalierung. Der Preferred-Wert in clamp verwendet typischerweise Viewport-Einheiten (vw, vh) oder Container-Einheiten (cqw). Dies ist der moderne Ansatz für responsives Design ohne Breakpoints.

css
/* clamp(min, preferred, max) */
h1 {
  font-size: clamp(1.5rem, 5vw, 3rem);
  /* Never smaller than 1.5rem, never larger than 3rem,
     preferred is 5vw */
}

/* min(): use the smaller value */
.container {
  width: min(100% - 2rem, 1200px);
  /* Full width minus padding, but max 1200px */
}

/* max(): use the larger value */
.hero {
  font-size: max(2rem, 4vw);
  /* At least 2rem, grows with viewport */
}

/* Combining for responsive padding */
.card {
  padding: clamp(1rem, 3vw, 2rem);
}

calc() Erweitert

calc() führt Berechnungen mit gemischten Einheiten aus (px, %, em, vw usw.). Addition und Subtraktion erfordern Leerzeichen um den Operator (calc(100% - 20px), nicht calc(100%-20px)). Multiplikation und Division funktionieren nur mit Zahlen, nicht mit Längen (calc(10px * 2) ist gültig; calc(10px * 10px) nicht). calc() kann verschachtelt werden, aber Klammern funktionieren ebenfalls. Kombiniert mit CSS-Variablen ermöglicht calc() dynamische, berechnete Design-Systeme. Es ist essenziell für responsive Layouts, die feste und fluide Dimensionen kombinieren.

css
/* Mixed units */
.sidebar {
  width: calc(100% - 250px); /* full width minus fixed sidebar */
  height: calc(100vh - 60px); /* viewport minus header */
}

/* Nested calc */
.element {
  margin: calc(calc(100% - 50px) / 2);
  /* Simplified: */
  margin: calc((100% - 50px) / 2);
}

/* With CSS variables */
:root { --gap: 20px; }
.grid {
  gap: calc(var(--gap) * 2);
}

/* Math operations: + - * / */
.padding {
  padding: calc(1rem + 2px);
  width: calc(50% - 10px);
}

attr()-Funktion

attr() ruft HTML-Attributwerte ab, am häufigsten verwendet in content für Pseudo-Elemente. Es ist die Basis von CSS-only-Tooltips (data-tooltip-Attribut → ::after-content). attr() funktioniert zuverlässig nur in der content-Eigenschaft. Die Verwendung von attr() für andere Eigenschaften (width, color usw.) mit Typ-Casting (attr(data-size px)) ist Teil von CSS Values Level 5, hat aber minimale Browser-Unterstützung. Verwende vorerst CSS-Variablen für dynamische Werte aus HTML: setze style='--size: 100px' und verwende var(--size).

css
/* Display attribute values */
a[href]::after {
  content: attr(href);
}

/* data attributes for tooltips */
.tooltip::after {
  content: attr(data-tooltip);
  display: none;
  position: absolute;
}
.tooltip:hover::after {
  display: block;
}

/* HTML: <div class="tooltip" data-tooltip="Help text">?</div> */

/* Note: attr() for non-content properties is experimental */
/* This doesn't work widely yet: */
/* .box { width: attr(data-width px); } */

var() mit Fallbacks

var() akzeptiert einen Fallback als zweites Argument, der verwendet wird, wenn die Variable nicht definiert ist. Fallbacks können verkettet werden: var(--a, var(--b, var(--c, default))). Dies ermöglicht Progressive Enhancement und Multi-Level-Theming. Ein leerer Variablenwert (--defined: ;) ist immer noch 'gesetzt', sodass der Fallback nicht auslöst — dies ermöglicht bedingte CSS-Muster. Fallbacks können jeden gültigen CSS-Wert enthalten, einschließlich calc() und andere Funktionen. Verwende Fallbacks für optionale Theme-Variablen, die möglicherweise nicht in allen Kontexten definiert sind.

css
/* Single fallback */
color: var(--text-color, #333);

/* Chained fallbacks */
color: var(--text, var(--default-text, black));

/* Fallback in shorthand */
background: var(--bg, white) url(image.png);

/* Fallback with calc */
width: calc(100% - var(--sidebar, 250px));

/* Check if variable is set */
:root {
  --defined: ; /* empty space = valid value */
}
.conditional {
  --use-default: var(--defined, initial);
  /* If --defined is empty, --use-default = initial */
}

gradient-Funktionen

CSS-Gradienten erzeugen sanfte Übergänge zwischen Farben ohne Bilder. linear-gradient (Richtung + Farben), radial-gradient (vom Zentrum nach außen) und conic-gradient (Rotation um einen Punkt) sind die drei Typen. Harte Stopps (gleicher Prozentwert für zwei Farben) erzeugen scharfe Bänder. repeating-linear-gradient erzeugt Muster wie Streifen. Gradienten können mit mehreren Hintergründen geschichtet werden (komma-getrennt, erste = oberste Schicht). Conic-Gradienten ermöglichen Tortendiagramme und Farbräder in reinem CSS. Gradienten sind auflösungsunabhängig und performen besser als Bilddateien.

css
/* Linear gradient */
.bg { background: linear-gradient(45deg, #3498db, #e74c3c); }
.bg2 { background: linear-gradient(to right, red, orange, yellow); }

/* Radial gradient */
.radial { background: radial-gradient(circle, white, blue); }
.radial2 { background: radial-gradient(circle at top left, #fff, #000); }

/* Conic gradient */
.pie { background: conic-gradient(red 0% 30%, blue 30% 70%, green 70% 100%); }

/* Repeating gradients */
.stripes { background: repeating-linear-gradient(45deg, #ccc 0 10px, #fff 10px 20px); }

/* Hard color stops (sharp edges) */
.hard { background: linear-gradient(to right, #000 50%, #fff 50%); }

/* Multiple backgrounds */
.multi {
  background:
    linear-gradient(rgba(0,0,0,0.5), transparent),
    url(photo.jpg);
}
20

CSS Variables

Variablen definieren & verwenden

CSS Custom Properties (Variablen) werden mit --name definiert und mit var() verwendet. Deklariere sie auf :root für globalen Zugriff. Im Gegensatz zu Sass-Variablen sind sie live — das Ändern einer Variable via JavaScript aktualisiert sofort jedes Element, das sie verwendet.

css
:root {
  --primary: #3498db;
  --spacing: 16px;
  --radius: 8px;
}

.button {
  background: var(--primary);
  padding: var(--spacing);
  border-radius: var(--radius);
}

Fallback-Werte

var() akzeptiert ein zweites Argument als Fallback, wenn die Variable undefiniert ist. Fallbacks können verschachtelt werden, sodass man Defaults verketten kann. Für Browser, die keine Custom Properties unterstützen, deklariere zuerst einen normalen Wert und überschreibe dann mit var().

css
.box {
  color: var(--brand, #333);
  background: var(--bg, var(--default-bg, white));
}

/* Provide fallback for older browsers */
.element {
  color: #333;
  color: var(--text-color, #333);
}

JavaScript-Interaktion

JavaScript liest Variablen via getComputedStyle().getPropertyValue() und setzt sie mit setProperty(). Dies macht Laufzeit-Theming trivial — kippe ein paar Variablen, um die gesamte App neu zu stylen.

css
// Read a variable
const color = getComputedStyle(document.documentElement)
  .getPropertyValue('--primary');

// Set a variable on an element
document.documentElement.style.setProperty('--primary', '#e74c3c');

// Toggle a theme
document.documentElement.setAttribute('data-theme', 'dark');

Scoping & Vererbung

Custom Properties vererben, sodass eine auf :root gesetzte Variable zu jedem Element kaskadiert. Neudefinieren auf .card überschreibt sie nur für diesen Teilbaum. Dieses Scoping ermöglicht Theming auf Komponenten-Ebene ohne Spezifitäts-Kriege.

css
:root { --size: 16px; }

.card {
  --size: 20px; /* Overrides only within .card */
  font-size: var(--size);
}

.card .text { font-size: var(--size); } /* 20px */
.other { font-size: var(--size); }       /* 16px */

Responsive Variablen

Redefiniere Variablen innerhalb von Media Queries, um das gesamte Layout auf Breakpoints reagieren zu lassen, ohne Regeln neu zu schreiben. Ändere eine Variable und jedes Element, das sie verwendet, adaptiert — weitaus sauberer, als jede Eigenschaft einzeln zu überschreiben.

css
:root {
  --container-width: 1200px;
  --font-size: 18px;
}

@media (max-width: 768px) {
  :root {
    --container-width: 100%;
    --font-size: 16px;
  }
}

.container { max-width: var(--container-width); }
body { font-size: var(--font-size); }
21

Animations & Keyframes

@keyframes & Animation-Kurzform

@keyframes definiert den Start- (from/0%) und Endzustand (to/100%) einer Animation. Die animation-Kurzform kombiniert name, duration, timing-function, delay, iteration-count, direction, fill-mode und play-state. forwards behält den Endzustand.

css
@keyframes slide-in {
  from { transform: translateX(-100%); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}

.element {
  animation: slide-in 0.5s ease-out forwards;
}

/* Shorthand: name duration timing delay count direction fill-mode */
.bounce {
  animation: bounce 1s cubic-bezier(0.68, -0.55, 0.27, 1.55) 0s infinite alternate;
}

Transitions

Transitions interpolieren sanft zwischen Eigenschaftswerten, wenn diese sich ändern. Gib an, welche Eigenschaften transitionieren und ihre Duration/Timing. transition: all ist bequem, kann aber die Performance beeinträchtigen — liste besser spezifische Eigenschaften auf.

css
.button {
  background: blue;
  transition: background 0.3s ease, transform 0.2s ease-out;
}

.button:hover {
  background: darkblue;
  transform: scale(1.05);
}

/* Transition all changed properties */
.card { transition: all 0.3s ease; }

Timing-Funktionen

Timing-Funktionen steuern die Beschleunigungskurve. ease-out startet schnell und verlangsamt (gut für Eintritte); ease-in startet langsam und beschleunigt (gut für Austritte). cubic-bezier lässt dich benutzerdefinierte Kurven gestalten. steps() erzeugt einen diskreten Effekt.

css
/* Built-in */
.ease-linear { transition: all 1s linear; }
.ease-out    { transition: all 1s ease-out; }

/* Custom cubic-bezier(x1, y1, x2, y2) */
.custom { transition: all 1s cubic-bezier(0.68, -0.55, 0.27, 1.55); }

/* Steps */
.steps { transition: all 1s steps(5, end); }

Animations-Events

JavaScript kann auf animationstart, animationiteration (feuert bei jedem Loop) und animationend lauschen. Steuere die Wiedergabe mit der animation-play-state-Eigenschaft (paused/running). Kombiniere mit animationend, um Animationen zu verketten.

css
const el = document.querySelector('.animate');
el.addEventListener('animationstart', () => console.log('Started'));
el.addEventListener('animationiteration', () => console.log('Looped'));
el.addEventListener('animationend', () => console.log('Finished'));

// Pause and resume
el.style.animationPlayState = 'paused';
el.style.animationPlayState = 'running';

Performance: transform & opacity

Animiere nur transform und opacity für 60fps-Performance — sie laufen auf der GPU, ohne Layout auszulösen. Das Animieren von width, height, top oder margin erzwingt jedes Frame eine Layout-Neuberechnung. Verwende will-change sparsam, um den Browser zu hinweisen.

css
/* GOOD: GPU-accelerated, cheap */
.fade { transition: opacity 0.3s; }
.move { transition: transform 0.3s; }

/* BAD: triggers layout/paint, expensive */
.resize { transition: width 0.3s, height 0.3s; }

/* Hint the browser to optimize */
.card { will-change: transform; }
22

Transforms 3D

2D-Transforms

2D-Transforms verschieben, rotieren, skalieren und verzerren Elemente, ohne das umgebende Layout zu beeinflussen. Transforms werden auf der GPU komponiert, was sie performant für Animationen macht. Die Reihenfolge ist wichtig: rotate dann translate bewegt sich entlang der rotierten Achse.

css
.box { transform: translate(50px, 20px); }
.box { transform: rotate(45deg); }
.box { transform: scale(1.5); }
.box { transform: skew(20deg, 10deg); }

/* Combined — order matters */
.combo { transform: translate(100px, 0) rotate(90deg) scale(1.2); }

3D-Transforms & Perspective

3D-Transforms fügen rotateX, rotateY, rotateZ, translateZ und scaleZ hinzu. perspective auf einem Eltern-Element gibt allen Kindern einen gemeinsamen Fluchtpunkt — niedrigere Werte übertreiben den 3D-Effekt. transform-style: preserve-3d behält verschachtelte Elemente im 3D.

css
.scene { perspective: 1000px; }

.card {
  transform: rotateY(45deg);
  transform-style: preserve-3d;
}

/* Perspective on the element itself */
.self { transform: perspective(800px) rotateX(30deg); }

/* Transform origin */
.pivot { transform-origin: top left; transform: rotate(45deg); }

Flip-Card-Effekt

Die klassische Flip-Card verwendet preserve-3d auf einem Container mit vorne und hinten absolut positionierten Faces. backface-visibility: hidden verbirgt die Rückseite jedes Faces. Das hintere Face ist vorrotiert um 180deg, sodass es sichtbar wird, wenn der Container kippt.

css
.card { perspective: 1000px; }
.inner {
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.6s;
}
.card:hover .inner { transform: rotateY(180deg); }
.front, .back {
  position: absolute;
  backface-visibility: hidden;
}
.back { transform: rotateY(180deg); }

Würfel mit 6 Faces

Ein 3D-Würfel wird aus sechs Faces gebaut, jeweils um 50px (halbe Würfelbreite) entlang ihrer Achse nach außen verschoben. preserve-3d behält die Faces im 3D-Raum positioniert. Animiere den Würfel-Transform, um ihn zu drehen.

css
.cube {
  position: relative;
  width: 100px; height: 100px;
  transform-style: preserve-3d;
  transform: rotateX(-20deg) rotateY(30deg);
}
.face { position: absolute; width: 100px; height: 100px; }
.front  { transform: translateZ(50px); }
.back   { transform: rotateY(180deg) translateZ(50px); }
.right  { transform: rotateY(90deg) translateZ(50px); }
.left   { transform: rotateY(-90deg) translateZ(50px); }
.top    { transform: rotateX(90deg) translateZ(50px); }
.bottom { transform: rotateX(-90deg) translateZ(50px); }

Matrix & Performance

matrix() und matrix3d() drücken jeden Transform als einzelne Matrix aus — nützlich, wenn Transforms in JavaScript berechnet werden. translateZ(0) oder will-change: transform erzwingen GPU-Beschleunigung und verbessern die Animations-Weichheit. Vermeide übermäßige Layer-Nutzung.

css
/* matrix(a, b, c, d, e, f) encodes translate, rotate, scale, skew */
.transformed { transform: matrix(1, 0, 0, 1, 100, 50); }

/* 3D matrix */
.cube { transform: matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); }

/* Hardware acceleration hint */
.gpu { transform: translateZ(0); }
23

CSS Grid Advanced

Grid Template Areas

grid-template-areas benennt Grid-Zellen visuell und macht die Layout-Absicht offensichtlich. Jede zitierte Zeile repräsentiert eine Grid-Zeile; identische Namen überspannen Zellen. Leere Zellen verwenden einen Punkt (.). Areas müssen Rechtecke bilden — L-Formen sind ungültig.

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  gap: 16px;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main   { grid-area: main; }
.footer { grid-area: footer; }

minmax & auto-fit

repeat(auto-fit, minmax(200px, 1fr)) erzeugt ein responsives Grid ohne Media Queries: Spalten sind mindestens 200px und strecken sich, um die Zeile zu füllen. auto-fit klappt leere Spuren zusammen; auto-fill behält sie reserviert.

css
.grid {
  display: grid;
  /* Columns auto-fit, each at least 200px, sharing leftover space */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 20px;
}

/* Fixed number that wraps */
.wrap {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

Grid-Ausrichtung

Grid-Ausrichtung funktioniert auf zwei Ebenen: dem Container (justify/align-items und justify/align-content) und dem Item (justify/align-self). justify-* steuert die Inline-Achse, align-* die Block-Achse. place-items: center ist die Kurzform für beide.

css
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  justify-items: center;
  align-items: center;
  justify-content: space-between;
  align-content: center;
}

.item {
  justify-self: end;
  align-self: start;
}

Spanning & Linien-Platzierung

Platziere Items nach Grid-Liniennummer (1 / 3 bedeutet von Linie 1 bis Linie 3) oder nach Span (span 2). Negative Linien zählen vom Ende (-1 ist die letzte Linie). grid-column: 1 / -1 lässt ein Item die volle Breite überspannen.

css
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
.header { grid-column: 1 / -1; }       /* full width */
.sidebar { grid-column: 1 / 3; }       /* columns 1-2 */
.main { grid-column: span 2; }          /* span 2 columns */
.tall { grid-row: 1 / span 2; }         /* span 2 rows */

Subgrid

subgrid lässt ein Kind-Grid die Eltern-Spurdefinitionen erben, sodass Spalten oder Zeilen über verschachtelte Grids hinweg perfekt ausgerichtet bleiben. Ohne subgrid definieren verschachtelte Grids eigene Spuren und können fehlalignieren. Seit 2023 in allen modernen Browsern unterstützt.

css
.card {
  display: grid;
  grid-template-rows: auto 1fr auto;
  /* Inherit column tracks from parent */
  grid-template-columns: subgrid;
  grid-column: span 3;
}

.parent {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
}
24

CSS Functions

calc()

calc() führt Mathematik mit gemischten Einheiten aus (px, %, vw, em, rem). Umschließe + und - immer mit Leerzeichen (calc(100%-20px) schlägt fehl; calc(100% - 20px) funktioniert). Multiplikation und Division benötigen auf einer Seite eine einheitenlose Zahl.

css
.sidebar {
  width: calc(100% - 250px);
  padding: calc(16px + 2vw);
  font-size: calc(14px + 0.5vw);
}

/* Nested calc */
.full { width: calc(calc(100% - 20px) / 2); }

/* With variables */
.box { margin: calc(var(--gap) * 2); }

clamp()

clamp() begrenzt einen Wert zwischen einem Minimum und Maximum mit einem Preferred-Wert in der Mitte. Es ist die sauberste Methode, fluide Typografie und Abstände zu bauen — der Wert skaliert, geht aber nie unter oder über die Grenzen.

css
/* clamp(MIN, PREFERRED, MAX) */
h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
}

.sidebar {
  width: clamp(200px, 25vw, 400px);
}

.padding {
  padding: clamp(1rem, 2vw + 1rem, 2rem);
}

min() & max()

min() gibt das kleinste Argument zurück; max() das größte. Im Gegensatz zu clamp (das genau drei Werte nimmt) akzeptieren min/max eine beliebige Anzahl von Argumenten. Verwende min(), um einen Wert zu deckeln, und max(), um einen Wert zu boden.

css
/* Picks the smallest/largest of comma-separated values */
.box {
  width: min(100% - 32px, 800px);
  font-size: max(16px, 2vw);
}

/* With multiple units */
.responsive {
  padding: min(5vw, 2rem);
  margin: max(1rem, 3vw);
}

var() mit Fallbacks

var()s zweites Argument wird nur verwendet, wenn die Custom Property undefiniert ist. Bei ungültigen Werten fällt die Eigenschaft auf ihren geerbten oder Initialwert zurück. Verschachtle var()-Aufrufe, um Fallbacks zu verketten.

css
.button {
  background: var(--btn-bg, #007bff);
  color: var(--text, var(--default-text, black));
  width: var(--width, 100%);
}

color-mix() & Farbfunktionen

color-mix() mischt zwei Farben in einem angegebenen Farbraum (srgb, oklch, lab). Es ist die moderne Methode, Tints und Shades aus einer Brand-Farbe abzuleiten. Relative Farbsyntax (from-Keyword) lässt dich einzelne Kanäle anpassen.

css
/* Mix two colors */
.muted { color: color-mix(in srgb, red 30%, blue); }

/* Adjust relative lightness */
.lighter { background: color-mix(in oklch, var(--brand) 70%, white); }
.darker  { background: color-mix(in oklch, var(--brand) 70%, black); }

/* Relative color syntax (newest) */
.tint { background: oklch(from var(--brand) calc(l + 0.1) c h); }
25

Scroll-Driven Animations

animation-timeline-Grundlagen

animation-timeline: scroll(root) bindet eine Animation an die Seiten-Scroll-Position — während der Nutzer scrollt, schreitet die Animation fort. Kein JavaScript nötig. Dies ist weitaus flüssiger als Scroll-Event-Listener.

css
@keyframes grow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.progress-bar {
  animation: grow linear;
  animation-timeline: scroll(root);
  transform-origin: left;
}

view()-Timeline

view() erzeugt eine Timeline, die an das Eintreten und Verlassen eines Elements im Viewport gebunden ist. animation-range steuert, welcher Teil des Eintritts die Animation auslöst. Perfekt für Scroll-Reveal-Effekte ohne IntersectionObserver.

css
@keyframes reveal {
  from { opacity: 0; transform: translateY(40px); }
  to   { opacity: 1; transform: translateY(0); }
}

.card {
  animation: reveal linear;
  animation-timeline: view();
  animation-range: entry 0% entry 100%;
}

Scroll-verknüpfte Fortschrittsleiste

Eine feste Fortschrittsleiste, die sich füllt, während du die Seite scrollst. animation-timeline: scroll(root) mappt den Seiten-Scroll auf den Animationsbereich 0-100%. transform-origin: 0 50% lässt die Leiste von links wachsen.

css
body { min-height: 200vh; }
.progress {
  position: fixed;
  top: 0; left: 0;
  height: 4px;
  width: 100%;
  background: linear-gradient(to right, #6366f1, #ec4899);
  transform-origin: 0 50%;
  animation: scale-x linear;
  animation-timeline: scroll(root);
}
@keyframes scale-x {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

Benannte Scroll-Timelines

Wenn du eine Animation an ein spezifisches scrollbares Element (nicht das Root) binden willst, definiere scroll-timeline-name auf dem Container und referenziere es in animation-timeline. scroll-timeline-axis wählt, welche Achse verfolgt wird (block/inline/x/y).

css
.scroll-container {
  scroll-timeline-name: --cards;
  scroll-timeline-axis: block;
  overflow-y: scroll;
  height: 400px;
}

.card {
  animation: fade-in linear;
  animation-timeline: --cards;
}

@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

View-Bereichs-Anpassungen

animation-range verfeinert, wann die Animation relativ zur Element-Sichtbarkeit läuft. cover 0% bis cover 100% reicht vom Eintreten des Elements bis zum vollständigen Verlassen. contain 0% bis 100% reicht nur, während es vollständig innen ist.

css
.image {
  animation: parallax linear;
  animation-timeline: view();
  animation-range: cover 0% cover 100%;
}

@keyframes parallax {
  from { transform: translateY(-20%); }
  to   { transform: translateY(20%); }
}

/* Only animate while in view */
.pulse {
  animation: pulse 1s infinite;
  animation-timeline: view();
  animation-range: contain 0% contain 100%;
}
26

CSS Layers

@layer definieren

@layer gruppiert Stile in benannte Kaskaden-Layer. Die Reihenfolge in der Deklarationszeile setzt die Priorität: spätere Layer gewinnen über frühere, unabhängig von der Selektor-Spezifität. Dies bringt vorhersagbare Ordnung in große Stylesheets.

css
@layer reset, base, components, utilities;

@layer reset {
  * { margin: 0; padding: 0; box-sizing: border-box; }
}

@layer base {
  body { font-family: sans-serif; line-height: 1.6; }
}

@layer utilities {
  .hidden { display: none !important; }
}

Layer-Priorität

Innerhalb von Layern gelten normale Spezifitätsregeln. Aber über Layer hinweg gewinnen spätere Layer immer — eine einzelne Klasse in components schlägt eine ID in base. Unlayered-Stile haben Priorität über allen layered-Stilen.

css
@layer base, components;

@layer base {
  /* Even though this is more specific, base loses */
  div.button { color: black; }
}

@layer components {
  .button { color: blue; } /* This wins */
}

/* Unlayered styles always beat layered styles */
.button { color: red; }

In Layer importieren

@import ... layer(name) platziert ein gesamtes Stylesheet in einen benannten Layer. Dies ist essenziell, um Third-Party-CSS zu bändigen: setze Bootstrap in einen vendor-Layer, und deine Custom-Stile (in einem späteren Layer oder unlayered) werden immer gewinnen.

css
@import url("reset.css") layer(reset);
@import url("bootstrap.css") layer(vendor);

@layer reset, vendor, custom;

@layer custom {
  .btn { background: hotpink; }
}

Verschachtelte Layer

Layer können verschachtelt werden und eine Hierarchie bilden. framework.theme referenziert den theme-Unter-Layer innerhalb von framework. Verschachtelte Layer folgen denselben Prioritätsregeln: innerhalb von framework schlägt theme base.

css
@layer framework {
  @layer base, theme;

  @layer base {
    .btn { padding: 8px; }
  }
  @layer theme {
    .btn { color: navy; }
  }
}

/* Reference nested layer */
@layer framework.theme {
  .btn { color: hotpink; }
}

Layer-Bedingungslogik

@layer-Blöcke können innerhalb von @media und @supports verschachtelt werden, sodass die Layer-Zugehörigkeit sich an Bedingungen anpasst. Dies hält Feature-spezifische Stile innerhalb ihres Layers organisiert, statt in den unlayered-Raum auszulaufen.

css
@layer base, components;

@media (max-width: 600px) {
  @layer components {
    .nav { flex-direction: column; }
  }
}

@supports (display: grid) {
  @layer components {
    .layout { display: grid; }
  }
}
27

Backdrop Filters

backdrop-filter-Grundlagen

backdrop-filter wendet einen Filter auf den Inhalt hinter einem Element an und erzeugt Frosted-Glass-Effekte. Schließe immer das -webkit-Präfix für Safari ein. Kombiniere mit einem halbtransparenten Hintergrund, sodass der Blur sichtbar wird.

css
.glass {
  background: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 12px;
}

Mehrere Filter

Verkette mehrere Filter leerzeichen-getrennt: blur, brightness, contrast, grayscale, hue-rotate, invert, opacity, saturate, sepia. Jeder wirkt auf den Backdrop. Kombiniere mit einem getönten Hintergrund, um die Stimmung zu lenken.

css
.vibrant {
  backdrop-filter: blur(8px) saturate(180%) brightness(1.1);
}

.dark-glass {
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(12px) grayscale(50%);
}

Blend-Modi

mix-blend-mode steuert, wie ein Element mit dem Inhalt darunter verschmilzt (separat von backdrop-filter). multiply verdunkelt, screen hellt auf, difference invertiert. Sei vorsichtig mit der Text-Lesbarkeit.

css
.overlay {
  background: rgba(255, 0, 100, 0.3);
  backdrop-filter: blur(4px);
  mix-blend-mode: multiply;
}

.difference {
  background: white;
  mix-blend-mode: difference;
  backdrop-filter: invert(1);
}

Performance & Fallbacks

backdrop-filter ist GPU-intensiv, besonders bei großen Blur-Radien. Biete einen soliden Hintergrund-Fallback für Browser ohne Unterstützung und erweitere dann mit @supports. Vermeide das Animieren von backdrop-filter — es kann starkes Ruckeln verursachen.

css
/* Fallback for unsupported browsers */
.glass {
  background: rgba(255, 255, 255, 0.9);
}

/* Progressive enhancement */
@supports (backdrop-filter: blur(10px)) {
  .glass {
    background: rgba(255, 255, 255, 0.2);
    backdrop-filter: blur(10px);
  }
}

Glassmorphism-Karte

Eine klassische Glassmorphism-Karte kombiniert einen transluzenten Hintergrund, Backdrop-Blur, eine dezente helle Border (Kantenreflexion simulierend) und einen weichen Schatten. Der saturate-Filter verstärkt die durch das Glas sichtbaren Farben.

css
.card {
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(16px) saturate(180%);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
  padding: 24px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}

Was this helpful?

Learning path

Learn from scratch

Learn this language from the ground up with structured lessons.