Sie wissen schon, Porky Pig, der aus diesen roten Ringen kommt und das Ende eines Looney Tunes Cartoons ankündigt. Wir werden dorthin gelangen, aber zuerst müssen wir einige CSS-Konzepte behandeln.
Alles in CSS ist eine Box, oder ein Rechteck. Rechtecke stapeln sich und können über oder unter anderen Rechtecken angezeigt werden. Rechtecke können andere Rechtecke enthalten und Sie können sie so gestalten, dass das innere Rechteck außerhalb des äußeren Rechtecks sichtbar ist (sodass sie überlaufen) oder dass sie vom äußeren Rechteck abgeschnitten werden (mit overflow: hidden). Soweit so gut.
Was ist, wenn Sie möchten, dass ein Rechteck außerhalb seines umgebenden Rechtecks sichtbar ist, aber nur auf einer Seite? Das ist nicht möglich, oder?

Vielleicht, wenn Sie sich das Bild oben ansehen, beginnen die Räder zu drehen: Was wäre, wenn ich das innere Rechteck kopiere und die Hälfte davon abschneide und es dann genau positioniere? Aber wenn es darauf ankommt, können Sie nicht wählen, dass ein Element oben überläuft, aber unten abgeschnitten wird.
Oder doch?
3D-Transformationen
Mit 3D-Transformationen können Sie Elemente im 3D-Raum drehen, transformieren und verschieben. Hier ist eine Sammlung praktischer Beispiele, die ich zusammengestellt habe und die einige Möglichkeiten aufzeigen.
Damit 3D-Transformationen ihre Arbeit tun können, benötigen Sie zwei CSS-Eigenschaften
perspective, die mit einem Wert in Pixeln angibt, wie stark der 3D-Effekt isttransform-style: preserve-3d, um dem Browser mitzuteilen, dass Elemente, die im 3D-Raum positioniert sind, beibehalten werden sollen.
Selbst mit der guten Unterstützung für 3D-Transformationen sieht man 3D-Transformationen leider nicht allzu oft „in freier Wildbahn“. Websites sind immer noch eine „2D“-Sache, eine flache Seite, die scrollt. Aber als ich anfing, mit 3D-Transformationen zu experimentieren und Beispiele zu suchen, fand ich eines, das bei weitem das interessanteste in Bezug auf 3D-Transformationen war.

Das Bild zeigt deutlich drei Ebenen, aber dieser Effekt wird mit einem einzigen <div> erzielt. Die beiden anderen Ebenen sind die Pseudo-Elemente ::before und ::after, die mit translate() nach oben bzw. unten verschoben werden, um sich im 3D-Raum zu stapeln. Auffällig ist hier, wie das ::after-Element, das normalerweise über einem Element positioniert wäre, hinter diesem Element liegt. Der Ersteller konnte dies durch Hinzufügen von transform: translateZ(-1px); erreichen.
Obwohl dies eine von vielen 3D-Transformationen war, die ich bis zu diesem Zeitpunkt gesehen hatte, war es die erste, die mich erkennen ließ, dass ich tatsächlich Elemente im 3D-Raum positionierte. Und wenn ich das kann, kann ich auch Elemente miteinander überlappen lassen.

Ich konnte mir nicht vorstellen, wie diese Art von Sache nützlich sein könnte, aber dann sah ich die Porky Pig Cartoon-Animation. Er taucht hinter dem unteren Rahmen auf, aber sein Gesicht überlappt und stapelt sich auf der Oberkante desselben Rahmens – genau die gleiche Art von Beschneidungssituation, die wir zuvor gesehen haben. Da begannen meine Räder zu drehen. Könnte ich diesen Effekt nur mit CSS nachbilden? Und für zusätzliche Punkte, könnte ich ihn mit einem einzigen <div> nachbilden?
Ich begann zu experimentieren und hatte relativ schnell dies zu zeigen.

Hier haben wir ein einzelnes <div> mit seinen ::before und ::after Pseudo-Elementen. Das div selbst ist transparent, das ::before hat einen blauen Rand und das ::after wurde entlang der x-Achse gedreht. Da das div perspective hat, ist alles im 3D positioniert, und deshalb liegt das ::after-Pseudo-Element über dem Rand am oberen Rand des Rahmens und hinter dem Rand am unteren Rand des Rahmens.
Hier ist das in Code
div {
transform: perspective(3000px);
transform-style: preserve-3d;
position: relative;
width: 200px;
height: 200px;
}
div::before {
content: "";
width: 100%;
height: 100%;
border:10px solid darkblue;
}
div::after {
content: "";
position: absolute;
background: orangered;
width: 80%;
height: 150%;
display: block;
left: 10%;
bottom: -25%;
transform: rotateX(-10deg);
}
Mit perspective können wir bestimmen, wie weit ein Betrachter von „z=0“ entfernt ist, was wir als „Horizont“ unseres CSS 3D-Raums betrachten können. Je größer die Perspektive, desto weniger ausgeprägt ist der 3D-Effekt und umgekehrt. Für die meisten 3D-Szenen funktioniert ein perspective-Wert zwischen 500 und 1.000 Pixel am besten, obwohl Sie damit herumspielen können, um den gewünschten Effekt zu erzielen. Sie können dies mit der Perspektivzeichnung vergleichen: Wenn Sie zwei Horizontpunkte eng beieinander zeichnen, erhalten Sie eine sehr starke Perspektive; wenn sie weit voneinander entfernt sind, erscheinen die Dinge flacher.
Von Rechtecken zu Cartoons
Rechtecke sind lustig, aber was ich wirklich bauen wollte, war etwas wie das hier.

Ich konnte keine gut ausgeschnittene Version von Porky Pig aus diesem Bild finden oder erstellen, aber die Wikipedia-Seite enthält eine nette Alternative, also werden wir diese verwenden.
Zuerst müssen wir das Bild in drei Teile aufteilen.
<div>: der blaue Hintergrund hinter Porky::after: all die roten Kreise, die eine Art Tunnel bilden::before: Porky Pig selbst in seiner ganzen Pracht, als Hintergrundbild.
Wir beginnen mit dem <div>. Das wird der Hintergrund und die Basis für die restlichen Elemente sein. Es wird auch die perspective und transform-style Eigenschaften enthalten, die ich bereits erwähnt habe, zusammen mit einigen Größen und der Hintergrundfarbe.
div {
transform: perspective(3000px);
transform-style:preserve-3d;
position: relative;
width: 200px;
height: 200px;
background: #4992AD;
}
Okay, als nächstes kümmern wir uns um die roten Kreise. Das Element selbst muss transparent sein, da dies die Öffnung ist, aus der Porky auftaucht. Wie gehen wir also vor? Wir können einen Rand verwenden, genau wie im Beispiel weiter oben in diesem Artikel, aber wir haben nur einen Rand und dieser kann eine durchgehende Farbe haben. Wir brauchen eine Reihe von Kreisen, die Verläufe annehmen können. Wir können stattdessen box-shadow verwenden und mehrere Schatten in den Eigenschaftswerten verketten. Das gibt uns alle benötigten Kreise, und durch die Verwendung eines Blur-Radius von 0 mit einem großen Spread-Radius können wir die Erscheinung mehrerer „Ränder“ erzeugen.
box-shadow: <x-offset> <y-offset> <blur-radius> <spread-radius> <color>;
Wir verwenden einen border-radius, der so groß ist wie das <div> selbst, wodurch das ::before zu einem Kreis wird. Dann fügen wir die Schatten hinzu. Wenn wir ein paar rote Kreise mit großem Spread und verschwommenem Weiß hinzufügen, erhalten wir einen Effekt, der dem Porky's Tunnel sehr ähnlich sieht.
box-shadow: 0 0 20px 0px #fff, 0 0 0 30px #CF331F,
0 0 20px 30px #fff, 0 0 0 60px #CF331F,
0 0 20px 60px #fff, 0 0 0 90px #CF331F,
0 0 20px 90px #fff, 0 0 0 120px #CF331F,
0 0 20px 120px #fff, 0 0 0 150px #CF331F;
Hier fügen wir fünf Kreise hinzu, wobei jeder 30px breit ist. Jeder Kreis hat einen durchgehenden roten Hintergrund. Und durch die Verwendung von weißen Schatten mit einem Blur-Radius von 20px darüber erzeugen wir den Gradienten-Effekt.

Mit dem Hintergrund und den Kreisen sind wir nun dabei, Porky hinzuzufügen. Beginnen wir damit, ihn vorerst an der Stelle zu platzieren, an der er enden soll, oberhalb der Kreise.
div::before {
position: absolute;
content: "";
width: 80%;
height: 150%;
display: block;
left: 10%;
bottom: -12%;
background: url("Porky_Pig.svg") no-repeat center/contain;
}
Sie haben vielleicht den Schrägstrich in „center/contain“ für den background bemerkt. Das ist die Syntax, um sowohl die Position (center) als auch die Größe (contain) in der background-Kurzschreibweise der CSS-Eigenschaft festzulegen. Die Schrägstrich-Syntax wird auch in der font-Kurzschreibweise verwendet, wo sie zur Festlegung von font-size und line-height wie folgt verwendet wird: <font-size>/<line-height>.
Die Schrägstrich-Syntax wird in zukünftigen CSS-Versionen häufiger verwendet. Zum Beispiel kann die aktualisierte rgb() und hsl() Farbsyntax einen Schrägstrich gefolgt von einer Zahl nehmen, um die Opazität anzugeben, wie folgt: rgb(0 0 0 / 0.5). Auf diese Weise besteht keine Notwendigkeit, zwischen rgb() und rgba() zu wechseln. Dies funktioniert bereits in allen Browsern außer Internet Explorer 11.

Sowohl die Größe als auch die Positionierung sind hier etwas willkürlich, spielen Sie also damit, wie Sie möchten. Wir sind unserem Ziel schon viel näher, aber jetzt müssen wir es so hinbekommen, dass der untere Teil von Porky hinter den roten Kreisen liegt und sein Oberkörper sichtbar bleibt.
Der Trick
Wir müssen sowohl die Kreise als auch Porky im 3D-Raum verschieben. Wenn wir Porky drehen wollen, müssen wir ein paar Voraussetzungen erfüllen.
- Er sollte nicht durch den Hintergrund schneiden.
- Wir sollten ihn nicht so weit drehen, dass das Bild verzerrt wird.
- Sein Unterkörper sollte unter den roten Kreisen und sein Oberkörper darüber liegen.
Um sicherzustellen, dass Porky nicht durch den Hintergrund schneidet, verschieben wir zuerst die Kreise in Z-Richtung, damit sie näher am Betrachter erscheinen. Da preserve-3d angewendet wird, bedeutet dies, dass sie auch ein wenig hineinzoomen, aber wenn wir sie nur ein kleines bisschen bewegen, ist der Zoomeffekt nicht bemerkbar und wir haben genügend Abstand zwischen Hintergrund und Kreisen.
transform: translateZ(20px);
Nun Porky. Wir werden ihn um die X-Achse drehen, wodurch sich sein Oberkörper uns nähert und der untere Teil sich von uns wegbewegt. Das können wir tun mit.
transform: rotateX(-10deg);
Das sieht zunächst ziemlich schlecht aus. Porky ist teilweise hinter dem blauen Hintergrund verborgen und schneidet auch auf seltsame Weise durch die Kreise.

Wir können dies lösen, indem wir Porky „näher“ zu uns bewegen (wie wir es mit den Kreisen getan haben) mithilfe von translateZ(), aber eine bessere Lösung ist es, die Position unseres Drehpunktes zu ändern. Im Moment geschieht dies vom Zentrum des Bildes aus, wodurch sich die untere Hälfte des Bildes von uns wegdreht.
Wenn wir den Startpunkt der Drehung in Richtung des unteren Bildrands oder sogar etwas darunter verschieben, dreht sich das gesamte Bild zu uns. Und da wir die Kreise bereits näher zu uns bewegt haben, sieht am Ende alles so aus, wie es soll.
transform: rotateX(-10deg);
transform-origin: center 120%;

Um eine Vorstellung davon zu bekommen, wie alles im 3D funktioniert, klicken Sie auf „debug anzeigen“ im folgenden Pen.
Animation
Wenn wir die Dinge so belassen würden, wie sie sind – ein statisches Bild –, dann hätten wir uns all diese Mühe nicht machen müssen. Aber wenn wir Dinge animieren, können wir die Schichtung enthüllen und den Effekt verstärken.
Hier ist die Animation, die ich anstrebe: Porky beginnt klein unten hinter den Kreisen, zoomt dann herein und taucht aus dem blauen Hintergrund über den roten Kreisen auf. Er bleibt eine Weile dort, dann bewegt er sich wieder zurück.
Wir verwenden transform für die Animation, um die beste Leistung zu erzielen. Und da wir das tun, müssen wir sicherstellen, dass wir rotateX beibehalten.
@keyframes zoom {
0% {
transform: rotateX(-10deg) scale(0.66);
}
40% {
transform: rotateX(-10deg) scale(1);
}
60% {
transform: rotateX(-10deg) scale(1);
}
100% {
transform: rotateX(-10deg) scale(0.66);
}
}
Bald werden wir in der Lage sein, verschiedene Transformationen direkt einzustellen, da Browser damit beginnen, sie als einzelne CSS-Eigenschaften zu implementieren. Das bedeutet, dass das Wiederholen von rotateX(-10deg) irgendwann überflüssig wird; aber im Moment haben wir ein wenig Duplizierung.
Wir zoomen mit der Funktion scale() hinein und heraus, und da wir bereits einen transform-origin eingestellt haben, geschieht das Skalieren vom unteren Zentrum des Bildes aus, was genau der gewünschte Effekt ist! Wir animieren die Skalierung bis zu 60% der tatsächlichen Größe von Porky, wir haben die kleine Pause am größten Punkt, wo er vollständig aus dem Kreisrahmen herausspringt.
Die Animation wird auf das ::before-Pseudo-Element angewendet. Damit die Animation etwas natürlicher wirkt, verwenden wir eine ease-in-out-Timingfunktion, die die Animation am Anfang und Ende verlangsamt.
div::before {
animation-name: zoom;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-fill-mode:forwards;
animation-timing-function: ease-in-out;
}
Was ist mit reduzierter Bewegung?
Gut, dass Sie fragen! Für Menschen, die empfindlich auf Animationen reagieren und reduzierte oder keine Bewegung bevorzugen, können wir auf die Media Query prefers-reduced-motion zurückgreifen. Anstatt die vollständige Animation zu entfernen, zielen wir auf diejenigen ab, die reduzierte Bewegung bevorzugen, und verwenden einen subtileren Fade-Effekt anstelle der vollen Animation.
@media (prefers-reduced-motion: reduce) {
@keyframes zoom {
0% {
opacity:0;
}
100% {
opacity: 1;
}
}
div::before {
animation-iteration-count: 1;
}
}
Durch Überschreiben von @keyframes innerhalb einer Media Query übernimmt der Browser dies automatisch. Auf diese Weise betonen wir immer noch den Effekt, dass Porky aus den Kreisen auftaucht. Und durch das Setzen von animation-iteration-count auf 1 lassen wir die Leute den Effekt sehen, stoppen dann aber, um fortlaufende Bewegung zu verhindern.
Feinschliff
Zwei weitere Dinge können wir tun, um dies etwas lustiger zu gestalten.
- Wir können mehr Tiefe im Bild erzeugen, indem wir einen Schatten hinter Porky hinzufügen, der wächst, wenn er hervortritt und näher an die Ansicht heranzuzoomen scheint.
- Wir können Porky drehen, während er sich bewegt, um den Pop-Out-Effekt noch weiter zu verschönern.
Den zweiten Teil können wir mit rotateZ() in derselben Animation implementieren. Ganz einfach.
Aber der erste Teil erfordert einen zusätzlichen Trick. Da wir ein Bild für Porky verwenden, können wir box-shadow nicht verwenden, da dies einen Schatten um die Box des ::before-Pseudo-Elements erzeugt und nicht um die Form von Porky Pig.
Hier kommt filter: drop-shadow() zur Rettung. Es betrachtet die undurchsichtigen Teile des Elements und fügt stattdessen einen Schatten hinzu, anstatt um die Box herum.
@keyframes zoom {
0% {
transform: rotateX(-10deg) scale(0.66);
filter: drop-shadow(-5px 5px 5px rgba(0,0,0,0));
}
40% {
transform: rotateZ(-10deg) rotateX(-10deg) scale(1);
filter: drop-shadow(-10px 10px 10px rgba(0,0,0,0.5));
}
60% {
transform: rotateZ(-10deg) rotateX(-10deg) scale(1);
filter: drop-shadow(-10px 10px 10px rgba(0,0,0,0.5));
}
100% {
transform: rotateX(-10deg) scale(0.66);
filter: drop-shadow(-5px 5px 5px rgba(0,0,0,0));
}
}
Und so habe ich die Looney Tunes Animation von Porky Pig nachgebaut. Alles, was ich jetzt noch sagen kann, ist: „That’s all Folks!“
Das war exzellent! Ich habe die Detailtiefe der Erklärung wirklich genossen.
Erstaunlich! Inspiriert mich wirklich, das selbst auszuprobieren.
Danke für die Idee! Besonders nützlich für mein aktuelles Projekt.