Äh, was ist @property? Es ist ein neues CSS-Feature! Es gibt dir Superkräfte. Kein Scherz, es gibt Dinge, die @property tun kann, die Dinge in CSS freischalten, die wir noch nie zuvor tun konnten.
Während alles an @property spannend ist, ist vielleicht das Interessanteste, dass es eine Möglichkeit bietet, einen Typ für benutzerdefinierte CSS-Eigenschaften anzugeben. Ein Typ liefert dem Browser mehr kontextbezogene Informationen, und das führt zu etwas Coolen: Wir können dem Browser die Informationen geben, die er benötigt, um diese Eigenschaften zu transittieren und zu animieren!
Aber bevor wir uns zu sehr freuen, ist es erwähnenswert, dass die Unterstützung noch nicht ganz da ist. Zum jetzigen Zeitpunkt wird @property in Chrome und damit in Edge unterstützt. Wir müssen die Browserunterstützung im Auge behalten, um zu sehen, wann wir dies auch an anderen Orten, wie Firefox und Safari, nutzen können.
Zuerst einmal bekommen wir Typprüfung
@property --spinAngle {
/* An initial value for our custom property */
initial-value: 0deg;
/* Whether it inherits from parent set values or not */
inherits: false;
/* The type. Yes, the type. You thought TypeScript was cool */
syntax: '<angle>';
}
@keyframes spin {
to {
--spinAngle: 360deg;
}
}
Das stimmt! Typprüfung in CSS. Es ist sozusagen, als würden wir unsere eigene kleine CSS-Spezifikation erstellen. Und das ist ein einfaches Beispiel. Schauen Sie sich all die verschiedenen Typen an, die uns zur Verfügung stehen
length (Länge)numberpercentage (Prozentwert)length-percentagecolorimage (Bild)urlintegerangle (Winkel)time (Zeit)resolutiontransform-listtransform-functioncustom-ident(eine benutzerdefinierte Identifikatorzeichenkette)
Davor haben wir uns vielleicht auf "Tricks" verlassen, um Animationen mit benutzerdefinierten Eigenschaften anzutreiben.
CSS-Variablen sind großartig, oder? Aber die Macht der Geltungsbereiche wird oft übersehen. Nehmen Sie zum Beispiel diese Demo, 3 verschiedene Animationen, aber nur 1 definierte Animation 💪 Das bedeutet dynamische Animationen 😎 https://#/VN02NlC4G8 via @CodePen #CSS #animation #webdev #webdesign #coding pic.twitter.com/ig8baxr7F3
— Jhey 🐻🛠 (@jh3yy) November 5, 2019
Was können wir dann Cooles machen? Schauen wir uns das an, um unsere Fantasie anzuregen.
Lassen Sie uns Farbe animieren
Wie könnte man ein Element durch eine Reihe von Farben oder zwischen ihnen animieren? Ich bin ein großer Verfechter des HSL-Farbraums, der Dinge in recht verständliche Zahlen aufteilt: Helligkeit, Sättigung und Leichtigkeit, jeweils.
Eine Helligkeit zu animieren, fühlt sich nach etwas Lustigem an, das wir tun können. Was ist bunt? Ein Regenbogen! Es gibt verschiedene Möglichkeiten, einen Regenbogen zu erstellen. Hier ist eine
In diesem Beispiel werden CSS Custom Properties auf die verschiedenen Bänder des Regenbogens gesetzt, wobei :nth-child() verwendet wird, um sie auf einzelne Bänder zu beschränken. Jedes Band hat auch einen --index, der zur Größenbestimmung dient.
Um diese Bänder zu animieren, könnten wir diesen --index verwenden, um einige negative Animationsverzögerungen einzustellen, aber dann dieselbe Keyframe-Animation verwenden, um durch die Helligkeiten zu wechseln.
.rainbow__band {
border-color: hsl(var(--hue, 10), 80%, 50%);
animation: rainbow 2s calc(var(--index, 0) * -0.2s) infinite linear;
}
@keyframes rainbow {
0%, 100% {
--hue: 10;
}
14% {
--hue: 35;
}
28% {
--hue: 55;
}
42% {
--hue: 110;
}
56% {
--hue: 200;
}
70% {
--hue: 230;
}
84% {
--hue: 280;
}
}
Das könnte ganz gut funktionieren, wenn Sie einen "gestuften" Effekt wünschen. Aber diese Keyframe-Schritte sind nicht besonders genau. Ich habe Schritte von 14% als grobe Sprünge verwendet.
Wir könnten die border-color animieren und das würde die Aufgabe erledigen. Aber wir hätten immer noch ein Problem mit der Berechnung der Keyframe-Schritte. Und wir müssen viel CSS schreiben, um das zu erreichen
@keyframes rainbow {
0%, 100% {
border-color: hsl(10, 80%, 50%);
}
14% {
border-color: hsl(35, 80%, 50%);
}
28% {
border-color: hsl(55, 80%, 50%);
}
42% {
border-color: hsl(110, 80%, 50%);
}
56% {
border-color: hsl(200, 80%, 50%);
}
70% {
border-color: hsl(230, 80%, 50%);
}
84% {
border-color: hsl(280, 80%, 50%);
}
}
Geben Sie @property ein. Beginnen wir damit, eine benutzerdefinierte Eigenschaft für die Helligkeit zu definieren. Dies teilt dem Browser mit, dass unsere benutzerdefinierte Eigenschaft --hue eine Zahl ist (keine Zeichenkette, die wie eine Zahl aussieht)
@property --hue {
initial-value: 0;
inherits: false;
syntax: '<number>';
}
Helligkeitswerte in HSL können von 0 bis 360 reichen. Wir beginnen mit einem Anfangswert von 0. Der Wert wird nicht vererbt. Und unser Wert ist in diesem Fall eine Zahl. Die Animation ist so einfach wie
@keyframes rainbow {
to {
--hue: 360;
}
}
Ja, das ist der richtige Weg
Um die Startpunkte genau zu machen, könnten wir mit Verzögerungen für jedes Band spielen. Das gibt uns einige coole Flexibilität. Zum Beispiel können wir die animation-duration erhöhen und erhalten einen langsamen Zyklus. Spielen Sie mit der Geschwindigkeit in dieser Demo.
Es ist vielleicht nicht das "wildeste" Beispiel, aber ich denke, die Animation von Farben bietet einige lustige Möglichkeiten, wenn wir Farbräume verwenden, die logische Zahlen nutzen. Die Animation durch das Farbrad erforderte bisher einige Kniffe. Zum Beispiel das Generieren von Keyframes mit einem Präprozessor wie Stylus
@keyframes party
for $frame in (0..100)
{$frame * 1%}
background 'hsl(%s, 65%, 40%)' % ($frame * 3.6)
Das tun wir nur, weil der Browser dies nicht versteht. Er sieht den Übergang von 0 auf 360 auf dem Farbrad als sofortige Überblendung, da beide HSL-Werte dieselbe Farbe anzeigen.
@keyframes party {
from {
background: hsl(0, 80%, 50%);
}
to {
background: hsl(360, 80%, 50%);
}
}
Die Keyframes sind gleich, daher nimmt der Browser an, dass die Animation beim gleichen background-Wert bleibt, obwohl wir eigentlich möchten, dass der Browser das gesamte Helligkeitsspektrum durchläuft, beginnend mit einem Wert und endend mit demselben Wert, nachdem er die Bewegungen ausgeführt hat.
Denken Sie an all die anderen Möglichkeiten, die wir hier haben. Wir können
- die Sättigung animieren
- unterschiedliche Easing-Funktionen verwenden
- die Leichtigkeit animieren
rgb()ausprobierenhsl()-Grade ausprobieren und unseren benutzerdefinierten Eigenschaftstyp als<angle>deklarieren
Das Coole ist, dass wir diesen animierten Wert über Elemente mit Geltungsbereichen hinweg teilen können! Betrachten Sie diesen Button. Der Rahmen und der Schatten animieren beim Überfahren mit der Maus durch das Farbrad.
Das Animieren von Farben lässt mich denken... *wow!*
Reine Nummerierung
Da wir Typen für Zahlen definieren können – wie integer und number – bedeutet dies, dass wir Zahlen auch animieren können, anstatt diese Zahlen als Teil von etwas anderem zu verwenden. Carter Li hat hier auf CSS-Tricks tatsächlich einen Artikel darüber geschrieben: Animieren von Zahlenzählern. Der Trick besteht darin, einen integer in Kombination mit CSS-Zählern zu verwenden. Dies ähnelt der Art und Weise, wie wir den Zähler in "Pure CSS"-Spielen wie diesem hier handhaben.
Die Verwendung von counter und Pseudoelementen bietet eine Möglichkeit, eine Zahl in eine Zeichenkette umzuwandeln. Dann können wir diese Zeichenkette für den content eines Pseudoelements verwenden. Hier sind die wichtigen Teile
@property --milliseconds {
inherits: false;
initial-value: 0;
syntax: '<integer>';
}
.counter {
counter-reset: ms var(--milliseconds);
animation: count 1s steps(100) infinite;
}
.counter:after {
content: counter(ms);
}
@keyframes count {
to {
--milliseconds: 100;
}
}
Was uns so etwas gibt. Ziemlich cool.
Nehmen Sie das noch *ein wenig* weiter und Sie haben eine funktionierende Stoppuhr, die nur mit CSS und HTML erstellt wurde. Klicken Sie auf die Schaltflächen! Das Coole daran ist, dass dies tatsächlich als Timer funktioniert. Er wird keine Abweichungen aufweisen. In gewisser Weise kann er genauer sein als die JavaScript-Lösungen, zu denen wir oft greifen, wie z. B. setInterval. Schauen Sie sich dieses großartige Video von Google Chrome Developer über JavaScript-Zähler an.
Wofür könnten Sie animierte Zahlen noch verwenden? Vielleicht einen Countdown?
Animierte Verläufe
Sie kennen sie, linear, radial und conic. Waren Sie jemals in einer Situation, in der Sie Farbverläufe überblenden oder animieren wollten? Nun, @property kann das!
Betrachten Sie einen Verlauf, bei dem wir Wellen am Strand erzeugen. Sobald wir einige Bilder übereinander gelegt haben, könnten wir so etwas machen.
body {
background-image:
linear-gradient(transparent 0 calc(35% + (var(--wave) * 0.5)), var(--wave-four) calc(75% + var(--wave)) 100%),
linear-gradient(transparent 0 calc(35% + (var(--wave) * 0.5)), var(--wave-three) calc(50% + var(--wave)) calc(75% + var(--wave))),
linear-gradient(transparent 0 calc(20% + (var(--wave) * 0.5)), var(--wave-two) calc(35% + var(--wave)) calc(50% + var(--wave))),
linear-gradient(transparent 0 calc(15% + (var(--wave) * 0.5)), var(--wave-one) calc(25% + var(--wave)) calc(35% + var(--wave))), var(--sand);
}
Da ist ziemlich viel los. Aber um es aufzuschlüsseln: Wir erstellen jeden Farbverlauf mit calc(). Und in dieser Berechnung fügen wir den Wert von --wave hinzu. Der clevere Trick hier ist, dass, wenn wir diesen --wave-Wert animieren, sich alle Wellenschichten bewegen.
Das ist alles, was wir brauchten, um das zu erreichen
body {
animation: waves 5s infinite ease-in-out;
}
@keyframes waves {
50% {
--wave: 25%;
}
}
Ohne die Verwendung von @property würden unsere Wellen zwischen Ebbe und Flut wechseln. Aber mit ihm erhalten wir einen schönen, entspannten Effekt wie diesen.
Es ist aufregend, an andere nette Möglichkeiten zu denken, die wir beim Manipulieren von Bildern haben. Wie Rotation. Oder wie wäre es, den Winkel eines conic-gradient zu animieren... aber innerhalb eines border-image. Bramus Van Damme macht einen brillanten Job, der dieses Konzept abdeckt.
Lassen Sie es uns aufschlüsseln, indem wir eine Ladeanzeige erstellen. Wir werden gleichzeitig einen Winkel und eine Helligkeit animieren. Wir können mit zwei benutzerdefinierten Eigenschaften beginnen
@property --angle {
initial-value: 0deg;
inherits: false;
syntax: '<number>';
}
@property --hue {
initial-value: 0;
inherits: false;
syntax: '<angle>';
}
Die Animation aktualisiert den Winkel und die Helligkeit mit einer leichten Pause bei jeder Wiederholung.
@keyframes load {
0%, 10% {
--angle: 0deg;
--hue: 0;
}
100% {
--angle: 360deg;
--hue: 100;
}
}
Nun wenden wir es als border-image eines Elements an.
.loader {
--charge: hsl(var(--hue), 80%, 50%);
border-image: conic-gradient(var(--charge) var(--angle), transparent calc(var(--angle) * 0.5deg)) 30;
animation: load 2s infinite ease-in-out;
}
Ziemlich cool.
Leider funktioniert border-image nicht gut mit border-radius. Aber wir könnten ein Pseudoelement dahinter verwenden. Kombinieren Sie es mit den Nummernanimations-Tricks von zuvor und wir haben eine vollständige Lade-/Fortschrittsanimation. (Ja, sie ändert sich, wenn sie 100% erreicht.)
Transforms sind auch cool
Ein Problem bei der Animation von Transformationen ist der Übergang zwischen bestimmten Teilen. Er bricht oft ab oder sieht nicht so aus, wie er sollte. Betrachten Sie das klassische Beispiel eines geworfenen Balls. Wir möchten, dass er von Punkt A nach Punkt B geht und dabei die Auswirkung der Schwerkraft nachahmt.
Ein erster Versuch könnte so aussehen
@keyframes throw {
0% {
transform: translate(-500%, 0);
}
50% {
transform: translate(0, -250%);
}
100% {
transform: translate(500%, 0);
}
}
Aber wir werden bald sehen, dass es nicht annähernd so aussieht, wie wir es wollen.
Zuvor hätten wir vielleicht auf Wrapper-Elemente zurückgegriffen und sie isoliert animiert. Aber mit @property können wir die einzelnen Werte der Transformation animieren. Und das alles auf einer einzigen Zeitleiste. Drehen wir die Funktionsweise um, indem wir benutzerdefinierte Eigenschaften definieren und dann eine Transformation für den Ball festlegen.
@property --x {
inherits: false;
initial-value: 0%;
syntax: '<percentage>';
}
@property --y {
inherits: false;
initial-value: 0%;
syntax: '<percentage>';
}
@property --rotate {
inherits: false;
initial-value: 0deg;
syntax: '<angle>';
}
.ball {
animation: throw 1s infinite alternate ease-in-out;
transform: translateX(var(--x)) translateY(var(--y)) rotate(var(--rotate));
}
Nun können wir für unsere Animation die gewünschte Transformation über die Keyframes zusammensetzen
@keyframes throw {
0% {
--x: -500%;
--rotate: 0deg;
}
50% {
--y: -250%;
}
100% {
--x: 500%;
--rotate: 360deg;
}
}
Das Ergebnis? Die gekrümmte Bahn, die wir uns erhofft hatten. Und wir können das anders aussehen lassen, je nachdem, welche Timing-Funktionen wir verwenden. Wir könnten die Animation in drei Teile aufteilen und verschiedene Timing-Funktionen verwenden. Das würde uns unterschiedliche Ergebnisse für die Bewegung des Balls liefern.
Betrachten Sie ein weiteres Beispiel, bei dem wir ein Auto haben, das wir um ein Quadrat mit abgerundeten Ecken fahren lassen wollen.
Wir können einen ähnlichen Ansatz wie beim Ball verwenden
@property --x {
inherits: false;
initial-value: -22.5;
syntax: '<number>';
}
@property --y {
inherits: false;
initial-value: 0;
syntax: '<number>';
}
@property --r {
inherits: false;
initial-value: 0deg;
syntax: '<angle>';
}
Die transform des Autos wird mit vmin berechnet, um die Responsivität zu gewährleisten
.car {
transform: translate(calc(var(--x) * 1vmin), calc(var(--y) * 1vmin)) rotate(var(--r));
}
Jetzt können wir eine extrem genaue Reise für das Auto Frame für Frame schreiben. Wir könnten mit dem Wert von --x beginnen.
@keyframes journey {
0%, 100% {
--x: -22.5;
}
25% {
--x: 0;
}
50% {
--x: 22.5;
}
75% {
--x: 0;
}
}
Das Auto macht die richtige Reise auf der x-Achse.
Dann bauen wir darauf auf, indem wir die Bewegung für die y-Achse hinzufügen
@keyframes journey {
0%, 100% {
--x: -22.5;
--y: 0;
}
25% {
--x: 0;
--y: -22.5;
}
50% {
--x: 22.5;
--y: 0;
}
75% {
--x: 0;
--y: 22.5;
}
}
Nun, das ist nicht *ganz* richtig.
Fügen wir ein paar zusätzliche Schritte in unsere @keyframes ein, um die Sache zu glätten
@keyframes journey {
0%, 100% {
--x: -22.5;
--y: 0;
}
12.5% {
--x: -22.5;
--y: -22.5;
}
25% {
--x: 0;
--y: -22.5;
}
37.5% {
--y: -22.5;
--x: 22.5;
}
50% {
--x: 22.5;
--y: 0;
}
62.5% {
--x: 22.5;
--y: 22.5;
}
75% {
--x: 0;
--y: 22.5;
}
87.5% {
--x: -22.5;
--y: 22.5;
}
}
Ah, das ist schon viel besser
Übrig bleibt die Drehung des Autos. Wir gehen von einem 5%igen Fenster um die Ecken aus. Das ist nicht präzise, zeigt aber definitiv das Potenzial dessen, was möglich ist
@keyframes journey {
0% {
--x: -22.5;
--y: 0;
--r: 0deg;
}
10% {
--r: 0deg;
}
12.5% {
--x: -22.5;
--y: -22.5;
}
15% {
--r: 90deg;
}
25% {
--x: 0;
--y: -22.5;
}
35% {
--r: 90deg;
}
37.5% {
--y: -22.5;
--x: 22.5;
}
40% {
--r: 180deg;
}
50% {
--x: 22.5;
--y: 0;
}
60% {
--r: 180deg;
}
62.5% {
--x: 22.5;
--y: 22.5;
}
65% {
--r: 270deg;
}
75% {
--x: 0;
--y: 22.5;
}
85% {
--r: 270deg;
}
87.5% {
--x: -22.5;
--y: 22.5;
}
90% {
--r: 360deg;
}
100% {
--x: -22.5;
--y: 0;
--r: 360deg;
}
}
Und da haben wir es, ein Auto, das um ein gekrümmtes Quadrat fährt! Keine Wrapper, keine komplexe Mathematik. Und wir haben das alles mit benutzerdefinierten Eigenschaften zusammengesetzt.
Eine ganze Szene mit Variablen steuern
Wir haben bisher einige ziemlich nette @property-Möglichkeiten gesehen, aber die Zusammenführung all dessen, was wir hier betrachtet haben, kann die Dinge auf ein neues Niveau heben. Wir können zum Beispiel ganze Szenen mit nur wenigen benutzerdefinierten Eigenschaften steuern.
Betrachten Sie das folgende Konzept für eine 404-Seite. Zwei registrierte Eigenschaften steuern die verschiedenen beweglichen Teile. Wir haben einen bewegten Verlauf, der mit -webkit-background-clip beschnitten wird. Der Schatten bewegt sich, indem er die Werte der Eigenschaften liest. Und wir schwingen ein weiteres Element für den Lichteffekt.
Das ist alles!
Es ist aufregend, über die Arten von Dingen nachzudenken, die wir mit der Fähigkeit, Typen mit @property zu definieren, tun können. Indem wir dem Browser zusätzlichen Kontext über eine benutzerdefinierte Eigenschaft geben, können wir verrückt werden, wie wir es zuvor mit einfachen Zeichenketten nicht konnten.
Welche Ideen haben Sie für die anderen Typen? Zeit und Auflösung würden für interessante Übergänge sorgen, obwohl ich zugeben muss, dass ich sie nicht so hinbekommen habe, wie ich es mir erhofft hatte. url könnte auch nett sein, wie vielleicht der Übergang zwischen einer Reihe von Quellen, wie es ein Bildkarussell typischerweise tut. Nur Brainstorming hier!
Ich hoffe, dieser kurze Einblick in @property inspiriert Sie, es auszuprobieren und Ihre eigenen großartigen Demos zu erstellen! Ich freue mich darauf zu sehen, was Sie machen. Teilen Sie es mir sogar hier in den Kommentaren mit!
Endlich... Marching Ants können wieder Realität werden!!!
Fantastisch! Dieses 404-Konzept sah auch großartig aus!
Das ist so cool! Ich liebe das!!!!
Obwohl der Transform-Abschnitt ein gutes Beispiel für @property ist, ist der beste Weg, ein solches Feature zu implementieren, die Verwendung von Motion Path (
offset-path).Das Problem dabei ist, dass
offset-pathnicht responsiv ist. Etwas, das ich bereits in einem anderen CSS Tricks Artikel behandelt habe ʕ •ᴥ•ʔ