mitmario.dev

position: sticky

CSS Im Browser 4 Min Lesezeit 4 BeispieleLektion 5 von 8

Scrollst du durch eine lange Tabelle, hilft es, wenn ihr Kopf oben stehen bleibt. Dafür gibt es position: sticky. Ein Element bleibt im Fluss und behält seinen Platz, bis eine Schwelle erreicht ist. Ab da verhält es sich wie fixiert.

Dieses Verhalten hat man lange mit ein paar Zeilen JavaScript und einem Scroll-Listener nachgebaut, bis 2017 auch Chrome und Edge so weit waren. Heute ist es eine Zeile CSS.

Im Fluss, bis die Schwelle kommt

Kleben ab der Schwelle
body {
  margin: 0;
  padding: 48px 16px 16px 16px;
  font-family: system-ui, sans-serif;
  line-height: 1.6;
}

p {
  margin: 0 0 64px 0;
}

/* Bis zur Schwelle im Fluss, danach fixiert.
   Der Platz bleibt die ganze Zeit reserviert. */
.kopf {
  position: sticky;
  top: 0;
  padding: 16px;
  font-weight: 700;
  color: #ffffff;
  background-color: #18181b;
}

Das Element scrollt zunächst ganz normal mit. Erreicht seine Oberkante den Wert, der in top steht, bleibt es stehen, und der Inhalt zieht darunter weg.

Der Unterschied zu fixed ist der Platz. Ein sticky-Element bleibt im Fluss. Es macht sich seinen Platz frei, und nichts rutscht darunter. Du musst hinterher auch kein padding nachtragen, um es auszugleichen. Deshalb ist es für Kopfzeilen und Tabellenköpfe die bessere Wahl.

Die Schwelle kann an jeder Seite sitzen. top nimmst du für die klebende Kopfzeile und left für die erste Spalte einer breiten Tabelle. Mit bottom fährt eine Leiste am unteren Rand mit, bis sie an ihrer eigenen Stelle ankommt, und von da an scrollt sie ganz normal weiter.

Ohne Schwelle passiert nichts

Ohne Schwelle passiert nichts
body {
  margin: 0;
  padding: 48px 16px 16px 16px;
  font-family: system-ui, sans-serif;
  line-height: 1.6;
}

p {
  margin: 0 0 64px 0;
}

.kopf {
  position: sticky;
  padding: 16px;
  font-weight: 700;
  color: #ffffff;
}

/* Gültiges CSS, keine Meldung, keine Wirkung.
   Ohne Schwelle weiß der Browser nicht, ab wann. */
.ohne {
  background-color: #b91c1c;
}

.mit {
  top: 0;
  background-color: #15803d;
}

position: sticky allein tut nichts. Ohne top, right, bottom oder left weiß der Browser nicht, ab wann er kleben soll, und lässt das Element schlicht mitlaufen.

Es gibt keine Meldung, und auch im Streifen sieht auf den ersten Blick alles richtig aus. An der Kopfzeile steht im Reiter „Regeln“ die Regel da. position: sticky ist nicht durchgestrichen und trägt keinen Vermerk, und im Reiter „Werte“ steht position: sticky als geltender Wert. Alles in Ordnung. Trotzdem passiert nichts.

In Lektion 3.5 stehen drei Ursachen dafür, dass eine Regel nichts bewirkt. Der Selektor trifft nicht, die Deklaration ist ungültig, oder eine andere Regel gewinnt. Alle drei sehen im Reiter „Regeln“ anders aus als hier. Es kommt also eine vierte dazu, die unauffälligste von allen. Die Deklaration gilt und wird auch angewandt, ihr fehlt nur die zweite Hälfte.

Klebt etwas nicht, frage ich deshalb zuerst, ob eine Schwelle dabeisteht, und erst danach, ob der Selektor stimmt. Was fehlt, siehst du an der Liste selbst, wenn du weißt, wonach du suchst. Keine Zeile heißt top, right, bottom oder left.

Der Container, der alles verhindert

Ein Vorfahre mit overflow
body {
  margin: 0;
  padding: 16px;
  font-family: system-ui, sans-serif;
  line-height: 1.6;
}

p {
  margin: 0 0 64px 0;
}

/* Sieht harmlos aus und ist ein häufiger Grund dafür,
   dass sticky nicht klebt. Der Kasten wird damit selbst
   zum Scroll-Container, und der scrollt nicht. */
.huelle {
  overflow: hidden;
}

.kopf {
  position: sticky;
  top: 0;
  padding: 16px;
  font-weight: 700;
  color: #ffffff;
  background-color: #b91c1c;
}

Eine zweite Ursache ist unauffälliger. Ein Vorfahre mit overflow: hidden, auto oder scroll wird selbst zum Scroll-Container. Das sticky-Element klebt dann brav in diesem Container. Der scrollt aber selbst nicht, und so siehst du davon nichts.

Tückisch ist, dass das overflow oft aus einem ganz anderen Grund dasteht. Jemand wollte einen Clearfix, hat einen Umbruch abgefangen oder eine Rundung sauber abgeschnitten. Drei Monate später klebt eine Kopfzeile nicht, und niemand bringt die beiden Dinge zusammen.

Lange suchen musst du trotzdem nicht. Eine overflow-Zeile taucht im Streifen nur auf, wenn dort etwas anderes als visible steht. Du gehst also die Vorfahren durch, und wo die Zeile auftaucht, sitzt der Übeltäter. Im Beispiel steht an der Hülle overflow: hidden, an der Kopfzeile darin nichts dergleichen.

Bleibt eine dritte Ursache. Ein sticky-Element klebt nur innerhalb seines Elternteils.

So nicht, in einer zu knappen Hülle
body {
  margin: 0;
  padding: 48px 16px 16px 16px;
  font-family: system-ui, sans-serif;
  line-height: 1.6;
}

p {
  margin: 0 0 64px 0;
}

/* Die Hülle ist genau so hoch wie die Kopfzeile darin. */
.kopf {
  position: sticky;
  top: 0;
  padding: 16px;
  font-weight: 700;
  color: #ffffff;
  background-color: #18181b;
}

Im Beispiel steckt die Kopfzeile in einem div, der so hoch ist wie sie. Beim Scrollen läuft sie mit hinaus, obwohl position: sticky und top: 0 dastehen. Innerhalb der Hülle gibt es einfach keinen Bereich, in dem sie kleben könnte. Wenn eine Kopfzeile trotz Schwelle und ohne overflow an den Vorfahren nicht klebt, ist das die Erklärung.

Wenn der Elternteil endet

Am deutlichsten unterscheidet sich sticky von fixed am Ende des Elternteils. Scrollt der Elternteil aus dem Bild, geht das klebende Element mit heraus.

Dafür ist es gemacht. Eine Abschnittsüberschrift soll nur so lange oben stehen bleiben, wie ihr Abschnitt sichtbar ist. Hier klappt das, mit fixed wäre sie nicht zu bauen. Dasselbe gilt für die Spaltenköpfe einer Tabelle und für Beschriftungen in einer langen Liste.

Der Elternteil bestimmt also den Bereich, in dem geklebt wird. Soll die Kopfzeile über die ganze Seite kleben, gehört sie direkt in den body. Soll sie nur einen Abschnitt begleiten, gehört sie in diesen Abschnitt.

In der Aufgabe kleben Kopfzeile und Abschnittsüberschriften, jede an ihrer eigenen Schwelle.

Zum Mitnehmen

Ohne Schwelle wie top: 0 klebt nichts, und geklebt wird nur, solange der Elternteil zu sehen ist. Steht an einem Vorfahren overflow, klebt das Element dort drin, wo man es nicht sieht.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

Was in dieser Lektion steckt

  • Artikel mit 4 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.