rem vs. em in einer verschachtelten Demo
rem bezieht sich auf die Schriftgröße der Wurzel (das Element <html>, standardmäßig 16px). em bezieht sich auf die aktuelle Schriftgröße, was bei font-size die des Elternelements bedeutet. Verschachtle dieselbe Klasse dreimal, und der Unterschied wird sichtbar:
Die ausgegebenen Größen hat der Browser berechnet. Jedes 1.25em multipliziert sein Elternelement: 20px, dann 25px, dann 31,25px. Jedes 1.25rem schaut nur auf die Wurzel: 20px, 20px, 20px. Wegen dieses Multiplizierens geraten em-Schriftgrößen in verschachtelten Listen und Menüs außer Kontrolle, und deshalb setzen die meisten Websites Schriftgrößen in rem.
Worauf sich jede Einheit bezieht
| Einheit | Bezieht sich auf | 1 Einheit standardmäßig |
|---|---|---|
px | nichts (ein CSS-Pixel) | 1px |
rem | Schriftgröße des Wurzelelements (html) | 16px |
em | Schriftgröße des Elements; bei font-size selbst die des Elternelements | 16px auf oberster Ebene |
% | hängt von der Eigenschaft ab (siehe unten) | |
vw / vh | 1% der Breite / Höhe des Viewports | |
dvh, svh, lvh | 1% der dynamischen, kleinen oder großen Viewport-Höhe | |
vmin / vmax | 1% der kleineren / größeren Viewport-Seite | |
ch | die Breite der „0“ in der aktuellen Schrift | etwa ein halbes em |
ex | die x-Höhe der aktuellen Schrift | etwa ein halbes em |
Ein CSS-Pixel ist kein Gerätepixel: Auf einem Handy mit 3x-Bildschirm ist 1px drei Gerätepixel breit. Es bleibt auf verschiedenen Bildschirmen ungefähr gleich groß, deshalb ist px für Rahmen und Schatten weiterhin in Ordnung.
em für Abstände, die mit dem Text skalieren
em ist nicht nur für Schriftgrößen da. Bei padding, margin, width oder border-radius bedeutet es „mal die Schriftgröße dieses Elements“. Damit funktioniert eine einzige Button-Klasse in jeder Größe:
Das Padding jedes Buttons ist vertikal die halbe Schriftgröße und horizontal eine Schriftgröße, also sehen die drei aus wie derselbe Button in drei Größen. Mit Padding in px bräuchtest du für jede Größe eine eigene Padding-Regel.
Beachte, dass Buttons die Schriftgröße der Seite standardmäßig nicht erben (Browser geben Formularelementen eine eigene), also ist der mittlere Button hier in Chrome 13,33px groß, nicht 16px. Füge Buttons und Eingabefeldern font: inherit hinzu, wenn sie zur Seite passen sollen.
Prozent: hängt von der Eigenschaft ab
% hat keine einheitliche Bedeutung. Jede Eigenschaft legt fest, wovon es ein Prozentsatz ist:
| Eigenschaft | % bezieht sich auf |
|---|---|
width, max-width, left, right | die Breite des Elternelements (des umgebenden Blocks) |
height, top, bottom | die Höhe des Elternelements, und nur wenn es eine festgelegte Höhe hat |
padding, margin (alle vier Seiten) | die Breite des Elternelements |
font-size | die Schriftgröße des Elternelements (150% = 1.5em) |
line-height | die eigene Schriftgröße des Elements |
transform: translate() | die eigene Größe des Elements |
width: 50% sind 200px, die Hälfte des Elternelements. padding-top: 5% sind 20px: 5% der Breite des Elternelements, nicht seiner Höhe. Und height: 50% bewirkt nichts, weil das Elternelement keine festgelegte Höhe hat, also ist das Kind nur so hoch wie sein Text plus dieses Padding. Die Seite zu Breite und Höhe behandelt diese Regel im Detail.
vw, vh und die mobile Adressleiste
1vw ist 1% der Viewport-Breite und 1vh 1% seiner Höhe. Sie sind praktisch für bildschirmfüllende Abschnitte und für fließende Größen (oft innerhalb von clamp()). Auf Handys hat vh einen Haken: Die Adressleiste des Browsers gleitet beim Scrollen ein und aus, und 100vh ist die Höhe ohne die Leiste, also wird ein Hero mit height: 100vh unten abgeschnitten, solange die Leiste zu sehen ist. Die neueren Einheiten beheben das:
| Einheit | Verwendete Höhe |
|---|---|
100vh | der große Viewport (Leisten ausgeblendet) in den meisten mobilen Browsern |
100svh | der kleine Viewport (Leisten sichtbar): passt immer |
100lvh | ausdrücklich der große Viewport |
100dvh | der dynamische Viewport: ändert sich, wenn sich die Leisten bewegen |
.hero {
min-height: 100vh; /* fallback for older browsers */
min-height: 100svh; /* fits the screen even with the address bar visible */
}
vw hat seinen eigenen Haken: 100vw enthält die Breite einer vertikalen Scrollleiste, wenn diese Platz einnimmt (wie unter Windows), also kann width: 100vw breiter als die Seite sein und eine horizontale Scrollleiste erzeugen. Nimm width: 100% für „die volle Breite des Elternelements“.
ch für gut lesbare Zeilenlänge
ch ist die Breite des Zeichens „0“, also begrenzt max-width: 65ch einen Absatz auf ungefähr 65 Zeichen pro Zeile, eine angenehme Leselänge, bei jeder Schriftgröße:
Welche Einheit du nimmst
| Für | Nimm | Warum |
|---|---|---|
| Schriftgrößen | rem | Überall gleich, respektiert die Schriftgrößeneinstellung des Lesers |
| Padding und Lücken in Komponenten | rem oder em | em, wenn es mit dem eigenen Text der Komponente wachsen soll |
| Rahmen, feine Linien, Schatten | px | Sollen bei jeder Schriftgröße dünn bleiben |
| Layoutbreiten | %, fr, max-width in rem oder ch | Folgen dem Container, begrenzen die Zeilenlänge |
| Bildschirmfüllende Abschnitte | svh / dvh (mit vh als Fallback) | Kommen mit mobilen Adressleisten klar |
| Fließende Schrift | clamp() mit rem und vw gemischt | Wächst mit dem Bildschirm innerhalb von Grenzen |
Warum rem Leser respektiert und px nicht
Browser haben eine Einstellung für die Standardschriftgröße, die Menschen nutzen, die größeren Text brauchen. Sie ändert die Schriftgröße der Wurzel, also wächst alles in rem und em mit. Ein font-size: 14px bleibt 14px, egal was der Leser gewählt hat. Der Browserzoom skaliert auch px, aber auf die Schriftgrößeneinstellung verlassen sich viele Leser. Das ist der Hauptgrund, Schriftgrößen in rem zu setzen.
Manche Websites setzen html { font-size: 62.5%; }, damit 1rem 10px entspricht und das Rechnen leichter fällt. Das respektiert die Einstellung des Lesers weiterhin (62,5% von dem, was er gewählt hat), aber denk daran, an body eine lesbare font-size zu setzen, sonst zeigt jedes Element ohne eigene Größe Text in 10px.
Häufige Fehler
em-Schriftgrößen in verschachtelten Elementen. Sie multiplizieren sich auf jeder Ebene. Nimmremfür Schriftgrößen.height: 50%, das nichts bewirkt. Das Elternelement braucht eine festgelegte Höhe, damit eine Prozenthöhe funktioniert.- Erwarten, dass
padding-top: 10%der Höhe des Elternelements folgt. Vertikales Padding und Margin in Prozent nutzen die Breite des Elternelements. width: 100vwerzeugt eine horizontale Scrollleiste. Es schließt die Scrollleiste ein. Nimm100%.height: 100vhwird auf Handys abgeschnitten. Nimm100svhoder100dvh.html { font-size: 12px }setzen. Ein px-Wert an der Wurzel überschreibt die Schriftgrößeneinstellung des Lesers für die ganze Seite. Lass die Wurzel in Ruhe oder nimm einen Prozentwert.
Häufig gestellte Fragen
Was ist der Unterschied zwischen rem und em?
rem bezieht sich auf die Schriftgröße des Wurzelelements (<html>), also ist 1.5rem überall auf der Seite gleich groß. em bezieht sich auf die Schriftgröße des Elements selbst (bei font-size auf die des Elternelements) und multipliziert sich deshalb, wenn Elemente verschachtelt sind.
Wie viele Pixel sind 1rem?
Standardmäßig 16px, weil Browser die Schriftgröße der Wurzel auf 16px setzen. Erhöht der Nutzer die Standardschriftgröße in den Browsereinstellungen oder setzt du html { font-size: ... }, ändert sich 1rem mit.
Soll ich für die Schriftgröße rem oder px nehmen?
Nimm rem für Schriftgrößen. Es respektiert die Standardschriftgröße, die der Leser im Browser eingestellt hat, was px ignoriert. Der Browserzoom skaliert beides, aber nicht jeder Leser nutzt den Zoom.
Wann nehme ich em statt rem?
Nimm em für Abstände, die mit dem eigenen Text des Elements skalieren sollen, etwa das Padding eines Buttons oder die Größe eines Icons neben Text. Dieselbe Klasse sieht dann bei jeder Schriftgröße richtig aus. Nimm rem für Schriftgrößen und Abstände auf Seitenebene, damit sich nichts multipliziert.
Was ist der Unterschied zwischen 100vh und 100dvh?
100vh ist in mobilen Browsern die Höhe bei ausgeblendeter Adressleiste, also ist ein 100vh-Abschnitt höher als der sichtbare Bildschirm, solange die Leiste zu sehen ist. 100dvh (dynamische Viewport-Höhe) folgt der Leiste, wenn sie erscheint und verschwindet, und 100svh ist immer die kleinere Höhe.