Überschriften ohne Schusterjungen: text-wrap: balance
Eine Überschrift, bei der das letzte Wort allein in der zweiten Zeile steht, sieht billig aus. Zwei CSS-Zeilen räumen das auf — ohne JavaScript und ohne manuelle Zeilenumbrüche.
Du kennst das: Die Überschrift passt auf dem Desktop wunderbar in eine Zeile, und auf dem Tablet steht plötzlich ein einzelnes Wort allein in Zeile zwei. In der Typografie heißt so etwas Schusterjunge, und es sieht immer nach Versehen aus — nie nach Absicht.
Früher habe ich das mit <br> an der „richtigen" Stelle erschlagen. Funktioniert genau bei einer Bildschirmbreite und ist bei jeder anderen falsch. Heute macht der Browser das selbst:
h1, h2, h3 {
text-wrap: balance;
}Das war's. Der Browser verteilt die Wörter so auf die Zeilen, dass sie möglichst gleich lang werden — statt jede Zeile bis zum Anschlag zu füllen und den Rest fallen zu lassen.
Wo du es einsetzt — und wo nicht
balance ist absichtlich teuer: Der Browser muss mehrere Umbruch-Varianten durchrechnen. Deshalb wenden ihn die Engines nur auf kurze Blöcke an (Chrome und Safari bis etwa sechs Zeilen, darüber fällt es still auf normales Umbrechen zurück). Genau richtig für Überschriften, Buttons, Karten-Titel, Bildunterschriften. Nicht für Fließtext.
Für lange Absätze gibt es den Geschwister-Wert:
p {
text-wrap: pretty;
}pretty balanciert nicht, sondern kümmert sich nur um die letzte Zeile: Es verhindert, dass ein Absatz mit einem einsamen Wort endet. Das ist billig genug für laufenden Text.
Ein vollständiges Beispiel
/* Überschriften: gleichmäßig verteilte Zeilen */
h1, h2, h3, .card-title {
text-wrap: balance;
/* Sinnvolle Obergrenze — sonst balanciert der Browser über die halbe Seite */
max-inline-size: 28ch;
}
/* Fließtext: nur die letzte Zeile absichern */
p, li {
text-wrap: pretty;
hyphens: auto; /* zusammen mit lang="de" im <html> */
}Das max-inline-size: 28ch ist der Teil, den ich am längsten übersehen habe. balance verteilt auf die verfügbare Breite — wenn die Überschrift über 1400 Pixel laufen darf, entsteht eine gleichmäßig verteilte, aber trotzdem unlesbar breite Zeile. Erst die Zeilenlängen-Bremse macht daraus Typografie.
Muss ich einen Fallback bauen?
Nein. Ältere Browser kennen den Wert nicht und ignorieren die Deklaration — der Text bricht dann eben um wie immer. Es gibt nichts, was kaputtgehen kann, und deshalb auch keinen Grund, es hinter einem @supports zu verstecken.
Ich setze die beiden Regeln inzwischen in jedem Projekt ins Basis-Stylesheet. Zwei Zeilen, die man einmal schreibt und danach nie wieder anfasst — und die auf jeder Kundenseite den Unterschied zwischen „selbst gebastelt" und „gesetzt" ausmachen.
Wenn du eine Website hast, bei der genau solche Kleinigkeiten fehlen: Ich baue Seiten mit eigenem CMS, bei denen der Text vom Kunden kommt und die Typografie trotzdem sitzt. Schreib mir über bymw.de.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
Text nach drei Zeilen abschneiden – line-clamp statt JavaScript
Kartenlisten sehen nur dann ordentlich aus, wenn alle Vorschautexte gleich hoch sind. Das serverseitig auf 120 Zeichen zu kürzen geht schief, sobald die Karte schmaler wird – CSS kann das seit Jahren selbst.
@layer in CSS: Kaskadenebenen statt !important-Wettrüsten
Irgendwann steht in jedem gewachsenen Stylesheet das erste !important – und ein halbes Jahr später das dreißigste. Mit @layer legst du die Reihenfolge einmal fest, und ab da gewinnt nicht mehr der längste Selektor, sondern die Ebene, die du bestimmt hast.
Tooltips ohne JavaScript – CSS Anchor Positioning
Ein Tooltip an einen Button hängen, der ausweicht, wenn oben kein Platz ist, und nicht am overflow: hidden der Elternbox scheitert – das brauchte jahrelang eine Bibliothek. Seit Firefox 147 kann das jeder große Browser in reinem CSS.