Ein Menü verschwindet hinter einem Bild, ein Pop-up lässt sich trotz z-index: 9999 nicht nach vorn holen, die Kopfzeile klebt nicht wie geplant: Fast immer steckt dahinter ein Missverständnis darüber, wie CSS Elemente positioniert und übereinanderschichtet. Dieser Einstieg erklärt die fünf Werte von position, die Regeln von z-index und das Konzept des Stacking Context mit kurzen Beispielen. Im zweiten Teil geht es um Schriftgrößen: wann px, em, rem, Prozent oder clamp() passen.
Die fünf Werte von position
Jedes Element liegt zunächst im normalen Fluss: Blöcke stehen untereinander, Text läuft von links nach rechts. Mit position und den Versatzangaben top, right, bottom und left lässt sich das ändern. Die Eigenschaft ist laut MDN seit Jahren in allen Browsern verfügbar, auch sticky funktioniert heute überall.
| Wert | Bezugspunkt | Platz im Fluss | Typischer Einsatz |
|---|---|---|---|
| static | keiner, Versatz wirkt nicht | bleibt erhalten | Standard für alle Elemente |
| relative | eigene Ausgangsposition | bleibt erhalten | leichtes Verschieben, Bezugsrahmen für Kinder |
| absolute | nächster positionierter Vorfahr | wird entfernt | Badges, Overlays, Tooltips |
| fixed | Browserfenster (Viewport) | wird entfernt | Cookie-Hinweis, Zurück-nach-oben-Knopf |
| sticky | nächster scrollender Vorfahr | bleibt erhalten | mitlaufende Kopfzeile, Tabellenköpfe |
relative und absolute als Paar
Ein absolut positioniertes Element orientiert sich am nächsten Vorfahren, dessen position nicht static ist. Gibt es keinen, dient der Anfangsblock des Dokuments als Bezug, und das Element landet unerwartet am Seitenrand. Deshalb erhält der Elternbehälter meist position: relative, ohne verschoben zu werden:
.karte {
position: relative; /* Bezugsrahmen, bleibt an seinem Platz */
}
.karte .badge {
position: absolute;
top: 0.5rem;
right: 0.5rem; /* oben rechts in der Karte */
}
fixed und sticky im Alltag
fixed bezieht sich auf das Browserfenster und bleibt beim Scrollen stehen. sticky verhält sich dagegen wie relative, bis eine Schwelle erreicht ist, und klebt erst dann fest. Diese Schwelle muss angegeben werden, sonst passiert nichts:
.kopfzeile {
position: sticky;
top: 0; /* klebt, sobald die Oberkante erreicht ist */
background: white; /* sonst scheint Inhalt durch */
}
Wie eine solche Kopfzeile mit Menü sinnvoll aufgebaut wird, beschreibt unser Beitrag Website-Navigation gestalten.
Wie z-index wirklich funktioniert
Überlappen sich Elemente, liegt ohne weitere Angaben das später im Quelltext stehende oben. z-index ändert diese Reihenfolge: Höhere Werte liegen weiter vorn, negative Werte hinter dem normalen Inhalt. Die Eigenschaft wirkt allerdings nur bei positionierten Elementen (alles außer static) sowie bei Kindern eines Flex- oder Grid-Containers. Auf einem gewöhnlichen div ohne Positionierung bleibt sie wirkungslos.
Der Stacking Context als abgeschlossene Ebene
Entscheidend ist der Stapelkontext (Stacking Context). Man kann ihn sich als Mappe vorstellen: Alles darin wird untereinander sortiert, die Mappe selbst liegt aber als Ganzes an einer Stelle im Stapel. Ein Kind mit z-index: 9999 kommt nie über ein Element außerhalb der Mappe, das höher liegt als die Mappe selbst.
Einen neuen Stapelkontext erzeugen laut MDN unter anderem:
- positionierte Elemente (
relative,absolute) mit einemz-indexungleichauto, - jedes Element mit
position: fixedodersticky, - Flex- und Grid-Kinder mit
z-indexungleichauto, opacitykleiner als 1,transform,filter,backdrop-filter,clip-pathodermaskmit einem anderen Wert alsnone,isolation: isolate,will-changemit solchen Eigenschaften sowiecontain: layoutoderpaint.
.slider { transform: translateX(0); } /* neuer Stapelkontext! */
.slider .dropdown {
position: absolute;
z-index: 1000; /* hilft nicht gegen Elemente außerhalb von .slider */
}
Wer bewusst einen abgeschlossenen Kontext schaffen will, etwa für eine Komponente, nutzt am saubersten isolation: isolate. Das hat keine optischen Nebenwirkungen.
Typische Fehler und ihre Lösung
- z-index ohne position: Das Element ist
static, also wirkt der Wert nicht. Lösung:position: relativeergänzen. - Gefangen im Elternelement: Ein Vorfahr hat
opacity,transformoder einen eigenenz-index. Lösung: denz-indexam Vorfahren anheben oder das Overlay im HTML außerhalb platzieren. - Abgeschnittene Dropdowns:
overflow: hiddenam Behälter kappt absolut positionierte Kinder. Das ist kein z-index-Problem, sondern ein Überlauf. - sticky klebt nicht: Es fehlt
top, oder ein Vorfahr mitoverflow: hiddenoderautowird zum Bezugsrahmen. - fixed scrollt mit: Ein Vorfahr mit
transform,perspectiveoderfilterersetzt das Browserfenster als Bezugsrahmen. - z-index-Wettrüsten: Werte wie 99999 sind ein Warnsignal. Besser ist eine kleine, dokumentierte Skala, etwa 10 für Dropdowns, 100 für die Kopfzeile, 1000 für Dialoge.
Für Dialoge und Pop-ups gibt es inzwischen eine elegantere Lösung: Das HTML-Element <dialog> mit showModal() und das popover-Attribut legen Inhalte in die sogenannte Top Layer, die über allem anderen liegt, ganz ohne z-index.
Schriftgrößen in CSS: px, em, rem, Prozent
Ein CSS-Pixel ist als 1/96 Zoll definiert und entspricht auf hochauflösenden Bildschirmen mehreren Gerätepixeln. Pixelangaben sind einfach zu verstehen, haben bei Schrift aber einen Nachteil: Wer im Browser eine größere Standardschrift einstellt, bekommt bei px trotzdem die feste Größe. Seitenzoom funktioniert zwar, die Grundeinstellung wird jedoch ignoriert.
em bezieht sich bei font-size auf die geerbte Schriftgröße des Elternelements. Das ist praktisch für Abstände, die mit der Schrift wachsen sollen, führt aber bei verschachtelten Elementen zu Vervielfachung. rem (root em) bezieht sich immer auf das html-Element, dessen Standardwert in den meisten Browsern 16 Pixel beträgt, sofern der Nutzer nichts anderes eingestellt hat. Prozentangaben bei font-size verhalten sich wie em: 150% entspricht 1.5em.
.box { font-size: 1.5em; } /* 24px bei 16px Grundgröße */
.box .box { font-size: 1.5em; } /* 36px: em multipliziert sich */
h2 { font-size: 1.5rem; } /* immer 24px bei 16px Grundgröße */
small { font-size: 0.875rem; } /* 14px */
Eine bewährte Faustregel: Schriftgrößen in rem, Abstände innerhalb von Komponenten wahlweise in em, Rahmenlinien in px, Zeilenhöhe ohne Einheit (line-height: 1.5), damit sie sich an jede Schriftgröße anpasst. Den früher beliebten Trick, die Grundgröße mit html { font-size: 62.5% } auf 10 Pixel zu drücken, um leichter rechnen zu können, braucht heute niemand mehr: Er zwingt dazu, überall nachzukorrigieren, und erschwert die Wartung.
Fließende Typografie mit clamp()
Mit clamp(Minimum, Wunschwert, Maximum) wächst eine Überschrift mit der Fensterbreite, bleibt aber innerhalb fester Grenzen. Die Funktion ist laut MDN seit Juli 2020 in allen gängigen Browsern verfügbar und ersetzt viele Media Queries:
h1 {
font-size: clamp(1.75rem, 1rem + 3vw, 3rem);
}
Der Wunschwert sollte eine rem-Komponente enthalten. Eine reine Angabe in vw hängt nur von der Fensterbreite ab und wächst bei Textvergrößerung nicht mit; die WCAG führen das als eigenen Fehlerfall (F94). MDN empfiehlt außerdem, das Maximum mindestens doppelt so groß wie das Minimum zu wählen, damit Text gemäß WCAG-Kriterium 1.4.4 auf 200 Prozent vergrößert werden kann.
Was sich für Einsteiger lohnt
Wer CSS lernt, kommt mit erstaunlich wenig aus: relative als Bezugsrahmen, absolute für Kleinigkeiten, sticky für Kopfzeilen und die Erkenntnis, dass z-index nur innerhalb des eigenen Stapelkontexts zählt. Für das Seitenlayout selbst ist position heute meist das falsche Werkzeug, dafür gibt es Flexbox und Grid. In den Entwicklerwerkzeugen von Firefox und Chrome lässt sich im Bereich „Berechnet“ beziehungsweise „Computed“ nachsehen, welche Werte tatsächlich greifen. Das spart oft mehr Zeit als jede weitere Null hinter dem z-index.







