SELFHTML wird 30 Jahre alt! → Veranstaltungs-Ankündigung.
Transform
skalieren, schräg
stellen und
verschieben
Durch CSS-Transform kann die Form eines HTML- oder SVG-Elements zwei- oder drei-dimensional geändert werden. So lässt es sich etwa spiegeln, drehen oder scheren, aber auch verschieben. Eine solche Transformation ist auf viele HTML Elemente anwendbar, mit Ausnahme von nicht ersetzten Inline-Elementen.[1]
- Individuelle Transformations-Eigenschaften
- translate
- scale
- rotate
vs transform: translate() rotate() scale();
- Drehen, Kreisen und Pendeln
- Drehung mit rotate()
- transform-origin: Drehpunkt festlegen
- SVG-Transformationen
CSS vs XML-Attribute
- 3D-Transforms
- perspective
- perspective-origin
- transform-style
- backface-visibility
- Rube-Goldberg-Maschinen
einfache Maschinen mit animierten CSS-Transforms
Individuelle Transformations-Eigenschaften
In SVG konnte man Elemente mit dem transform-Attribut verschieben, drehen und spiegeln. Seit 2008 gab es in der CSS-Welt eine entsprechende CSS-Eigenschaft, die sogar 3D-Transformationen ermöglicht.
Im CSS Transforms Module Level 2 wurden zusätzlich die Einzeleigenschaften rotate, scale und translate eingeführt, die mittlerweile von allen Browsern unterstützt werden.[2] Mit ihnen ist es möglich, einfache Transformationen unabhängig voneinander zu festzulegen, und zwar in einer Weise, die der typischen Verwendung auf der Benutzeroberfläche entspricht, anstatt sich die Reihenfolge in transform merken zu müssen.
translate
Die translate-Eigenschaft verschiebt die Form eines HTML- oder SVG-Elements.
Sie erwartet einen, zwei oder drei Werte.
- translate erfordert ein, zwei oder drei mit Leerzeichen getrennte Werte ohne umschließende Klammern.
- die gleichlautende translate()-Funktion erfordert dagegen zwei kommaseparierte Werte innerhalb der Klammer.
@keyframes translating {
0% { translate: 0 0;}
25% { translate: 0;}
50% { translate: 20em 200px;}
75% { translate: 0 200px;}
100%{ translate: 0 0;}
}
.animiert {
animation: translating 4s linear infinite;
background: #dfac20;
}
Im Beispiel wird das aside-Element mit der CSS-animation translating
zuerst nach rechts, dann nach unten, nach links und dann wieder hoch zum Ausgangspunkt verschoben. Dabei wird der folgende Textabsatz kurzfristig verdeckt.
Für Effekte wie :hover
verhält sich das Element zunächst so, als befände es sich noch an seiner Ausgangsposition. Das klingt merkwürdig, aber andernfalls würde ein :hover
-Effekt, der das Element an eine andere Stelle schiebt, eventuell sofort den Effekt beenden und das Element hin und her flackern lassen. Erst dann, wenn die Maus in den Bereich kommt, den das Element an seiner Zielposition belegt, wird der Auslösebereich für :hover
auf die Zielposition gelegt.
Um ein Element zu transformieren und aus dem Elementfluss zu entfernen, kann man zusätzlich die Eigenschaft position auf absolute
oder fixed
setzen. Der Browser platziert das Element zunächst gemäß der position-Eigenschaft und transformiert es dann.
Eine Verschiebung alleine zeigt ihren Nutzen erst in Kombination mit anderen Transformationen:
scale
Die scale-Eigenschaft streckt, staucht oder verzerrt die Form eines HTML- oder SVG-Elements.
Sie erwartet einen, zwei oder drei Zahlenwerte als Streckungsfaktor(en).
Der Streckungsfaktor ist eine Zahl, das „Streckungszentrum“ (mathematisch korrekt die Fixpunktgerade) wird durch die Eigenschaft transform-origin
festgelegt. Wird dazu keine Angabe gemacht, so ist die Fixpunktgerade die durch den Mittelpunkt des Elements verlaufende Vertikale. Streckungsfaktoren größer als Eins vergrößern (strecken) das Element, Faktoren zwischen Null und Eins stauchen es und negative Faktoren spiegeln das Element an der Fixpunktgeraden.
Der Vollständigkeit halber sei erwähnt, dass k = 1
das Element unverändert lässt, wohingegen k = 0
die Breite des Elements auf Null setzt.
So kann man eine Parallelstreckung entlang der Horizontalen erreichen. Mit einem negativen Streckungsfaktor können einzelne Wörter oder Buchstaben gespiegelt werden:
.gespiegelt {
color: #c82f04;
display: inline-block;
scale: -1 1;
}
Alle Elemente der Klasse .gespiegelt
werden entlang der x-Achse gespiegelt. Damit dies bei den inline-Elementen span funktioniert, müssen sie einen display:inline-block
bekommen.
scale: -1 1
benötigt einen zweiten Parameter, damit nur die X-Achse gespigelt wird; hier wäre transform: scaleX(-1)
übersichtlicher.
#scale1:hover {
scale: 2 0.5;
translate: -50px 25px;
}
#scale2:hover {
scale: 2 0.5;
}
Innerhalb des svg-Elements werden zwei Sterne mit einem path-Element gezeichnet.
Hovert die Maus über einen Stern, wird dieser in der X-Achse um das Zweifache gestreckt und in der y-Achse auf die Hälfte gestaucht. Damit das Objekt nicht aus dem Element wandert, erfolgt beim linken Stern zusätzlich eine Verschiebung mit translate.
- scale erfordert ein, zwei oder drei mit Leerzeichen getrennte Zahlenwerte ohne umschließende Klammern.
- die gleichlautende scale()-Funktion erfordert dagegen zwei kommaseparierte Werte innerhalb der Klammer.
rotate
Die rotate-Eigenschaft dreht die Form eines HTML oder SVG-Elements. Sie wurde im CSS Transforms Module Level 2 als zusätzliche Möglichkeit bereitgestellt, ein Element unabhängig von den übrigen Transformationen rotieren zu können.
@keyframes pulse {
from {
scale: 1;
}
to {
scale: 1.2;
}
}
svg {
fill: rebeccapurple;
rotate: .40turn;
animation: 1s infinite alternate pulse;
}
Der Pfeil erhält zwei Transformationen. Die Animation der scale-Eigenschaft läuft unabhängig von der Drehung durch rotate ab.
Siehe auch Drehen, Kreisen und Pendeln
transform-Eigenschaft
Die klassische Eigenschaft für Transformationen ist die transform-Eigenschaft. Sie wendet eine 2D- oder 3D-Transformation auf ein Element an, indem eine oder mehrere Transform-Funktionen angewandt werden.
Die Syntax entspricht der „normalen“ CSS-Schreibweise:
transform: … function3(…) function2(…) function1(…);
Diese Transform-Funktionen gibt es:
#scale1:hover {
transform: translate(-50px) scale(2, 0.5);
}
#scale2:hover {
transform: scale(2, 0.5) translate(-50px, 25px);
}
Das Beispiel scheint identisch zum oberen Beispiel. Allerdings wird hier die transform-Eigenschaft verwendet. Nach dem Namen der Eigenschaft folgen mehrere durch Leerzeichen separierte CSS-Funktionen:
- die translate()-Funktion führt die Verschiebung eines Elements aus. Sie benötigt folgende Parameter:
- eine (positive oder negative) Längenangabe für die horizontale Verschiebung,
- eine (optionale) Längenangabe für die vertikale Verschiebung
Wenn nur ein Wert angegeben wird, wird nur die x-Achse verschoben.
- die scale()-Funktion für eine Streckung. Sie benötigt folgende Parameter:
- ein (positiver oder negativer) Zahlenwert für die horizontale
- eine (optionaler) Zahlenwert für die vertikale Streckung
Wird nur eine Zahl angegeben, so gilt dieser Streckungsfaktor für beide Richtungen.
Im Unterschied zur CSS-Syntax für Eigenschaften werden die Parameter in den CSS-Funktionen durch Kommas separiert!
Die Funktionen werden von rechts nach links abgearbeitet:
- der linke Stern wird gestreckt und dann, da auch der Startpunkt des path-Elements skaliert wird, wieder an seinen Ausgangspunkt verschoben.
- der linke Stern wird zuerst verschoben und dann gestreckt. Nach der Transformation findet er sich an anderer Stelle wieder.
Ausführungsreihenfolge mehrerer Transformationen
Gerade wenn Skalierungen oder Rotationen im Spiel sind, ist die Reihenfolge, in der Transformationen angewendet werden, von Bedeutung. Das ist schon kompliziert genug, wenn nur die transform-Eigenschaft genutzt wird, und zusammen mit den übrigen Eigenschaften, die ein Element verschieben können, wird es nicht einfacher.
Eine Einführung dazu, wie der Browser mehrere Transformationen zu einer 3D-Matrix kombiniert, findet man bei der Beschreibung von matrix3D()). Die CSS Spezifikation[3] definiert eindeutig, in welcher Reihenfolge diese Kombination vorzunehmen ist, und dadurch entsteht die folgende Ausführungsreihenfolge:
- Verschiebe das Element um den negierten transform-origin Vektor. Das geschieht, weil die Berechnungen, die einen Punkt um einen bestimmten Winkel drehen können, immer auf den Nullpunkt des Koordinatensystems bezogen sind. Diese erste Verschiebung bringt den gewünschten Bezugspunkt der Transformation nach (0,0,0).
- Wende die Transform-Funktionen der transform-Eigenschaft von rechts nach links an. Die zuletzt notierte Transform-Funktion wird zuerst ausgeführt - das vergisst man gerne
- Wende die offset-Eigenschaft an
- Wende die scale-Eigenschaft an
- Wende die rotate-Eigenschaft an
- Wende die translate-Eigenschaft an
- Verschiebe das Element um den transform-origin-Vektor, d.h. Schritt 1 wird rückgängig gemacht.
Neigen und Verzerren mit skewX()
Mit skewX() kann man ein Element neigen, bzw. verzerren. Durch dieses Schrägstellen können rechteckige Elemente zu Parallelogrammen geneigt werden. Im folgenden Beispiel sollen die Listenelemente der Navigation pfeilartig angeschrägt werden.
ul a {
background: lightgrey;
border: thin solid grey;
display: block;
margin: 0.5em 1em;
padding: 0.5em 1em;
text-decoration: none;
transform: skewX(-30deg);
}
ul a:hover {
background: #dfac20;
}
Die Elemente der Navigation werden zu Parallelogrammen verzerrt – leider aber auch der Text der beinhalteten Links!
Eine Möglichkeit wäre es, einem Kind-Element ul li a span
eine entsprechende positive Verzerrung zu geben. Allerdings würde der Text dann zweimal verzerrt werden und entsprechend unscharf dargestellt.
In der hier verwendeten Alternative werden die angeschrägten Parallelogramme nun durch Pseudoelemente ul a::before
gebildet. Diese werden mit z-index:-1;
in den Hintergrund geschoben.
Die Links der Navigation werden normal darüber dargestellt.
ul a {
display: block;
margin: 0.5em 1em;
position: relative;
text-decoration: none;
z-index: 0;
}
ul a::before {
background: lightgrey;
border: thin solid grey;
content: "\A0 ";
display: block;
height: 100%;
margin: -0.5em -1em;
padding: 0.5em 1em;
position: absolute;
transform: skewX(-30deg);
width: 100%;
z-index: -1;
}
Transformationen kombinieren
ul a::before { transform: skewX(-30%); } ul a:hover::before { /* überschreibt (wsl. unbeabsichtigt) die vorherige Transformation mit skewX() */ transform: scale(1.2); }
Eigentlich ist dieses CSS nicht falsch - es arbeitet nur anders als beabsichtigt. Anstatt die beiden CSS-Funktionen zu kombinieren, überschreibt die zweite Zuweisung den ersten Regelsatz.[4]
Die funktionierende Lösung wäre es, alle Funktionen in den Regelsatz einzuschließen, was aber dem DRY-Grundsatz widerspricht.
ul a::before {
transform: skewX(-30deg);
}
ul a:hover::before {
transform: translate(-5px) scale(1.1) skewX(-30deg);
}
Alternativ könnte man die kombinierte Transformation nur einmal notieren und die Werte mit custom properties immer wieder neu setzen:
ul a::before {
transform: translate(var(--translate)) scale(var(--scale)) skewX(-30deg);
--scale: 1;
--translate: 0;
}
ul a:hover::before {
--scale: 1.2;
--translate: -10px;
}
kombinierte Transformationen animieren
Wenn man die Transform-Eigenschaft animieren möchte, dann muss man wissen, wie der Browser dabei vorgeht. Es sind nämlich mehrere Fälle zu unterscheiden:
- Alle Transform-Funktionen von Start- und Zielzustand sind gleich
- In diesem Fall animiert der Browser jede Transform-Funktion einzeln. „Überrotationen“ wie (rotate(720deg) bleiben dabei erhalten.
- Ein Endzustand ist eine Erweiterung des anderen Endzustandes
- Dieser Fall liegt zum Beispiel vor, wenn an den Startzustand weitere Transform-Funktionen hinten angefügt werden. Der Browser sucht sich nun zu jeder angefügten Funktion den Wert, der zu einer identischen Transformation führt, also translate(0,0) oder scale(1), erweitert den kürzeren Zustand damit und animiert dann wieder jede Transform-Funktion einzeln
- Die 1:1 Zuordnung der Transform-Funktionen zwischen Start- und Endzustand kann nicht hergestellt werden
- Der Browser bildet von links nach rechts eine möglichst lange Kette zueinander passender Funktionen. Die übrigen Transform-Funktionen fasst er im Start- und Endzustanden jeweils zu einer Transformationsmatrix zusammen und interpoliert dann diese Matrix. Das geschieht nicht stumpf durch Interpolation der Matrix-Einzelwerte, statt dessen führt er eine Dekomposition der Matrizen in Einzeltransformationen durch, wodurch eine Liste von Transformationsfunktionen entsteht, deren Reihenfolge immer gleich ist. Und diese Einzeltransformationen werden dann interpoliert.
Sobald man den Browser zu einer Matrix-Animation zwingt, muss auf Überrotationen verzichtet werden. Der Rotationswinkel wird in Form von Sinus- und Cosinuswerten in die Matrix eingearbeitet, wodurch Winkel auf das Intervall [0°, 360°[ normiert werden.
Ein weiteres Problem bei animierten Transformationen ist, dass für Anfangs- und Endzustand immer die vollständige Liste der zu verwendenden Funktionen aufgeschrieben werden muss. Das führt bei späteren Änderungen schnell zu Fehlern, oder zumindest zu viel Arbeit, wenn eine Animation geändert werden soll und mehrere Keyframes vorliegen.
Wenn man das nicht möchte, gibt es mehrere Lösungsansätze.
Zum einen kann man prüfen, ob die neuen Einzeleigenschaften translate, scale und rotate für diesen Zweck passend sind. Schau dir dazu die Ausführungsreihenfolge der Transformationen an. Diese Eigenschaften kann man unabhängig von der transform-Eigenschaft animieren.
Alternative mit custom properties
Das umständliche Notieren aller Transformations-Funktionen lässt sich auch mithilfe von registrierten custom properties vereinfachen. Während unregistrierte custom properties vom Browser als Zeichenketten behandelt werden, die sich nur als "ist da" oder "ist nicht da" animieren lassen, kann die Registrierung dem Browser einen numerischen Datentyp für das Property liefern, für den eine Interpolation möglich ist.
Voraussetzung für diese Methode ist, dass die verwendeten Transform-Funktionen während der Animation gleich bleiben. Dann können die Transformationsfunktion in dem HTML Element, das animieren werden soll, notiert und die Werte darin, die animiert werden sollen, durch custom properties angegeben werden:
transform: rotate(.45turn) scale(var(--scale, 1));
Wenn das custom property --scale
nun als Zahl deklariert wird, kann man es in der @keyframes-Regel animieren und der Browser passt die Transformation entsprechend an. Von der zusätzlichen Rotation brauchen die Keyframes dann nichts mehr zu wissen. Allerdings ist die Registrierung von custom properties derzeit (2022) nur in Browsern der Chrome-Familie einsetzbar. Firefox und Safari unterstützen dagegen die Einzeleigenschaften, bei denen Chrome wiederum erst im August 2022 nachgezogen ist. Diese Methode ist deshalb zur Zeit nur für Anwendungsfälle relevant, wo man mit Einzeleigenschaften nicht zurechtkommt und wo man außerhalb der Chrome-Welt auch auf die Animation verzichten kann.
Das folgende Beispiel verwendet in älteren Chrome-Browsern custom properties und in Browsern, die die rotate-Eigenschaft unterstützen, Einzeleigenschaften.
@property --scale {
syntax: "<number>";
inherits: true;
initial-value: 1;
}
@keyframes pulse {
from { --scale: 1.0; }
to { --scale: 1.2; }
}
svg {
fill: rebeccapurple;
width: 12em;
transform: rotate(.45turn) scale(var(--scale, 1));
animation: 1s infinite alternate custom-pulse;
}
@supports (rotate: .45turn) {
svg {
transform: none;
rotate: .45turn;
}
@keyframes pulse {
from { scale: 1.0; }
to { scale: 1.2; }
}
}
@property legt fest, dass die selbstdefinierte Eigenschaft --scale
nur einheitenlose Zahlen enthalten darf, vererbt werden kann und einen Standardwert von 1 hat.
Die Feature-Abfrage auf rotate: .45turn
bewirkt, dass aktuelle Browser durchweg die Animation mit Einzeleigenschaften verwenden. Etwas ältere Chromebrowser fallen auf die custom property Animation zurück. Und Browser, die beides nicht kennen, lassen die Pfeilgröße zwischen klein und groß springen.
Siehe auch
- Polaroid-Bildergalerie
In dieser Bildergalerie werden Bilder als kleinere Vorschauansichten angezeigt. Ein Berühren mit der Maus skaliert sie auf die Originalgröße. Zusätzlich erscheint die bisher durch verborgene figcaption als Bildunterschrift. - Transform/Rube-Goldberg-Maschinen
unnötig komplizierte Maschinen, bei denen eine eigentlich triviale Aktion durch eine Kette nacheinander ablaufender Aktionen ausgelöst wird. Die SVG-Elemente werden mit CSS-Transforms animiert. - SELFHTML-Forum: Erläuterung der Orientierung der Scherung von Gunnar Bittersmann
Weblinks
- ↑ github: Intro to CSS 3D transforms (sehr gutes Tutorial mit vielen Beispielen von David DeSandro)
- ↑ CSSWG: CSS Transforms Module Level 2
- ↑ CSS Transforms 2
- ↑ css-tricks: Individual CSS Transform Functions Chris Coyier on Feb 23, 2017