Willkommen zu Teil 2 dieser dreiteiligen Serie! Wir schmücken Bilder immer noch ohne zusätzliche Elemente und Pseudoelemente. Ich hoffe, Sie haben sich bereits die Zeit genommen, Teil 1 zu verdauen, denn wir werden weiterhin mit vielen Verläufen arbeiten, um großartige visuelle Effekte zu erzielen. Wir werden auch die CSS-Eigenschaft mask für komplexere Dekorationen und Hover-Effekte einführen.
Fancy Image Decorations Serie
- Einzelelement-Magie
- Masken und fortgeschrittene Hover-Effekte (Sie sind hier!)
- Umrisse und komplexe Animationen
Wenden wir uns dem ersten Beispiel zu, an dem wir gemeinsam arbeiten…
Der Briefmarken-Effekt
Ob Sie es glauben oder nicht, alles, was benötigt wird, um einen Briefmarken-CSS-Effekt zu erzielen, sind zwei Verläufe und ein Filter
img {
--r: 10px; /* control the radius of the circles */
padding: calc(2 * var(--r));
filter: grayscale(.4);
background:
radial-gradient(var(--r),#0000 98%,#fff) round
calc(-1.5 * var(--r)) calc(-1.5 * var(--r)) / calc(3 * var(--r)) calc(3 * var(--r)),
linear-gradient(#fff 0 0) no-repeat
50% / calc(100% - 3 * var(--r)) calc(100% - 3 * var(--r));
}
Wie wir im vorherigen Artikel gesehen haben, besteht der erste Schritt darin, mit padding Platz um das Bild herum zu schaffen, damit wir einen Hintergrundverlauf zeichnen und ihn dort sehen können. Dann verwenden wir eine Kombination aus radial-gradient() und linear-gradient(), um diese Kreise um das Bild herum auszuschneiden.
Hier ist eine Schritt-für-Schritt-Illustration, die zeigt, wie die Verläufe konfiguriert sind
Beachten Sie die Verwendung des Werts round im zweiten Schritt. Er ist für den Trick sehr wichtig, da er sicherstellt, dass die Größe des Verlaufs so angepasst wird, dass er an allen Seiten perfekt ausgerichtet ist, unabhängig von der Bildbreite oder -höhe.
Aus der Spezifikation: Das Bild wird so oft wiederholt, wie es in den Hintergrundpositionierungsbereich passt. Wenn es keine ganze Anzahl von Malen passt, wird es so skaliert, dass es das tut.
Der abgerundete Rahmen
Betrachten wir eine weitere Bilddekoration, die Kreise verwendet…
Dieses Beispiel verwendet ebenfalls einen radial-gradient(), aber diesmal habe ich Kreise *um* das Bild herum erstellt, anstatt den Ausschnitteffekt. Beachten Sie, dass ich auch hier wieder den Wert round verwende. Der kniffligste Teil hier ist der transparente Abstand zwischen dem Rahmen und dem Bild, wo ich zur CSS-Eigenschaft mask greife
img {
--s: 20px; /* size of the frame */
--g: 10px; /* the gap */
--c: #FA6900;
padding: calc(var(--g) + var(--s));
background:
radial-gradient(farthest-side, var(--c) 97%, #0000)
0 0 / calc(2 * var(--s)) calc(2 * var(--s)) round;
mask:
conic-gradient(from 90deg at calc(2 * var(--s)) calc(2 * var(--s)), #0000 25%, #000 0)
calc(-1 * var(--s)) calc(-1 * var(--s)),
linear-gradient(#000 0 0) content-box;
}
Maskierung ermöglicht es uns, den Bereich des Bildes anzuzeigen – dank des linear-gradient() darin – sowie 20px um jede Seite davon – dank des conic-gradient(). Die 20px sind nichts anderes als die Variable --s, die die Größe des Rahmens definiert. Mit anderen Worten, wir müssen die Lücke verstecken.
Hier ist, was ich meine
Der lineare Verlauf ist der blaue Teil des Hintergrunds, während der konische Verlauf der rote Teil des Hintergrunds ist. Der transparente Teil zwischen beiden Verläufen ist das, was wir aus unserem Element ausschneiden, um die Illusion eines inneren transparenten Rahmens zu erzeugen.
Der innere transparente Rahmen
Für dieses Beispiel werden wir keinen Rahmen erstellen, sondern etwas anderes versuchen. Wir werden einen transparenten inneren Rahmen *innerhalb* unseres Bildes erstellen. Wahrscheinlich nicht sehr nützlich in einem realen Szenario, aber es ist eine gute Übung mit CSS-Masken.
Ähnlich wie im vorherigen Beispiel werden wir uns auf zwei Verläufe verlassen: einen linear-gradient() für den inneren Teil und einen conic-gradient() für den äußeren Teil. Wir lassen einen Abstand dazwischen, um den transparenten Rahmeneffekt zu erzeugen.
img {
--b: 5px; /* the border thickness */
--d: 20px; /* the distance from the edge */
--_g: calc(100% - 2 * (var(--d) + var(--b)));
mask:
conic-gradient(from 90deg at var(--d) var(--d), #0000 25%, #000 0)
0 0 / calc(100% - var(--d)) calc(100% - var(--d)),
linear-gradient(#000 0 0) 50% / var(--_g) var(--_g) no-repeat;
}

Sie haben vielleicht bemerkt, dass der konische Verlauf dieses Beispiels eine andere Syntax als im vorherigen Beispiel hat. Beide sollen die gleiche Form erzeugen, warum sind sie also unterschiedlich? Das liegt daran, dass wir mit verschiedenen Syntaxen dasselbe Ergebnis erzielen können. Das mag auf den ersten Blick verwirrend erscheinen, ist aber eine gute Funktion. Sie sind nicht verpflichtet, *die* Lösung zu finden, um eine bestimmte Form zu erreichen. Sie müssen nur eine Lösung finden, die für Sie funktioniert, aus den vielen Möglichkeiten, die es gibt.
Hier sind vier Möglichkeiten, das äußere Quadrat mit Verläufen zu erstellen
Es gibt noch mehr Möglichkeiten, dies zu bewerkstelligen, aber Sie verstehen das Prinzip.
Es gibt keinen besten™ Ansatz. Persönlich versuche ich, den mit dem kleinsten und optimiertesten Code zu finden. Für mich ist jede Lösung, die weniger Verläufe, weniger Berechnungen und weniger wiederholte Werte erfordert, am besten geeignet. Manchmal wähle ich eine ausführlichere Syntax, weil sie mir mehr Flexibilität beim Ändern von Variablen und Modifizieren von Dingen bietet. Das kommt mit Erfahrung und Übung. Je mehr Sie mit Verläufen spielen, desto mehr wissen Sie, welche Syntax Sie wann verwenden müssen.
Kommen wir zurück zu unserem inneren transparenten Rahmen und tauchen in den Hover-Effekt ein. Falls Sie es nicht bemerkt haben, gibt es einen coolen Hover-Effekt, der diesen transparenten Rahmen mithilfe eines font-size-Tricks bewegt. Die Idee ist, die Variable --d mit dem Wert 1em zu definieren. Diese Variable steuert den Abstand des Rahmens vom Rand. Wir können dies transformieren, wie folgt:
--_d: calc(var(--d) + var(--s) * 1em)
…was uns den folgenden aktualisierten CSS-Code ergibt:
img {
--b: 5px; /* the border thickness */
--d: 20px; /* the distance from the edge */
--o: 15px; /* the offset on hover */
--s: 1; /* the direction of the hover effect (+1 or -1)*/
--_d: calc(var(--d) + var(--s) * 1em);
--_g: calc(100% - 2 * (var(--_d) + var(--b)));
mask:
conic-gradient(from 90deg at var(--_d) var(--_d), #0000 25%, #000 0)
0 0 / calc(100% - var(--_d)) calc(100% - var(--_d)),
linear-gradient(#000 0 0) 50% / var(--_g) var(--_g) no-repeat;
font-size: 0;
transition: .35s;
}
img:hover {
font-size: var(--o);
}
Die font-size ist anfangs gleich 0, also ist 1em auch gleich 0 und --_d wird gleich --d sein. Beim Hovern ist die font-size jedoch gleich einem Wert, der durch eine Variable --o definiert wird, die den Versatz des Rahmens festlegt. Dies wiederum aktualisiert die Variable --_d und verschiebt den Rahmen um den Versatz. Dann füge ich eine weitere Variable, --s, hinzu, um das Vorzeichen zu steuern, das entscheidet, ob sich der Rahmen nach innen oder außen bewegt.
Der font-size-Trick ist sehr nützlich, wenn wir Eigenschaften animieren wollen, die ansonsten nicht animierbar wären. Mit @property definierte benutzerdefinierte Eigenschaften können dies lösen, aber die Unterstützung dafür ist zum Zeitpunkt, an dem ich dies schreibe, noch unzureichend.
Das Einblenden des Rahmens
Die folgende Einblendungsanimation haben wir im ersten Teil dieser Serie erstellt
Wir können die gleiche Idee aufgreifen, aber anstelle eines Rahmens mit einer Volltonfarbe verwenden wir einen Verlauf wie diesen
Wenn Sie beide Codes vergleichen, werden Sie die folgenden Änderungen bemerken
- Ich habe die gleiche Gradientenkonfiguration aus dem ersten Beispiel innerhalb der
mask-Eigenschaft verwendet. Ich habe die Verläufe einfach von derbackground-Eigenschaft zurmask-Eigenschaft verschoben. - Ich habe einen
repeating-linear-gradient()hinzugefügt, um den Gradientenrahmen zu erstellen.
Das ist alles! Ich habe die meiste Arbeit mit denselben Codes wiederverwendet, die wir bereits gesehen haben – mit super kleinen Anpassungen – und eine weitere coole Bilddekoration mit einem Hover-Effekt erhalten.
/* Solid color border */
img {
--c: #8A9B0F; /* the border color */
--b: 10px; /* the border thickness*/
--g: 5px; /* the gap on hover */
padding: calc(var(--g) + var(--b));
--_g: #0000 25%, var(--c) 0;
background:
conic-gradient(from 180deg at top var(--b) right var(--b), var(--_g))
var(--_i, 200%) 0 / 200% var(--_i, var(--b)) no-repeat,
conic-gradient(at bottom var(--b) left var(--b), var(--_g))
0 var(--_i, 200%) / var(--_i, var(--b)) 200% no-repeat;
transition: .3s, background-position .3s .3s;
cursor: pointer;
}
img:hover {
--_i: 100%;
transition: .3s, background-size .3s .3s;
}
/* Gradient color border */
img {
--b: 10px; /* the border thickness*/
--g: 5px; /* the gap on hover */
background: repeating-linear-gradient(135deg, #F8CA00 0 10px, #E97F02 0 20px, #BD1550 0 30px);
padding: calc(var(--g) + var(--b));
--_g: #0000 25%, #000 0;
mask:
conic-gradient(from 180deg at top var(--b) right var(--b), var(--_g))
var(--_i, 200%) 0 / 200% var(--_i, var(--b)) no-repeat,
conic-gradient(at bottom var(--b) left var(--b), var(--_g))
0 var(--_i, 200%) / var(--_i, var(--b)) 200% no-repeat,
linear-gradient(#000 0 0) content-box;
transition: .3s, mask-position .3s .3s;
cursor: pointer;
}
img:hover {
--_i: 100%;
transition: .3s, mask-size .3s .3s;
}
Versuchen wir eine weitere Rahmenanimation. Diese ist etwas knifflig, da sie eine dreistufige Animation hat
Der erste Schritt der Animation besteht darin, den unteren Rand größer zu machen. Dazu passen wir die background-size eines linear-gradient() an
Sie fragen sich wahrscheinlich, warum ich auch den oberen Rand hinzufüge. Wir brauchen ihn für den dritten Schritt. Ich versuche immer, den von mir geschriebenen Code zu optimieren, daher verwende ich einen Verlauf, um sowohl die oberen als auch die unteren Seiten abzudecken, aber die obere ist versteckt und wird später mit einer mask eingeblendet.
Für den zweiten Schritt fügen wir einen zweiten Verlauf hinzu, um die linken und rechten Ränder anzuzeigen. Aber diesmal tun wir es mit background-position
Wir können hier aufhören, da wir bereits einen schönen Effekt mit zwei Verläufen haben, aber wir sind hier, um die Grenzen zu erweitern, also fügen wir einen Hauch von Maske hinzu, um den dritten Schritt zu erreichen.
Der Trick besteht darin, den oberen Rand versteckt zu halten, bis wir die Unterseite und die Seiten anzeigen, und dann aktualisieren wir die mask-size (oder mask-position), um den oberen Teil anzuzeigen. Wie ich bereits sagte, können wir viele Gradientenkonfigurationen finden, um den gleichen Effekt zu erzielen.
Hier ist eine Illustration der Verläufe, die ich verwenden werde
Ich verwende zwei konische Verläufe mit einer Breite von 200%. Beide Verläufe decken den Bereich ab und lassen nur den oberen Teil unbedeckt (dieser Teil wird später unsichtbar sein). Beim Hovern schiebe ich beide Verläufe, um diesen Teil abzudecken.
Hier ist eine bessere Illustration eines der Verläufe, um Ihnen eine bessere Vorstellung davon zu geben, was passiert
Jetzt setzen wir das in die mask-Eigenschaft ein und sind fertig! Hier ist der vollständige Code
img {
--b: 6px; /* the border thickness*/
--g: 10px; /* the gap */
--c: #0E8D94;
padding: calc(var(--b) + var(--g));
--_l: var(--c) var(--b), #0000 0 calc(100% - var(--b)), var(--c) 0;
background:
linear-gradient(var(--_l)) 50%/calc(100% - var(--_i,80%)) 100% no-repeat,
linear-gradient(90deg, var(--_l)) 50% var(--_i,-100%)/100% 200% no-repeat;
mask:
conic-gradient(at 50% var(--b),#0000 25%, #000 0) calc(50% + var(--_i, 50%)) / 200%,
conic-gradient(at 50% var(--b),#000 75%, #0000 0) calc(50% - var(--_i, 50%)) / 200%;
transition:
.3s calc(.6s - var(--_t,.6s)) mask-position,
.3s .3s background-position,
.3s var(--_t,.6s) background-size,
.4s transform;
cursor: pointer;
}
img:hover {
--_i: 0%;
--_t: 0s;
transform: scale(1.2);
}
Ich habe auch einige Variablen eingeführt, um den Code zu optimieren, aber daran sollten Sie jetzt gewöhnt sein.
Was ist mit einer vierstufigen Animation? Ja, das ist möglich!
Keine Erklärung dafür, denn das ist Ihre Hausaufgabe! Nehmen Sie alles, was Sie in diesem Artikel gelernt haben, um den Code zu zerlegen und zu versuchen, zu artikulieren, was er tut. Die Logik ist ähnlich wie bei allen vorherigen Beispielen. Der Schlüssel ist, jeden Verlauf zu isolieren, um jeden Schritt der Animation zu verstehen. Ich habe den Code nicht optimiert, um die Dinge etwas leichter lesbar zu machen. Ich habe eine optimierte Version, falls Sie interessiert sind, aber Sie können auch versuchen, den Code selbst zu optimieren und ihn mit meiner Version zu vergleichen, um zusätzliche Übung zu erhalten.
Zusammenfassung
Das war's für Teil 2 dieser dreiteiligen Serie über kreative Bilddekorationen, die nur das <img>-Element verwenden. Wir haben jetzt ein gutes Verständnis dafür, wie Verläufe und Masken kombiniert werden können, um großartige visuelle Effekte und sogar Animationen zu erstellen – ohne zusätzliche Elemente oder Pseudoelemente. Ja, ein einziges <img>-Tag reicht aus!
Wir haben noch einen weiteren Artikel in dieser Serie vor uns. Bis dahin hier eine Bonus-Demo mit einem coolen Hover-Effekt, bei dem ich mask verwende, um ein zerbrochenes Bild zusammenzusetzen.
Fancy Image Decorations Serie
- Einzelelement-Magie
- Masken und fortgeschrittene Hover-Effekte (Sie sind hier!)
- Umrisse und komplexe Animationen
Großartige Sachen :) Besonders die Briefmarken- und Masken-Demos sind eine lustige Kunstrichtung