mitmario.dev

transform

CSS Im Browser 4 Min Lesezeit 4 BeispieleLektion 2 von 6

Ein größerer Innenabstand schiebt die Nachbarn weg, ein Außenabstand ebenso. transform tut das nicht. Es nimmt das fertig ausgerechnete Element und zeichnet es woanders hin. Sein Platz im Fluss bleibt dabei, wo er war.

Die vier Funktionen

Die vier Funktionen
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 24px;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
}

.reihe {
  display: flex;
  gap: 24px;
}

.platz {
  border: 1px dashed #a1a1aa;
}

.kasten {
  display: block;
  width: 96px;
  padding: 16px 8px;
  text-align: center;
  font-size: 13px;
  color: #ffffff;
  background-color: #2563eb;
}

.verschoben {
  transform: translate(12px, -12px);
}

.gedreht {
  transform: rotate(15deg);
}

.skaliert {
  transform: scale(1.2);
}

.geneigt {
  transform: skewX(-12deg);
}

.hinweis {
  max-width: 60ch;
  margin-top: 32px;
  color: #52525b;
}

translate(x, y) verschiebt, rotate() dreht, scale() vergrößert oder verkleinert, skew() neigt. Zu jeder gibt es Varianten für eine Achse, also translateX(), scaleY() und so weiter.

Dazu zwei Kleinigkeiten. Bei translate() beziehen sich Prozentangaben auf das Element selbst und nicht auf den Elternteil. Deshalb funktioniert translateX(-50%) als Zentrierhilfe.

Bei scale() wird alles mitskaliert, auch Schrift, Rahmen und Schatten. Schrift und Vektorformen zeichnet der Browser bei einem festen Wert in voller Auflösung neu, die bleiben also scharf. Ein Bild im Element wird unscharf, sobald es über seine eigene Auflösung hinaus wächst. Während einer laufenden Animation kann sogar alles unscharf werden, denn dort streckt der Browser oft eine fertig gezeichnete Ebene, statt bei jedem Bild neu zu zeichnen.

Um den gestrichelten Rahmen im Beispiel geht es eigentlich. Der Platz bleibt, wo er war, und der blaue Kasten hängt darüber wie ein Aufkleber. Eine Vergrößerung schiebt deshalb auch nichts zur Seite. Sie kann Nachbarn überdecken.

Das lässt sich nachmessen. Bei den vier blauen Kästen steht oben im Streifen jedes Mal etwas anderes, rund 96 × 52 beim verschobenen, rund 106 × 75 beim gedrehten, rund 115 × 62 beim skalierten. In der Zeile width darunter steht bei allen vieren 96px, und der gestrichelte Platz darum misst durchgehend rund 98 × 54. Oben steht, was du siehst, und unten, was im Layout gilt. transform ändert nur das Obere.

Eine Zeile transform steht dort auch, aber nie so wie im Stylesheet. Aus translate(12px, -12px) wird matrix(1, 0, 0, 1, 12, -12), aus rotate(15deg) wird matrix(0.97, 0.26, -0.26, 0.97, 0, 0). So rechnet der Browser jede Kette von Funktionen zusammen. Die beiden letzten Zahlen sind die Verschiebung, davor steht der Rest.

Die Reihenfolge ist nicht egal

Die Reihenfolge entscheidet
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 24px;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
}

.bahn {
  margin: 0 0 48px 0;
  border-top: 1px dashed #a1a1aa;
}

.kasten {
  display: inline-block;
  padding: 8px 16px;
  font-size: 13px;
  color: #ffffff;
  background-color: #2563eb;
}

.erst-drehen {
  transform: rotate(20deg) translateX(120px);
}

.erst-schieben {
  transform: translateX(120px) rotate(20deg);
}

.hinweis {
  max-width: 60ch;
  color: #52525b;
}

Mehrere Funktionen schreibst du hintereinander in einen Wert, getrennt durch Leerzeichen. Der Browser wendet sie von links nach rechts an, und jede arbeitet in dem Koordinatensystem, das die vorherige hinterlassen hat.

Wer erst dreht und dann schiebt, schiebt also in die gedrehte Richtung. Wer erst schiebt und dann dreht, schiebt nach rechts und dreht dann an Ort und Stelle. Dieselben zwei Angaben, zwei verschiedene Ergebnisse. Wenn das Ergebnis nicht stimmt, ist die Reihenfolge die erste Stelle, an der ich nachsehe.

Der Drehpunkt

Der Drehpunkt lässt sich verschieben
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 48px 24px;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
}

.reihe {
  display: flex;
  gap: 48px;
}

.platz {
  border: 1px dashed #a1a1aa;
}

.kasten {
  display: block;
  width: 110px;
  padding: 16px 8px;
  text-align: center;
  font-size: 13px;
  color: #ffffff;
  background-color: #2563eb;
  rotate: 25deg;
}

.mitte {
  transform-origin: center;
}

.oben-links {
  transform-origin: top left;
}

.unten {
  transform-origin: bottom center;
}

.hinweis {
  max-width: 60ch;
  margin-top: 48px;
  color: #52525b;
}

Von allein dreht und skaliert alles um die Mitte des Elements. transform-origin verschiebt diesen Punkt, entweder mit Schlüsselwörtern wie top left, mit Prozentangaben oder mit Längen. Bei einem Menü, das aus einer Ecke aufklappt, macht diese Eigenschaft den Unterschied zwischen “erscheint” und “wächst aus dem Button heraus”.

Im Streifen findest du hier ausnahmsweise nichts, denn transform-origin steht nicht darin. Die drei Kästen des Beispiels messen sogar gleich, rund 121 × 93 und rotate: 25deg an jedem. Verschieden ist nur, wo sie liegen, und die Lage steht nicht im Streifen. Dafür gibt es die gestrichelten Rahmen im Beispiel.

Die getrennten Eigenschaften

Getrennt notiert statt in transform
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 24px;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
}

.bahn {
  margin: 0 0 48px 0;
}

.kasten {
  display: inline-block;
  padding: 8px 16px;
  font-size: 13px;
  color: #ffffff;
  background-color: #2563eb;
  transition: transform 0.2s ease-out, scale 0.2s ease-out;
}

.shorthand {
  transform: rotate(-6deg);
}

.shorthand:hover {
  transform: scale(1.15);
}

.getrennt {
  rotate: -6deg;
}

.getrennt:hover {
  scale: 1.15;
}

.hinweis {
  max-width: 60ch;
  color: #52525b;
}

translate, rotate und scale gibt es auch als eigene Eigenschaften, und alle großen Browser können sie seit August 2022. Sie wirken zusätzlich zu transform und lösen zwei Probleme auf einmal.

Das erste ist die Reihenfolge. Sie werden immer in der Folge translate, rotate, scale angewendet, egal wie du sie notierst, und erst danach kommt ein eventuelles transform.

Das zweite ist das Überschreiben. Eine zweite transform-Angabe ersetzt die erste komplett, auch die Teile, die du behalten wolltest. Das ist ganz normale Kaskade. transform ist eine einzige Eigenschaft, und die spätere Deklaration gewinnt, egal wie viele Funktionen darin stehen.

Im Beispiel verliert der obere Kasten beim Überfahren seine Drehung und der untere nicht. Im Streifen ist das schwarz auf weiß zu sehen. Am oberen steht beim Überfahren eine einzige Zeile, transform: matrix(1.15, 0, 0, 1.15, 0, 0). Die 1,15 ist die Vergrößerung, und von der Drehung ist nichts übrig, denn die beiden schrägen Zahlen stehen auf 0. Beim unteren stehen zwei eigene Zeilen untereinander, rotate: -6deg und scale: 1.15. Die Drehung ist noch da, weil sie nie zur Debatte stand.

Für einen einzelnen festen Effekt nehme ich transform, das ist kürzer. Sobald sich mehrere Regeln oder Zustände einzelne Teile teilen, nehme ich die getrennten Eigenschaften.

Warum transform überall auftaucht

transform gehört zusammen mit opacity zu den wenigen Eigenschaften, die der Browser bewegen kann, ohne das Layout neu zu rechnen und ohne die Fläche neu zu zeichnen. Die getrennten Schreibweisen translate, rotate und scale zählen mit, es ist derselbe Mechanismus. Der Browser verschiebt dabei eine fertige Ebene, und das schafft auch ein altes Telefon flüssig. In Lektion 13.4 wird daraus eine Regel.

Zwei Nebenwirkungen kennst du aus Abschnitt 8. Beide hängen nicht an der Schreibweise, transform, translate, rotate und scale lösen sie gleichermaßen aus.

Ein Element mit einer dieser Angaben öffnet einen eigenen Stacking Context. z-index-Werte darin gelten dann nur noch untereinander. Außerdem wird es zum Bezugsrahmen für Nachfahren mit position: absolute und position: fixed, und die richten sich dann an ihm aus statt am nächsten positionierten Vorfahren oder am Viewport. Wenn eine fixierte Kopfzeile plötzlich mitscrollt, steht meistens irgendwo darüber eine dieser vier Angaben.

In der Aufgabe hängt an einer von zwei Karten ein Badge, und ihr Hover springt noch.

Zum Mitnehmen

transform bewegt die Darstellung, ohne den Platz im Layout zu ändern. Die Reihenfolge der Funktionen zählt, und die getrennten Eigenschaften translate, rotate und scale überschreiben einander nicht.

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

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.