mitmario.dev

Gleiche Höhen und die klebende Fußzeile

CSS Im Browser 3 Min Lesezeit 3 BeispieleLektion 8 von 9

Drei Karten sind gleich hoch, und ihre Buttons sitzen trotzdem auf drei verschiedenen Höhen. Dazu kommt eine Seite mit wenig Inhalt, deren Fußzeile mitten im Bild hängt. Hinter beiden steckt dieselbe Idee. Du gibst den freien Platz in einer Flex-Spalte gezielt an eine Stelle, und das sind jeweils nur ein paar Zeilen.

Gleich hoch, aber nicht unten

Gleich hoch reicht nicht
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  font-family: system-ui, sans-serif;
  line-height: 1.5;
  background-color: #fafaf9;
}

/* Die drei Karten sind gleich hoch, dafür sorgt
   stretch von allein. Die Buttons sitzen trotzdem auf
   drei verschiedenen Höhen, denn jeder steht einfach
   da, wo sein Text aufhört. */
.rezepte {
  display: flex;
  gap: 16px;
}

.rezept {
  padding: 16px;
  border-radius: 12px;
  background-color: #ffffff;
}

.rezept h3 {
  margin: 0 0 4px 0;
}

.rezept p {
  margin: 0 0 16px 0;
  color: #52525b;
}

.button {
  padding: 8px 16px;
  border-radius: 8px;
  font-weight: 700;
  text-decoration: none;
  color: #ffffff;
  background-color: #15803d;
}

Die drei Karten im ersten Beispiel sind gleich hoch. Dafür hat niemand etwas getan. align-items steht auf seinem Standard, und der streckt Flex-Items über die volle Querachse. Das kennst du aus 9.4.

Die Buttons sitzen trotzdem auf drei verschiedenen Höhen. Auch das ist folgerichtig, denn innerhalb einer Karte ist nichts Flexbox. Dort stehen Überschrift und Text als ganz normale Blöcke untereinander. Darunter kommt der Button als Link in seiner eigenen Zeile, und der steht eben da, wo der Text aufhört.

Es fehlt also nicht eine Angabe an den Buttons, sondern eine Ebene tiefer ein zweiter Container.

Der automatische Außenabstand

Zwei Zeilen, und der Button sitzt unten
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  font-family: system-ui, sans-serif;
  line-height: 1.5;
  background-color: #fafaf9;
}

.rezepte {
  display: flex;
  gap: 16px;
}

/* Die Karte wird selbst zum Flex-Container, und zwar
   als Spalte. Damit läuft ihre Hauptachse nach unten,
   und darauf kann ein automatischer Außenabstand
   wirken. */
.rezept {
  display: flex;
  flex-direction: column;
  padding: 16px;
  border-radius: 12px;
  background-color: #ffffff;
}

.rezept h3 {
  margin: 0 0 4px 0;
}

.rezept p {
  margin: 0 0 16px 0;
  color: #52525b;
}

/* auto frisst den ganzen freien Platz über dem Button.
   align-self hält ihn schmal, sonst zöge stretch ihn
   über die volle Kartenbreite. */
.button {
  margin-top: auto;
  align-self: flex-start;
  padding: 8px 16px;
  border-radius: 8px;
  font-weight: 700;
  text-decoration: none;
  color: #ffffff;
  background-color: #15803d;
}

Die Karte wird selbst zum Flex-Container, und zwar als Spalte. Ihre Hauptachse läuft damit von oben nach unten, und der Button ist jetzt ein Flex-Item auf dieser Achse, genau wie Überschrift und Text über ihm.

Hier greift die Regel aus 9.3, die dort für Kopfzeilen gedacht war. Ein automatischer Außenabstand frisst in Flexbox den gesamten freien Platz auf seiner Seite. margin-top: auto am Button sammelt also allen Platz über ihm ein und drückt ihn an die Unterkante.

Dazu gehört als Zweites align-self: flex-start. Ohne das zieht stretch den Button über die volle Kartenbreite, denn in einer Spalte ist die Querachse waagerecht.

Du brauchst dabei keine Höhe an der Karte, kein position: absolute am Button und kein padding-bottom, das zum Button passen muss. Das Ergebnis stimmt auch dann noch, wenn ein Text drei Zeilen länger wird.

Übrigens lässt sich margin-top: auto nicht prüfen. Der berechnete Wert ist der ausgerechnete Pixelwert, und der ist in jeder Karte ein anderer, weil jede Karte unterschiedlich viel Text hat. Gemessen wird deshalb das Ergebnis. Liegen die Buttons auf einer Linie, sind die Karten gleich hoch und die Buttons unten. Eine einzige Prüfung reicht dann für zwei Eigenschaften.

Die Fußzeile, die unten bleibt

Die Fußzeile, die unten bleibt
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Drei Zutaten. Der body ist mindestens so hoch wie
   der sichtbare Bereich und eine Spalte, und der
   Hauptbereich nimmt sich alles, was darin übrig
   bleibt. Die Fußzeile wird dadurch nach unten geschoben,
   ohne selbst etwas dafür zu tun. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  margin: 0;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
  background-color: #f4f4f5;
}

header,
footer {
  padding: 16px 24px;
  font-weight: 700;
  color: #ffffff;
  background-color: #18181b;
}

main {
  flex-grow: 1;
  padding: 24px;
}

main p {
  margin: 0;
  max-width: 46ch;
  color: #52525b;
}

Dasselbe Prinzip, eine Ebene höher. Eine Seite mit wenig Inhalt hat ihre Fußzeile mitten im Bild, und darunter steht weiße Fläche. Das sieht nach einem Fehler aus, ist aber nur eine Seite, die kürzer ist als der Bildschirm.

Es braucht drei Zutaten.

  1. body bekommt min-height: 100dvh, ist also mindestens so hoch wie der sichtbare Bereich.
  2. body wird eine Flex-Spalte.
  3. main bekommt flex-grow: 1 und nimmt sich damit den gesamten Überschuss.

Die Fußzeile wird dadurch nach unten geschoben, ohne selbst eine einzige Angabe zu bekommen. Wird der Inhalt länger als der Bildschirm, rutscht sie einfach mit nach unten, denn es ist eine Mindest- und keine Festhöhe.

100vh ist auf Mobilgeräten die falsche Zahl. Sie rechnet mit dem Bereich ohne Adressleiste. Beim Laden ist die Leiste aber noch da, und deshalb ragt die Fußzeile beim ersten Blick knapp aus dem Bild. 100dvh meint den tatsächlich sichtbaren Bereich und passt sich an, wenn die Leiste ein- und ausfährt. Ich nehme deshalb dvh, es kostet nichts.

In der Aufgabe sind die Karten schon gleich hoch, ihre Buttons aber nicht unten, und die Fußzeile hängt mitten auf der Seite.

Zum Mitnehmen

Freier Platz in einer Flex-Spalte lässt sich gezielt an eine Stelle geben. In der Karte schluckt ihn margin-top: auto über dem Button, auf der Seite nimmt ihn main mit flex-grow: 1, solange body mindestens 100dvh hoch ist.

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 3 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.