Startseite / Artikel / Von 66 % auf 185 px: Wie Browser CSS-Werte vor dem Layout berechnen

Von 66 % auf 185 px: Wie Browser CSS-Werte vor dem Layout berechnen

Verfolgen Sie einen CSS-Wert durch die Phasen „deklariert“, „kaskadiert“, „spezifiziert“, „berechnet“, „verwendet“ und „tatsächlich“ und erkennen Sie, warum relative Einheiten sowie der rem-Umrechnungstrick sich so verhalten.

1920 Wörter

Der Sieg in der Kaskadierung ist nicht das Ende der Reise einer CSS-Deklaration. Selbst wenn width: 50% alle konkurrierenden Regeln übertrifft, kann der Browser 50% noch nicht an seinen Layout-Engine weitergeben; er muss zunächst herausfinden, was zu fünfzig Prozent im aktuellen Kontext gemeint ist, und das in eine konkrete Größe umwandeln. Diese Anleitung verfolgt einen einzigen Wert durch jede Verarbeitungsstufe, die in den Spezifikationen definiert ist, zeigt auf, wo relative Einheiten wie rem und Prozentsätze berechnet werden, und erklärt das beliebte Konvertierungstrick von px zu rem samt dessen Einschränkungen hinsichtlich der Barrierefreiheit.

Der Wert, den Sie eingeben, ist nicht der Wert, der tatsächlich verwendet wird

Viel von dem, was Sie in einer Stylesheet eintragen, ist eher eine Beziehung als eine Messung. Eine Breite kann einen Anteil am Elternelement darstellen:

width: 50%;

oder in einer anderen Regel einen anderen Anteil:

width: 66%;

Die Schriftgröße kann relativ zur Schriftgröße des Wurzelelements sein:

font-size: 2rem;

Und die Höhe kann ein Bruchteil des Ansichtsfensters sein:

height: 50vh;

Keiner dieser Werte ist in Pixeln angegeben, doch das Layout benötigt letztendlich echte Abmessungen, um zu bestimmen, wohin jede Box kommt. Um diese Lücke zu überbrücken, wird jeder Wert durch eine feste Reihe von Schritten weitergeleitet:

Declared Value
      ↓
Cascaded Value
      ↓
Specified Value
      ↓
Computed Value
      ↓
Used Value
      ↓
Actual Value

Die Namen klingen anfangs wie Fachjargon, doch jeder Schritt beantwortet eine spezifische Frage. Die folgenden Abschnitte erläutern sie nacheinander anhand eines einzigen Beispiels.

Deklarierte Wert: Was Sie angefordert haben

Der deklarierte Wert ist einfach der Wert, wie er in einer Deklaration erscheint. Gegeben:

width: 66%;

Der deklarierte Wert für width ist 66%. Es handelt sich dabei um eine Anfrage, nichts weiter. Ein Element kann leicht mehrere deklarierte Werte für dieselbe Eigenschaft aus verschiedenen Regeln haben, weshalb die erste Aufgabe darin besteht, einen davon auszuwählen.

Kaskadierte Wert: der überlebende Wert

Stellen Sie sich zwei Regeln vor, die beide die Breite eines Absatzes festlegen. Eine verwendet einen Typ-Selektor:

p {
  width: 100px;
}

und die andere verwendet eine Klasse:

.amazing {
  width: 66%;
}

Falls ein Absatz die amazing-Klasse trägt, passen beide Regeln darauf. Der Klassenselektor ist spezifischer als der reine Elementselektor, weshalb die Kaskade folgendes wählt:

width: 66%;

Der überlebende 66%-Wert ist der kaskadierte Wert. Dieser Schritt ist wichtig, denn jede nachfolgende Stufe arbeitet nur mit dem einzigen Gewinner; verlorene Angaben werden verworfen und nicht weiterverarbeitet.

Spezifizierter Wert: Sicherstellung, dass jede Eigenschaft einen hat

Der spezifizierte Wert entsteht durch die Gewährleistung, dass jede Eigenschaft jedes Elements irgendeinen Wert hat. Die Regel ist einfach:

  • Falls es einen kaskadierten Wert gibt, wird dieser zum spezifizierten Wert;
  • Andernfalls ist für eine vererbte Eigenschaft der angegebene Wert der berechnete Wert des Elternteils;
  • Andernfalls ist es der Anfangswert der Eigenschaft, der Standard aus der Spezifikation.
  • In unserem Beispiel gibt es einen kaskadierten Wert, sodass der angegebene Wert weiterhin 66% ist und diese Stufe scheinbar nichts auslöst. Wichtig wird es für Eigenschaften, für die überhaupt keine Regel festgelegt ist – genau da kommt die Vererbung ins Spiel. Dieser Mechanismus wird im letzten Abschnitt behandelt.

    Berechneter Wert: Auflösen dessen, was ohne Layout ermittelt werden kann

    Der berechnete Wert ist der Punkt, an dem der Browser alles auflöst, was er ohne tatsächliches Layouten der Seite ermitteln kann. Relative Längen, die auf Schriftgrößen basieren, werden zu absoluten Längen, und Schlüsselwörter werden in konkrete Werte umgewandelt. Betrachten Sie:

    font-size: 2rem;
    

    Die Einheit hier:

    2rem
    

    Es wird eine Beziehung beschrieben, nämlich „doppelt so groß wie die Schriftgröße des Wurzelelements“, anstelle einer festen Messung. In der Berechnungsphase sucht der Browser nach der Schriftgröße des Wurzelelements und wandelt diesen Wert in Pixel um. Wenn die Schriftgröße des Wurzelelements 16px beträgt, liegt die berechnete Schriftgröße bei 32px.

    Ein Grund dafür, dass diese Umrechnung in dieser Phase stattfindet, ist die Vererbung: Der berechnete Wert wird von den Kinderelementen übernommen, sodass sie eine konkrete Länge erhalten anstelle einer Beziehung, die sie in ihrem eigenen Kontext neu interpretieren müssten. Deshalb verstärken sich geschachtelte em-Schriftgrößen auf diese Weise, und deshalb können prozentuale Zeilenhöhen manchmal zu engem Text bei Kinderelementen mit größeren Schriftgrößen führen.

    Einige Werte können noch nicht ermittelt werden. Eine prozentuale Breite hängt von der Größe des enthaltenden Blocks ab, die erst beim Layout bekannt ist. Daher bleibt 66% in der berechneten Wertung im Allgemeinen als Prozentsatz und wird erst in der nächsten Phase endgültig festgelegt.

    Verwendeter Wert: Einbezug von Layout-Informationen

    Der verwendete Wert ist das Ergebnis, sobald Layout-Informationen verfügbar sind. Zurück zu:

    width: 66%;
    

    Ein Prozentsatz ist für sich genommen unvollständig, solange nicht bekannt ist, welchen Anteil er darstellt. Für width ist diese Referenz die Breite des enthaltenden Blocks. Angenommen, der übergeordnete Abschnitt ist:

    280px
    

    breit. Der Browser kann nun berechnen:

    66% of 280px
    

    was wie folgt aussieht:

    184.8px
    

    Diese Zahl ist der tatsächlich verwendete Wert. Das ist der Wendepunkt im Prozess: Der Browser speichert nicht mehr den von Ihnen eingegebenen Prozentsatz, sondern eine echte Dimension, die aus der tatsächlichen Geometrie der Seite abgeleitet wird. Dasselbe gilt für Werte wie Breiten im Modus auto, die erst dann sinnvoll sind, wenn die umgebende Layoutstruktur bekannt ist. Wenn Sie ein Element in JavaScript mit getComputedStyle abfragen, liefern viele layoutabhängige Eigenschaften wie width diesen berechneten Pixelwert anstelle des Prozentsatzes – was eine praktische Möglichkeit ist, diesen Zustand in der Praxis zu beobachten.

    Tatsächlicher Wert: Anpassung an die Einschränkungen des Geräts

    In der letzten Phase werden die Grenzen der Darstellungsumgebung berücksichtigt. Ein Gerät kann nicht notwendigerweise einen Wert mit beliebiger Präzision darstellen, weshalb ein verwendeter Wert wie:

    184.8px
    

    eventuell ungefähr so dargestellt wird:

    185px
    

    Die angepasste Zahl ist der tatsächliche Wert. In der Praxis legen moderne Browser mit subpixelgenauer Präzision aus und wenden je nach Eigenschaft und Engine an verschiedenen Stellen Rundung oder Anpassung an, daher sollte man sich nicht auf eine bestimmte Rundungsregel verlassen. Die wichtige Idee ist einfach, dass es eine endgültige Anpassung zwischen dem berechneten Wert und dem geben kann, was auf dem Bildschirm angezeigt wird.

    Insgesamt lässt sich die gesamte Abfolge auf einen Satz reduzieren: was man in einer Stylesheet schreibt, ist nicht unbedingt das, was der Browser letztendlich verwendet, und es gibt dabei klar definierte Schritte dazwischen.

    Warum relative Einheiten weniger rätselhaft werden

    Dieses Modell erklärt, warum relative Einheiten so wertvoll sind und doch so oft falsch verstanden werden. Solche Einheiten wie:

    %
    rem
    em
    vh
    vw
    

    Erlaubt es, Größen in Bezug auf etwas anderes zu beschreiben (den Elternelement, die Root-Schriftgröße, die eigene Schriftgröße des Elements oder den Ansichtsbereich) anstelle von fest codierten Pixeln. Dadurch passen sich Layouts an verschiedene Bildschirme und Benutzereinstellungen an.

    Jede dieser Einheiten muss jedoch vor ihrer Verwendung im Layout gegen ihren Referenzwert ausgewertet werden, und dies geschieht in verschiedenen Phasen: font-relative Einheiten in der Berechnungsphase, Prozentsätze gegenüber dem enthaltenden Block in der Verwendungsphase. Wenn man den Bearbeitungspfad im Hinterkopf hat, kann man die vage Vorstellung, „der Browser klärt das schon“, durch eine präzisere Frage während des Debuggens ersetzen: Wovon hängt dieser Wert ab, und welcher Referenzwert gilt gerade? Wenn ein responsives Layout nicht wie erwartet funktioniert, liegt das Problem oft an einem Referenzwert, der von dem abweicht, was man angenommen hat – beispielsweise ein Prozentsatz, der sich auf einen unerwarteten enthaltenden Block bezieht, oder ein em-Wert, der durch mehrere verschachtelte Elemente beeinflusst wird.

    Umrechnung von px in rem mit einer Wurzelgröße von 10px

    Das Verständnis der Wertverarbeitung klärt auch einen gängigen Größenanpassungsworkflow auf: die Umwandlung von Pixelwerten aus einem Design in rem. Angenommen, ein Design legt Folgendes fest:

    padding: 30px;
    

    und man möchte es lieber wie folgt ausdrücken:

    padding: 3rem;
    

    Ein beliebter Ansatz besteht darin, die Größe der Grundschrift auf eine gerundete Zahl zu setzen:

    html {
      font-size: 10px;
    }
    

    Sobald das gesetzt ist:

    1rem = 10px
    

    werden die Umrechnungen zu mentaler Arithmetik:

    30px → 3rem
    40px → 4rem
    20px → 2rem
    

    Im Allgemeinen:

    rem = pixels / 10
    

    Der Vorteil liegt nicht nur in ordentlicheren Zahlenwerten. Da jeder rem-Wert in der Berechnungsphase anhand der Grundschriftgröße bestimmt wird, führt eine Änderung dieser einen Grundwert dazu, dass alle auf rem-Basis gemessenen Werte auf der Seite gleichzeitig neu skaliert werden – was eine einheitliche globale Kontrolle über das Größenverwaltungssystem ermöglicht.

    Es gibt eine wichtige Einschränkung. Die Einstellung der Wurzel auf einen festen Wert von 10px überschreibt die Standard-Schriftgröße, die ein Benutzer in den Einstellungen seines Browsers gewählt haben könnte, was einen der Hauptgründe für die Verwendung von rem aus Sicht der Barrierefreiheit untergräbt. Eine weit verbreitete Alternative ist html { font-size: 62.5%; }: Bei der standardmäßigen Browser-Einstellung von 16px ergibt sich dadurch weiterhin 10px, doch es skaliert proportional, wenn der Benutzer seine bevorzugte Größe erhöht. Wenn Sie dieses Muster verwenden, vergessen Sie nicht auch eine lesbare Schriftgröße für body festzulegen (zum Beispiel 1.6rem), da der Text sonst standardmäßig auf die verringerte Wurzelgröße zurückgreifen würde.

    Wenn überhaupt nichts deklariert wurde

    Eine Frage bleibt durch die oben genannten Schritte unbeantwortet. Nehmen wir diese Markup-Struktur:

    <div class="parent">
      <p>Hello World</p>
    </div>
    

    und eine Regel für den Wrapper:

    .parent {
      color: red;
    }
    

    Irgendwo gibt es keine Regel wie:

    p {
      color: red;
    }
    

    Doch der Text des Absatzes ist rot. Der Absatz weist keine kaskadierte color-Einstellung auf, sodass der angegebene Wert von einem anderen Ort stammen muss. Da color eine vererbte Eigenschaft ist, verwendet der Browser die berechnete Farbe des Elternelements. Das ist Erbschaft, und sie greift direkt in die zuvor beschriebene Phase der angegebenen Werte ein. Um detailliert zu erfahren, welche Eigenschaften vererbt werden, warum Kinderelemente berechnete statt deklarierte Werte erhalten und wie inherit sowie initial die Standardwerte überschreiben, verdient die Erbschaft eine eigene ausführliche Behandlung.

    Kernpunkte

    • Ein CSS-Wert durchläuft sechs Phasen: deklariert, kaskadiert, angegeben, berechnet, verwendet und tatsächlich.
    • Durch die Kaskade werden viele deklarierte Werte auf einen einzigen kaskadierten Wert reduziert; nur dieser wird weiter verarbeitet.
  • Der angegebene Wert fällt bei Nichtdeklaration auf die Vererbung oder den Initialwert zurück.
  • Schriftart-bezogene Einheiten wie rem und em werden in der Berechnungsphase zu absoluten Längen; Prozentsatzbreiten warten auf die Layout-Phase und werden in der Verwendungsphase festgelegt.
  • Der tatsächliche Wert kann aufgrund von Gerätebeschränkungen angepasst werden, daher sollte man nicht auf ein exaktes Rundungsverhalten vertrauen.
  • Das 10px-Root-Trick erleichtert die Umrechnung in rem, doch 62,5% berücksichtigt die Schriftart-Einstellungen des Benutzers besser als ein fester Wert von 10px.