Mehr als nur Schriftgrößen: Die CSS-Einheit rem

Avatar of Roman Rudenko
Roman Rudenko am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der folgende Text ist ein Gastbeitrag von Roman Rudenko, einem verrückten Wissenschaftler bei Mobify, wo er dafür zuständig ist, zu verstehen, warum Browser sich daneben benehmen, und sie dazu zu bringen, sich gut zu benehmen. Wenn er nicht gerade programmiert, lernt Roman Motorradfahren, ohne zu viele feste Objekte zu rammen.

Viele Webdesigner und -entwickler sind mit der CSS-rem-Längeneinheit vertraut. Aber Sie wissen vielleicht nicht, dass sie ein paar praktische alternative Verwendungsmöglichkeiten hat. In diesem Beitrag beschreibe ich, wie die CSS-rem-Einheit verwendet wird, um bestimmte Seitenelemente zu skalieren, während andere unverändert bleiben. Ich werde auch diskutieren, wie sie als Ersatz für die noch nicht gut unterstützte Einheit vw (Viewport-Breite) verwendet werden kann.

Für Leser, die mit der rem-Einheit (steht für „root em“) nicht vertraut sind: Sie bietet eine Möglichkeit, Längen als Bruchteile der Schriftgröße des Wurzelelements anzugeben. Praktisch bedeutet dies fast immer die Schriftgröße des <html>-Elements. Die offensichtlichste Verwendung von rem ist der Ersatz von em, um zu verhindern, dass die Schriftgrößen innerer Elemente durch äußere Elemente verändert werden, und so das klassische Problem der verschachtelten em-Skalierung zu vermeiden. Aber rem funktioniert effektiv als benutzerdefinierte, anpassbare Einheit und kann daher auch für andere Dinge nützlich sein.

Zuerst schauen wir uns an, wie rem funktioniert und wie es sich von der em-Einheit unterscheidet. Ein em-Wert wird gegen die font-size eines aktuellen Elements berechnet, sodass damit dimensionierte Boxen entsprechend skaliert werden, wenn die Schriftgrößen durch das Element oder seine Vorfahren angepasst werden. Währenddessen ist rem als font-size des Wurzelelements definiert. Daher geben alle Verweise auf rem den gleichen Wert zurück, unabhängig von der Schriftgröße der Vorfahren. Tatsächlich ist rem eine dokumentweite CSS-Variable. Die Browserunterstützung für rem ist heutzutage recht gut. Auf Desktops ist sie eingeschränkt, da IE8 sie nicht unterstützt, aber gängige mobile und Tablet-Browser handhaben sie viel besser.

Rem kann für seine übliche Aufgabe der Schriftgrößenanpassung verwendet werden. Wenn die Markup-Struktur komplex verschachtelt ist, können font-size-Deklarationen mit em-Werten unerwartet kumulieren, und rem ist eine gute Wahl, um diese Probleme zu entwirren. Es gibt jedoch einige andere interessante Verwendungszwecke für rem.

Skalierung von Dokumentelementen

Sie können rem verwenden, um einige Elemente eines Dokuments zu skalieren, während andere unverändert bleiben. In diesem Beispiel wird die font-size von sekundären Seiteninhalten (Slideshow-Steuerelemente, Illustrationsnamen, Post-Metadaten) über rem gesteuert, aber der primäre Inhalt bleibt in Pixeln dimensioniert.

Check out this Pen!

Wenn auf einen der roten Links zur Größenanpassung geklickt wird, passt ein kleines JavaScript-Snippet die font-size von <html> an, wodurch sekundäre Elemente neu dimensioniert werden, ohne die primären zu verändern.

Diese Art der Bemaßung kann für benutzergesteuerte Anpassungen nützlich sein oder um Layouts für Fälle anzupassen, in denen sekundäre Elemente berührungsfreundlicher (Tablet) oder sichtbarer (TV) sein müssen. Ohne rem müsste jedes anpassbare Element separat neu dimensioniert werden.

/* States */
html.secondary-12px { font-size: 12px; }
html.secondary-14px { font-size: 14px; }
html.secondary-16px { font-size: 16px; }

/* Primary content stays fixed */
body { font-size: 18px; }

/* Secondary content scales */
.post-inner .meta { font-size: 1rem; }
.figure .title { font-size: 1rem; }
.slideshow .controls { font-size: 1.25rem; }
.slideshow .controls a { padding: 0 0.5rem; }

Ersatz für vw

Die CSS-vw-Einheit ist als 1/100 der Viewport-Breite definiert. Diese Einheit ist nützlich, um Überlappungen bei Breitenberechnungen zu vermeiden, genauso wie rem Überlappungen bei font-size-Multiplikatoren vermeidet. Sie kann auch für Nicht-Breite-Eigenschaften verwendet werden, wie z. B. font-size (um ein festes Textfragment in eine prozentual dimensionierte Box zu passen) oder Höhe (um das Seitenverhältnis des Elements zu erhalten). Die Unterstützung für vw ist immer noch lückenhaft. Daher können wir stattdessen rem verwenden und die <html>-Schriftgröße dynamisch neu berechnen, um sie an die vw-Einheit anzupassen.

Schauen wir uns eine Beispielimplementierung für diesen Workaround an (ändern Sie die Browsergröße, um die Anpassungen zu sehen).

Check out this Pen!
body { font-size: 12px; margin: 0; padding: 0;}
.one, .two {
  border: solid #666;
  border-width: 10px; border-width: 0.01rem;   /* 1vw */
  border-radius: 30px; border-radius: 0.03rem; /* 3vw */
  font-size: 20px; font-size: 0.02rem;         /* 2vw */
  padding: 20px; padding: 0.02rem;             /* 2vw */
}

Hier schirmt die font-size-Regel für das <body>-Element den Inhalt vor Änderungen der <html>-font-size ab. Browser, die rem nicht verstehen, erhalten einen Pixel-basierten Fallback; Browser, die rem kennen, leiten die richtige Dimension von der <html>-Schriftgröße ab.

Eine frühere Version dieses Beispiels erlaubte es Browsern, die die vw-Eigenschaft erkennen, sie direkt zu verwenden, aber das wurde entfernt, nachdem Chrome 25 einen mit vw angegebenen Rand nicht anwendete. Der rem-basierte Ersatz hatte keine solchen Probleme.

All dies war möglich, bevor die rem-Einheit verfügbar war, indem man Eigenschaften direkt mit JavaScript berechnete und zuwies. Aber rem macht die Dinge viel einfacher. Mit rem muss nur eine Zuweisung für das gesamte Dokument vorgenommen werden, und das Skript muss sich nicht merken, welche Eigenschaften wie genau skaliert werden sollen.

(function (doc, win) {
    var docEl = doc.documentElement,
        recalc = function () {
            var clientWidth = docEl.clientWidth;
            if (!clientWidth) return;

            docEl.style.fontSize = clientWidth + 'px';
            docEl.style.display = "none";
            docEl.clientWidth; // Force relayout - important to new Android devices
            docEl.style.display = "";
        };

    // Abort if browser does not support addEventListener
    if (!doc.addEventListener) return;

    // Test rem support
    var div = doc.createElement('div');
    div.setAttribute('style', 'font-size: 1rem');

    // Abort if browser does not recognize rem
    if (div.style.fontSize != "1rem") return;

    win.addEventListener('resize', recalc, false);
    doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);

Es gibt ein paar Dinge, die im obigen JavaScript zu beachten sind. Erstens wird das Skript frühzeitig beendet, wenn der Browser veraltet ist und die addEventListener-API oder die rem-Einheit selbst nicht unterstützt. Zweitens wird statt <html>-Schriftgröße auf eine tatsächliche vw-Einheit gesetzt, die viewport-Breite in Pixeln. Dies bedeutet, dass CSS vw-Werte mit einem Faktor von 100 für die Verwendung mit rem skalieren müsste, vermeidet aber Rundungsfehler, die sonst aufgrund der begrenzten font-size-Präzision in Webkit auftreten würden.

Andere Viewport-Einheiten können auf nahezu die gleiche Weise unterstützt werden. Dieser Ansatz hat Nachteile. Zum Beispiel können Sie rem nicht für andere Zwecke verwenden. Und Sie können nur eine Viewport-Einheit (vw) gleichzeitig verwenden und nicht andere wie vh, vmin oder vmax.

Während heute fast kein Produktionsbrowser echte CSS-Variablen unterstützt, erlauben es einige, ein wenig zu schummeln und eine in Form der rem-Einheit zu erhalten. Wenn Sie rem nicht für normale Schriftgrößen verwenden müssen, können Sie es zur Laufzeitskalierung von praktisch allem verwenden. Wenn Sie rem für Schriftgrößen verwenden müssen, haben Sie die Möglichkeit, CSS-Präprozessoren (Sass oder Less) zu verwenden, um korrekte Schriftgrößen zu berechnen, und lassen die rem-Einheit für Laufzeit-Tricksereien frei.