CSS-Positionierung und Koordinatensysteme

Die meisten Tutorials sagen dir, was position: absolute tut. Dieser zeigt dir, wie es denkt -- als Koordinatensystem mit Ursprung, Achsen und Containing Block.

Live-Demo: Positionierungsmodi Umschalten

Waehle einen position-Wert und ziehe die Schieberegler. Die rote Box positioniert sich neu und die Koordinatenanzeige zeigt dir genau, wo ihr Ursprungspunkt liegt und wie top/left sich in Pixel-Verschiebungen uebersetzen. Das ist der schnellste Weg, den Unterschied zwischen relative und absolute zu verinnerlichen.

10px 10px
Container (position: relative)
Box
Ursprung: Containing-Block oben-links
position: relative | top: 10px left: 10px

Positionierung als Koordinatensystem, Nicht als Layout-Regel

Hier ist der mentale Wechsel, der CSS-Positionierung zum Klick bringt: top, right, bottom und left sind Koordinaten, keine Margins. Wenn du top: 50px schreibst, platzierst du das Element 50 Pixel unter einem spezifischen Ursprungspunkt. Die Frage ist: Ursprung von was?

Jedes positionierte Element lebt innerhalb eines Containing Blocks -- der Box, die seinen Koordinatenursprung definiert. Stell es dir als den (0, 0)-Punkt fuer dieses Element vor. Der Containing Block ist unterschiedlich, je nachdem, welchen position-Wert du verwendest, und das ist die einzige verwirrendste Sache an CSS-Positionierung.

Bei position: absolute und position: fixed wird das Element vollstaendig aus dem normalen Dokumentfluss entfernt. Seine Koordinaten werden gegen den Containing Block gemessen, nicht gegen seine Geschwister oder Eltern im normalen Fluss. Deshalb kann ein absolut positioniertes Element anderen Inhalt ueberlappen -- es hat das Koordinatensystem des Dokumentflusses verlassen.

Die Fuenf position-Werte, Aus Koordinaten-Perspektive

WertKoordinatenursprung (Containing Block)Im Normalfluss?Haeufige Verwendung
static (Standard)Kein Ursprung -- top/left werden ignoriertJa, folgt der DokumentreihenfolgeAlles, was keine explizite Positionierung braucht
relativeDie urspruengliche Position des Elements im FlussJa, aber visuell verschoben (urspruenglicher Raum bleibt erhalten)Feinabstimmung, Containing Block fuer Kinder erstellen
absoluteNaechster positionierter Vorfahr (beliebiger nicht-static), oder der anfaengliche Containing BlockNein -- aus dem Fluss entfernt, andere Elemente fuellen seinen PlatzTooltips, Abzeichen, Overlays relativ zum Eltern-Element
fixedDer Viewport (Browser-Fenster), es sei denn ein Vorfahr hat transform/filter/perspectiveNein -- aus dem Fluss entferntFixe Navigationsleisten, schwebende Buttons, Cookie-Banner
stickyNaechster scrollender Vorfahr; wechselt zwischen fluss-relativ und fixed beim ScrollenJa, bis die Scroll-Schwelle erreicht istTabellen-Ueberschriften, beim Scrollen haftende Bereichsnavigation

Die obige Tabelle ist die Referenz. Nun entpacken wir die drei Dinge, die die meisten Verwirrung in der Praxis verursachen.

Containing Block: Das Konzept, das die Meisten Tutorials Ueberspringen

Wenn du eine Sache von dieser Seite mitnimmst, dann diese: position: absolute ist nicht relativ zum Eltern-Element. Es ist relativ zum naechsten positionierten Vorfahr -- dem ersten Vorfahren beim Hinaufsteigen im Baum, der position auf etwas anderes als static gesetzt hat.

Das legt jeden beim ersten Mal herein. Du setzt position: absolute auf ein Kind, setzt top: 0; left: 0;, und das Element fliegt in die Ecke der Seite statt in die Ecke des Eltern-Elements. Der Grund: Das Eltern-Element hat position: static (Standard), also geht der Browser im Baum nach oben, sucht einen positionierten Vorfahr, findet keinen und verwendet den Viewport als Containing Block.

I am lost

Die Loesung ist immer dieselbe: Fuege position: relative zum Eltern-Element hinzu. Das etabliert das Eltern-Element als Containing Block, und jetzt werden top/left des Kindes von der Padding-Kante des Eltern-Elements gemessen.

I am anchored

Faustregel: Wenn du position: absolute bei einem Kind verwendest, braucht das Eltern-Element fast sicher position: relative ohne Versatz. Dieses Muster -- relative Eltern, absolute Kind -- ist das Arbeitstier der Overlay-, Tooltip- und Abzeichen-Positionierung.

Die transform-Positionierungsfalle

Hier ist eine Falle, die Entwickler stundenlang gekostet hat: Wenn du transform, perspective, filter, backdrop-filter, will-change: transform oder contain: paint auf ein Element setzt, wird es zum Containing Block fuer alle Nachfahren mit position: fixed. Nicht nur direkte Kinder -- jegliche Nachfahren.

Das bedeutet, deine fix-positionierte Navigationsleiste scrollt ploetzlich mit der Seite statt stehen zu bleiben, weil irgendein Vorfahr 10 Ebenen hoeher ein transform: translateZ(0) fuer GPU-Beschleunigung hat. Die Loesung ist zu verstehen, was Containing Blocks erstellt:

/* This ancestor looks innocent... */
.site-wrapper {
  transform: translateZ(0); /* GPU optimization */
}

/* ...but it hijacks fixed positioning for ALL descendants */
.nav {
  position: fixed;
  top: 0;
  /* BUG: this is now relative to .site-wrapper,
     not the viewport. It scrolls with the page. */
}

Die Eigenschaften, die einen Containing Block fuer position: fixed-Nachfahren erstellen: transform, perspective, filter, backdrop-filter (wo unterstuetzt), will-change mit Wert transform/perspective/filter und contain: paint oder contain: layout. Wenn dein fixed-Element sich falsch verhaelt, gehe im DOM-Baum nach oben und pruefe auf diese Eigenschaften.

Stacking Contexts: Das Z-Achsen-Koordinatensystem

Positionierung handhabt X und Y. z-index handhabt Z -- aber es funktioniert nicht so, wie die meisten denken. z-index funktioniert nur innerhalb eines Stacking Contexts (Schichtkontexts), und ein Stacking Context ist nicht dasselbe wie das Dokument.

Stell dir einen Stacking Context als isolierte Ebene vor. Elemente darin koennen relativ zueinander gestapelt werden, aber die gesamte Ebene wird als Einheit gegen andere Ebenen positioniert. Also kann ein z-index: 9999 innerhalb eines Stacking Contexts immer noch hinter einem z-index: 1 in einem anderen, hoeheren Stacking Context liegen.

Was erstellt einen Stacking Context?

Die praktische Konsequenz: Wenn dein Modal mit z-index: 9999 hinter einem Dropdown mit z-index: 10 erscheint, liegt das fast sicher daran, dass das Modal in einem Stacking Context ist (erstellt durch transform oder opacity bei einem Vorfahr), der selbst unter dem Stacking Context des Dropdowns liegt. Du kannst das nicht beheben, indem du den z-index des Modals hoeher setzt -- du musst das Modal aus dem Stacking Context des Vorfahren herausbewegen oder die Eigenschaft entfernen.

Viewport-Einheiten und Responsives Positionieren

Wenn du position: fixed oder position: absolute mit Prozent-Versaetzen verwendest, sind diese Prozente relativ zu den Dimensionen des Containing Blocks, nicht zur Groesse des Elements selbst. top: 50% bedeutet 50% der Hoehe des Containing Blocks.

Viewport-Einheiten ermoeglichen Positionierung relativ zum tatsaechlichen Browser-Fenster:

EinheitRelativ ZuAnwendungsfall
vw / vh1% der Viewport-Breite / -HoeheVollbild-Overlays, fixe Seitenleisten
dvw / dvh1% des dynamischen Viewports (beruecksichtigt mobile URL-Leiste)Mobile-first fixe Positionierung -- vermeidet den iOS Safari URL-Leisten-Sprung
svw / svh1% des kleinstmoeglichen ViewportsElemente, die nie hinter Browser-UI versteckt werden duerfen
lvw / lvh1% des groesstmoeglichen ViewportsWenn du randlose Hintergrundbilder willst

Die dvh / dvw / svh / lvh-Einheiten sind neuer und loesen das mobile Safari-Problem, bei dem 100vh den Bereich hinter der URL-Leiste einschliesst, was dazu fuehrt, dass Inhalt abgeschnitten wird. Verwende 100dvh statt 100vh fuer Elemente, die den sichtbaren Viewport fuellen sollen.

Wirklich Funktionierende Praxis-Muster

Zentriertes Modal-Overlay

Das Muster fuer ein zentriertes Modal, das ueberall funktioniert. Der Schluessel ist die Kombination von position: fixed mit inset: 0 (Kurzform fuer alle vier Seiten) und place-items: center:

.modal-backdrop {
  position: fixed;
  inset: 0; /* top:0; right:0; bottom:0; left:0 */
  background: rgba(0,0,0,.5);
  display: grid;
  place-items: center; /* centers the modal */
  z-index: 1000;
}
.modal {
  background: #fff;
  border-radius: 12px;
  padding: 2rem;
  max-width: 90vw;
  max-height: 90vh;
  overflow: auto;
}

Sticky Tabellen-Kopfzeile

position: sticky auf einer Tabellen-Kopfzeile ist der sauberste Weg, Spalten-Beschriftungen beim Scrollen sichtbar zu halten. Der Trick: top: 0 definiert, wann sie haftet, und der Scroll-Container muss der Scroll-Parent der Tabelle sein:

.table-scroll {
  max-height: 400px;
  overflow: auto;
}
.table-scroll thead th {
  position: sticky;
  top: 0;
  background: #fff; /* must be opaque */
  z-index: 1;
}

Tooltip beim Hovern

Das relative-Eltern-absolute-Kind-Muster fuer Tooltips. Der Tooltip ist standardmaessig versteckt und wird beim Hovern eingeblendet:

.tooltip-trigger {
  position: relative; /* containing block for tooltip */
  display: inline-block;
}
.tooltip {
  position: absolute;
  bottom: 100%; /* sits above the trigger */
  left: 50%;
  transform: translateX(-50%); /* horizontal center */
  margin-bottom: 8px;
  padding: .5rem .75rem;
  background: #1a1a1a;
  color: #fff;
  border-radius: 6px;
  font-size: .85rem;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s;
}
.tooltip-trigger:hover .tooltip {
  opacity: 1;
}

Entscheidungsrahmen: Welche position Verwenden

Hoer auf, dir zu merken, was jeder Wert tut. Verwende stattdessen diesen Entscheidungsfluss:

Muss das Element anderen Inhalt ueberlappen oder aus dem normalen Fluss ausbrechen?

  Nein → Verwende static (Standard). Nutze Flexbox oder Grid fuer Layout.

  Ja, temporaer bei Interaktion (Dropdown, Tooltip) → relative beim Eltern-Element, absolute beim Kind.

Soll das Element sichtbar bleiben, wenn die Seite scrollt?

  Ja, immerfixed (pruefe auf transform bei Vorfahren!)

  Ja, aber erst nach dem Scrollen ueber einen Punktsticky.

Willst du ein Element nur leicht aus seiner normalen Position verschieben?

  Jarelative mit kleinen top/left-Versaetzen.

FAQ

Warum erscheint mein z-index:9999-Element hinter einem z-index:1-Element?

Stacking Contexts. Dein z-index:9999-Element befindet sich wahrscheinlich in einem Stacking Context (erstellt durch transform, opacity oder position:fixed bei einem Vorfahr), der unter dem Stacking Context liegt, der das z-index:1-Element enthaelt. Eine hoehere Zahl hilft nicht. Bewege das Element aus dem Vorfahr heraus, der den Stacking Context erstellt, oder entferne diese Eigenschaft.

Warum scrollt mein position:fixed-Element mit der Seite?

Ein Vorfahr hat transform, filter, perspective, will-change oder contain. Diese Eigenschaften erstellen einen Containing Block fuer fixed-Positionierte Nachfahren und lassen sie wie absolute wirken. Finde und entferne die Eigenschaft beim Vorfahr oder bewege das fixed-Element hoeher im DOM.

Was ist der Unterschied zwischen position: relative und einem Margin-Versatz?

Beide verschieben das Element visuell, aber position: relative bewahrt den urspruenglichen Platz des Elements im Layout -- andere Elemente fliessen nicht nach, um die Luecke zu fuellen. Ein margin verschiebt das Element und bewirkt, dass umgebende Elemente neu fliessen. Verwende relative, wenn du verschieben willst, ohne Geschwister zu beeinflussen.

Sollte ich inset statt top/right/bottom/left verwenden?

Ja, fuer modernen Code. inset: 0 ist die Kurzform fuer top:0; right:0; bottom:0; left:0. Du kannst auch inset: 10px 20px fuer vertikal/horizontal schreiben. Es ist kuerzer, lesbarer und hat gute Browser-Unterstuetzung (97%+).

Beeinflusst position die Performance?

position: fixed und position: sticky koennen haeufigere Repaints beim Scrollen verursachen, da der Browser sie in jedem Frame neu positionieren muss. Das Hinzufuegen von will-change: transform kann dem Browser bei der Optimierung helfen, aber uebermaessige Verwendung von will-change erhoeht den Speicherverbrauch. Teste auf echten Geraeten, wenn du Scroll-Ruckeln siehst.

Wie positioniere ich etwas relativ zur Viewport-Mitte?

Verwende position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); oder den modernen Ansatz: position: fixed; inset: 0; margin: auto; width: deine-breite; height: deine-hoehe;. Beide zentrieren das Element. Der transform-Ansatz ist flexibler fuer unbekannte Groessen.

Weitermachen: CSS-Positionierung ist die eine Haelfte der Bildschirm-Koordinaten-Story. Hier ist die andere:

JavaScript Maus-Koordinaten — Wie clientX, offsetX, pageX, screenX mit positionierten Elementen zusammenhaengen

Physische vs Logische Pixel — Warum positionierte Elemente auf HiDPI-Displays anders rendern

DPI-Scaling-Leitfaden — Wie OS-Level-Scaling CSS-Koordinaten beeinflusst

Technischer Bildschirm-Koordinaten-Leitfaden — Tiefenanalyse von Device Pixel Ratio und Koordinaten-Transformationen

Startseite