Imaginați-vă asta: vă alăturați unui nou proiect, vă scufundați în baza de cod și, în primele ore, descoperiți ceva frustrant de familiar. Împrăștiate în foile de stil, găsiți mai multe definiții @keyframes pentru aceleași animații de bază. Trei efecte de fade-in diferite, două sau trei variații de diapozitive, o mână de animații de zoom și cel puțin două animații de rotire diferite pentru că, de ce nu? @keyframes pulse { de la { scara: 1; } la { scara: 1,1; } }
@keyframes bigger-pulse { 0%, 20%, 100% { scara: 1; } 10%, 40% { scara: 1,2; } }
Dacă acest scenariu sună familiar, nu ești singur. Din experiența mea în diverse proiecte, unul dintre cele mai consistente câștiguri rapide pe care le pot oferi este consolidarea și standardizarea cadrelor cheie. A devenit un model atât de fiabil încât acum aștept cu nerăbdare această curățare ca una dintre primele mele sarcini pe orice bază de cod nouă. Logica din spatele haosului Această redundanță are sens perfect atunci când te gândești la asta. Cu toții folosim aceleași animații fundamentale în munca noastră de zi cu zi: estompări, diapozitive, măriri, învârtiri și alte efecte comune. Aceste animații sunt destul de simple și este ușor să creați o definiție rapidă de @keyframes pentru a finaliza treaba. Fără un sistem de animație centralizat, dezvoltatorii scriu în mod natural aceste cadre cheie de la zero, fără să știe că animații similare există deja în altă parte în baza de cod. Acest lucru este obișnuit mai ales atunci când lucrați în arhitecturi bazate pe componente (ceea ce majoritatea dintre noi facem în prezent), deoarece echipele lucrează adesea în paralel în diferite părți ale aplicației. Rezultatul? Haosul animației. Mica Problemă Cele mai evidente probleme cu duplicarea cadrelor cheie sunt timpul de dezvoltare pierdut și umflarea inutilă a codului. Definițiile de cadre cheie multiple înseamnă mai multe locuri de actualizat atunci când cerințele se modifică. Trebuie să ajustați sincronizarea animației de estompare? Va trebui să urmăriți fiecare instanță din baza de cod. Doriți să standardizați funcțiile de relaxare? Succes în găsirea tuturor variantelor. Această multiplicare a punctelor de întreținere face chiar și actualizările simple ale animației o sarcină consumatoare de timp. Problema mai mare Această duplicare a cadrelor cheie creează o problemă mult mai insidioasă care pândește sub suprafață: capcana globală. Chiar și atunci când lucrați cu arhitecturi bazate pe componente, cadrele cheie CSS sunt întotdeauna definite în domeniul global. Aceasta înseamnă că toate cadrele cheie se aplică tuturor componentelor. Întotdeauna. Da, animația dvs. nu folosește neapărat cadrele cheie pe care le-ați definit în componentă. Utilizează ultimele cadre cheie care se potrivesc exact cu același nume care au fost încărcate în domeniul global. Atâta timp cât toate cadrele cheie sunt identice, aceasta ar putea părea o problemă minoră. Dar în momentul în care doriți să personalizați o animație pentru un anumit caz de utilizare, aveți probleme sau, mai rău, veți fi cel care le provoacă. Fie animația dvs. nu va funcționa, deoarece o altă componentă s-a încărcat după a dvs., suprascriind cadrele cheie, fie componenta dvs. se încarcă ultima și modifică accidental comportamentul animației pentru fiecare altă componentă folosind numele acelui cadru cheie și este posibil să nu vă dați seama. Iată un exemplu simplu care demonstrează problema: .component-one { /* stiluri componente */ animație: puls 1s ease-in-out infinit alternativ; }
/* această definiție @keyframes nu va funcționa */ @keyframes pulse { de la { scara: 1; } la { scara: 1,1; } }
/* mai târziu în cod... */
.component-două { /* stiluri componente */ animație: puls 1s ease-in-out infinit; }
/* aceste cadre cheie se vor aplica ambelor componente */ @keyframes pulse { 0%, 20%, 100% { scara: 1; } 10%, 40% { scara: 1,2; } }
Ambele componente folosesc același nume de animație, dar a doua definiție @keyframes o suprascrie pe prima. Acum, atât componenta-unu cât și componenta-două vor folosi cele doua cadre cheie, indiferent de componentă care a definit cadrele cheie. Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 1 [furcat] de Amit Sheen. Partea cea mai rea? Acest lucru funcționează adesea perfect în dezvoltarea locală, dar se întrerupe în mod misterios în producție atunci când procesele de construire schimbă ordinea de încărcare a foilor de stil. Ajungi cu animații care se comportă diferit, în funcție de ce componente sunt încărcate și în ce secvență. Soluția: cadre cheie unificate Răspunsul la acest haos este surprinzător de simplu: cadre cheie dinamice predefinite stocate într-o foaie de stil partajată. În loc să lăsăm fiecare componentă să-și definească propriile animații, creăm cadre cheie centralizate care sunt bine documentate, ușor deutilizabil, întreținut și adaptat nevoilor specifice ale proiectului dumneavoastră. Gândiți-vă la asta ca la simboluri de cadre cheie. Așa cum folosim jetoane pentru culori și spațiere, iar mulți dintre noi deja folosesc jetoane pentru proprietățile de animație, cum ar fi durata și funcțiile de ușurare, de ce să nu folosim jetoane și pentru cadrele cheie? Această abordare se poate integra în mod natural cu orice flux de lucru curent cu simboluri de proiectare pe care îl utilizați, rezolvând în același timp atât problema mică (duplicarea codului), cât și problema mai mare (conflicte la nivel global). Ideea este simplă: creați o singură sursă de adevăr pentru toate animațiile noastre comune. Această foaie de stil partajată conține cadre cheie realizate cu atenție care acoperă modelele de animație pe care proiectul nostru le folosește de fapt. Nu mai ghicim dacă o animație de estompare există deja undeva în baza noastră de cod. Nu mai suprascrieți accidental animațiile din alte componente. Dar iată cheia: acestea nu sunt doar animații statice de tip copy-paste. Sunt proiectate pentru a fi dinamice și personalizabile prin proprietăți personalizate CSS, permițându-ne să menținem coerența, având totuși flexibilitatea de a adapta animații la cazuri de utilizare specifice, de exemplu, dacă aveți nevoie de o animație „puls” puțin mai mare într-un singur loc. Construirea primului simbol de cadre cheie Unul dintre primele fructe cu care ar trebui să le abordăm este animația „fade-in”. Într-unul dintre proiectele mele recente, am găsit peste o duzină de definiții fade-in separate și, da, toate au animat pur și simplu opacitatea de la 0 la 1. Deci, să creăm o nouă foaie de stil, să o numim kf-tokens.css, să o importăm în proiectul nostru și să plasăm cadrele noastre cheie cu comentariile adecvate în interiorul acesteia. /* keyframes-tokens.css */
/* * Fade In - se estompează animația de intrare * Utilizare: animație: kf-fade-in 0.3s ease-out; */ @keyframes kf-fade-in { de la { opacitate: 0; } la { opacitate: 1; } }
Această singură declarație @keyframes înlocuiește toate acele animații cu fade-in împrăștiate în baza noastră de cod. Curat, simplu și aplicabil la nivel global. Și acum că avem acest token definit, îl putem folosi din orice componentă de-a lungul proiectului nostru: .modal { animație: kf-fade-in 0.3s ease-out; }
.tooltip { animație: kf-fade-in 0.2s ease-in-out; }
.notificare { animație: kf-fade-in 0.5s ease-out; }
Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 2 [forked] de Amit Sheen. Notă: folosim un prefix kf- în toate numele noastre @keyframes. Acest prefix servește ca spațiu de nume care previne conflictele de denumire cu animațiile existente în proiect și clarifică imediat faptul că aceste cadre cheie provin din fișierul nostru de simboluri de cadre cheie. Realizarea unui slide dinamic Cadrele cheie kf-fade-in funcționează grozav, deoarece sunt simple și există puțin spațiu pentru a încurca lucrurile. În alte animații, totuși, trebuie să fim mult mai dinamici și aici putem profita de puterea enormă a proprietăților personalizate CSS. Acesta este locul în care simbolurile cadrelor cheie strălucesc cu adevărat în comparație cu animațiile statice împrăștiate. Să luăm un scenariu comun: animații „alunecare”. Dar alunecă de unde? 100px din dreapta? 50% din stânga? Ar trebui să intre din partea de sus a ecranului? Sau poate plutesc de jos? Atât de multe posibilități, dar în loc să creăm cadre cheie separate pentru fiecare direcție și fiecare variație, putem construi un simbol flexibil care se adaptează tuturor scenariilor: /* * Slide In - animație direcțională de diapozitive * Utilizați --kf-slide-from pentru a controla direcția * Implicit: alunecă de la stânga (-100%) * Utilizare: * animație: kf-slide-in 0.3s ease-out; * --kf-slide-from: -100px 0; // glisează de la stânga * --kf-slide-from: 100px 0; // alunecare de la dreapta * --kf-slide-de la: 0 -50px; // aluneca de sus */
@keyframes kf-slide-in { de la { traduce: var(--kf-slide-from, -100% 0); } la { traduce: 0 0; } }
Acum putem folosi acest singur simbol @keyframes pentru orice direcție de diapozitiv pur și simplu schimbând proprietatea personalizată --kf-slide-from: .sidebar { animație: kf-slide-in 0.3s ease-out; /* Folosește valoarea implicită: diapozitive de la stânga */ }
.notificare { animație: kf-slide-in 0.4s ease-out; --kf-slide-de la: 0 -50px; /* alunecare de sus */ }
.modal { animatie: kf-fade-in 0,5s, kf-slide-in 0,5s cubic-bezier(0,34, 1,56, 0,64, 1); --kf-slide-from: 50px 50px; /* slide din dreapta jos */ }
Această abordare ne oferă o flexibilitate incredibilă, păstrând în același timp consistența. O declarație de cadru cheie, posibilități infinite. Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 3 [forked] de Amit Sheen. Și dacă vrem să facem animațiile noastre și mai flexibile, permițând și efecte de „slide-out”, putempur și simplu adăugați o proprietate personalizată --kf-slide-to, similar cu ceea ce vom vedea în secțiunea următoare. Cadre cheie cu zoom bidirecțional O altă animație obișnuită care este duplicată în proiecte este efectele de „zoom”. Fie că este vorba de o mărire subtilă pentru mesajele de tip toast, de o mărire dramatică pentru modal sau de un efect de reducere ușoară pentru titluri, animațiile de zoom sunt peste tot. În loc să creăm cadre cheie separate pentru fiecare valoare de scară, să construim un set flexibil de cadre cheie kf-zoom:
/* * Zoom - animație la scară * Utilizați --kf-zoom-from și --kf-zoom-to pentru a controla valorile scalei * Implicit: mărește de la 80% la 100% (0,8 la 1) * Utilizare: * animație: kf-zoom 0.2s ease-out; * --kf-zoom-de la: 0,5; --kf-zoom-to: 1; // zoom de la 50% la 100% * --kf-zoom-de la: 1; --kf-zoom-to: 0; // zoom de la 100% la 0% * --kf-zoom-de la: 1; --kf-zoom-to: 1.1; // zoom de la 100% la 110% */
@keyframes kf-zoom { de la { scară: var(--kf-zoom-from, 0,8); } la { scară: var(--kf-zoom-to, 1); } }
Cu o singură definiție, putem obține orice variație de zoom de care avem nevoie: .toast { animatie: alunecare kf 0,2 s, kf-zoom 0.4s ease-out; --kf-alunecare-de la: 0 100%; /* alunecare de sus */ /* Utilizează zoom-ul implicit: scala de la 80% la 100% */ }
.modal { animație: kf-zoom 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); --kf-zoom-de la: 0; /* zoom dramatic de la 0% la 100% */ }
.titlu { animatie: kf-fade-in 2s, kf-zoom 2s ease-in; --kf-zoom-de la: 1,2; --kf-zoom-to: 0,8; /* scade usor */ }
Valoarea implicită de 0,8 (80%) funcționează perfect pentru majoritatea elementelor UI, cum ar fi mesajele și cardurile toast, fiind în același timp ușor de personalizat pentru cazuri speciale. Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 4 [forked] de Amit Sheen. S-ar putea să fi observat ceva interesant în exemplele recente: am combinat animații. Unul dintre avantajele cheie ale lucrului cu jetoanele @keyframes este că sunt proiectate să se integreze perfect între ele. Această compoziție fină este intenționată, nu întâmplătoare. Vom discuta mai detaliat despre compoziția animației mai târziu, inclusiv unde pot deveni problematice, dar majoritatea combinațiilor sunt simple și ușor de implementat. Notă: În timp ce scriam acest articol, și poate din cauza scrisului lui, m-am trezit regândind întreaga idee a animațiilor de intrare. Cu toate progresele recente în CSS, mai avem nevoie de ele? Din fericire, Adam Argyle a explorat aceleași întrebări și le-a exprimat cu brio pe blogul său. Acest lucru nu contrazice ceea ce este scris aici, dar prezintă o abordare care merită luată în considerare, mai ales dacă proiectele tale se bazează în mare măsură pe animațiile de intrare. Animații continue În timp ce animațiile de intrare, cum ar fi „decolorarea”, „alunecarea” și „mărirea” au loc o dată și apoi se opresc, animațiile continue sunt difuzate la infinit pentru a atrage atenția sau pentru a indica o activitate în desfășurare. Cele mai frecvente două animații continue pe care le întâlnesc sunt „spin” (pentru indicatorii de încărcare) și „pulse” (pentru evidențierea elementelor importante). Aceste animații prezintă provocări unice atunci când vine vorba de crearea de simboluri de cadre cheie. Spre deosebire de animațiile de intrare care merg de obicei de la o stare la alta, animațiile continue trebuie să fie extrem de personalizabile în modelele lor de comportament. Spin Doctorul Fiecare proiect pare să folosească mai multe animații de rotire. Unele se rotesc în sensul acelor de ceasornic, altele în sens invers acelor de ceasornic. Unii fac o singură rotație de 360 de grade, alții fac mai multe ture pentru un efect mai rapid. În loc să creăm cadre cheie separate pentru fiecare variație, să construim o rotație flexibilă care se ocupă de toate scenariile:
/* * Spin - animație de rotație * Utilizați --kf-spin-from și --kf-spin-to pentru a controla intervalul de rotație * Utilizați --kf-spin-turns pentru a controla cantitatea de rotație * Implicit: se rotește de la 0 grade la 360 de grade (1 rotație completă) * Utilizare: * animație: kf-spin 1s liniar infinit; * --kf-spin-turns: 2; // 2 rotații complete * --kf-spin-de la: 0deg; --kf-spin-to: 180deg; // jumătate de rotație * --kf-spin-de la: 0deg; --kf-spin-to: -360deg; // în sens invers acelor de ceasornic */
@keyframes kf-spin { de la { rotire: var(--kf-spin-from, 0deg); } la { rotiți: calc(var(--kf-spin-from, 0deg) + var(--kf-spin-to, 360deg) * var(--kf-spin-turns, 1)); } }
Acum putem crea orice variație de rotație care ne place:
.loading-spinner { animație: kf-spin 1s liniar infinit; /* Utilizează implicit: se rotește de la 0° la 360° */ }
.fast-loader { animație: kf-spin 1.2s ease-in-out infinit alternativ; --kf-spin-turnuri: 3; /* 3 rotații complete pentru fiecare direcție pe ciclu*/ }
.steped-reverse { animație: kf-spin 1.5s pași(8) infinit; --kf-spin-to: -360deg; /* în sens invers acelor de ceasornic */ }
.subtle-wiggle { animație: kf-spin 2s ease-in-out infinit alternativ; --kf-spin-de la: -16deg; --kf-spin-to: 32deg; /* mișcare la 36 de grade: între -18 grade și +18 grade */ }
Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 5 [furcat] de Amit Sheen. Frumusețea acestei abordări este că aceleași cadre cheie funcționează pentru încărcarea rotitoarelor, pictogramele rotative, efectele de mișcare și chiar animațiile complexe cu mai multe ture. Paradoxul pulsului Animațiile cu puls sunt mai complicate, deoarece pot „impulsa” diferite proprietăți. Unele impulsează scara, altele impulsează opacitatea și unele proprietăți ale culorii impuls, cum ar fi luminozitatea sau saturația. În loc să creăm cadre cheie separate pentru fiecare proprietate, putem crea cadre cheie care funcționează cu orice proprietate CSS. Iată un exemplu de cadru cheie de impuls cu opțiuni de scară și opacitate:
/* * Puls - animație pulsatorie * Utilizați --kf-pulse-scale-from și --kf-pulse-scale-to pentru a controla intervalul de scară * Utilizați --kf-pulse-opacity-from și --kf-pulse-opacity-to pentru a controla intervalul de opacitate * Implicit: fără impuls (toate valorile 1) * Utilizare: * animație: kf-pulse 2s ease-in-out infinit alternativ; * --kf-pulse-scale-de la: 0,95; --kf-puls-scale-to: 1,05; // scale puls * --kf-opacitate-puls-de la: 0,7; --kf-opacitate-puls-la: 1; // puls de opacitate */
@keyframes kf-pulse { de la { scară: var(--kf-puls-scale-from, 1); opacitate: var(--kf-opacitate-impuls-de la, 1); } la { scară: var(--kf-pulse-scale-to, 1); opacitate: var(--kf-opacitate-impuls-to, 1); } }
Acest lucru creează un impuls flexibil care poate anima mai multe proprietăți: .îndemn la acțiune { animație: kf-pulse 0.6s infinit alternativ; --kf-opacitate-puls-de la: 0,5; /* impuls de opacitate */ }
.notification-dot { animație: kf-pulse 0.6s ease-in-out infinit alternativ; --kf-scale-impuls-de la: 0,9; --kf-puls-scale-to: 1,1; /* puls scala */ }
.text-highlight { animație: kf-pulse 1.5s ease-out infinit; --kf-scale-impuls-de la: 0,8; --kf-opacitate-puls-de la: 0,2; /* impuls de scară și opacitate */ }
Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 6 [furcat] de Amit Sheen. Acest singur cadru cheie kf-pulse poate gestiona orice, de la captarea subtilă a atenției până la evidențieri dramatice, totul fiind ușor de personalizat. Ușurare avansată Unul dintre lucrurile grozave despre utilizarea simbolurilor de cadre cheie este cât de ușor este să ne extinzi biblioteca de animații și să ofere efecte pe care majoritatea dezvoltatorilor nu s-ar deranja să le scrie de la zero, cum ar fi elastic sau bounce. Iată un exemplu de simbol simplu de cadre cheie „bounce” care utilizează o proprietate personalizată --kf-bounce-from pentru a controla înălțimea saltului. /* * Bounce - animație de intrare care sări * Folosiți --kf-bounce-from pentru a controla înălțimea săriturii * Implicit: sare de la 100vh (în afara ecranului) * Utilizare: * animație: kf-bounce 3s ease-in; * --kf-bounce-de la: 200px; // sari de la 200px inaltime */
@keyframes kf-bounce { 0% { traduce: 0 calc(var(--kf-bounce-from, 100vh) * -1); }
34% { traduce: 0 calc(var(--kf-bounce-from, 100vh) * -0,4); }
55% { traduce: 0 calc(var(--kf-bounce-from, 100vh) * -0,2); }
72% { traduce: 0 calc(var(--kf-bounce-from, 100vh) * -0,1); }
85% { traduce: 0 calc(var(--kf-bounce-from, 100vh) * -0,05); }
94% { traduce: 0 calc(var(--kf-bounce-from, 100vh) * -0,025); }
99% { traduce: 0 calc(var(--kf-bounce-from, 100vh) * -0,0125); }
22%, 45%, 64%, 79%, 90%, 97%, 100% { traduce: 0 0; animație-funcție de sincronizare: ease-out; } }
Animațiile precum „elastice” sunt puțin mai complicate din cauza calculelor din cadrul cadrelor cheie. Trebuie să definim --kf-elastic-from-X și --kf-elastic-from-Y separat (ambele sunt opționale), iar împreună ne permit să creăm o intrare elastică din orice punct de pe ecran.
/* * Elastic In - animație de intrare elastică * Utilizați --kf-elastic-from-X și --kf-elastic-from-Y pentru a controla poziția de pornire * Implicit: intră din centru sus (0, -100vh) * Utilizare: * animație: kf-elastic-in 2s ease-in-out ambele; * --kf-elastic-din-X: -50px; * --kf-elastic-din-Y: -200px; // introduceți de la (-50px, -200px) */
@keyframes kf-elastic-in { 0% { traduce: calc(var(--kf-elastic-din-X, -50vw) * 1) calc(var(--kf-elastic-from-Y, 0px) * 1); }
16% { traduce: calc(var(--kf-elastic-din-X, -50vw) * -0,3227) calc(var(--kf-elastic-din-Y, 0px) * -0,3227); }
28% { traduceți: calc(var(--kf-elastic-from-X, -50vw) * 0,1312)calc(var(--kf-elastic-de-Y, 0px) * 0,1312); }
44% { traduce: calc(var(--kf-elastic-din-X, -50vw) * -0,0463) calc(var(--kf-elastic-de-Y, 0px) * -0,0463); }
59% { traduce: calc(var(--kf-elastic-din-X, -50vw) * 0,0164) calc(var(--kf-elastic-from-Y, 0px) * 0,0164); }
73% { traduce: calc(var(--kf-elastic-din-X, -50vw) * -0,0058) calc(var(--kf-elastic-de-Y, 0px) * -0,0058); }
88% { traduce: calc(var(--kf-elastic-din-X, -50vw) * 0,0020) calc(var(--kf-elastic-from-Y, 0px) * 0,0020); }
100% { traduce: 0 0; } }
Această abordare face ușoară reutilizarea și personalizarea cadrelor cheie avansate în proiectul nostru, doar prin schimbarea unei singure proprietăți personalizate.
.bounce-and-zoom { animatie: kf-bounce 3s ease-in, kf-zoom 3s liniar; --kf-zoom-de la: 0; }
.bounce-and-glise { animatie-compozitie: adauga; /* Ambele animații folosesc translate */ animatie: kf-bounce 3s ease-in, kf-slide-in 3s ease-out; --kf-slide-de la: -200px; }
.elastic-in { animație: kf-elastic-in 2s ease-in-out ambele; }
Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 7 [furcat] de Amit Sheen. Până în acest moment, am văzut cum putem consolida cadrele cheie într-un mod inteligent și eficient. Desigur, este posibil să doriți să modificați lucrurile pentru a se potrivi mai bine nevoilor proiectului dvs., dar am acoperit exemple de mai multe animații comune și cazuri de utilizare de zi cu zi. Și cu aceste simboluri de cadre cheie la locul lor, acum avem blocuri puternice pentru crearea de animații coerente și care pot fi întreținute în întregul proiect. Gata cu cadre cheie duplicate, nu mai există conflicte la nivel global. Doar o modalitate curată și convenabilă de a face față tuturor nevoilor noastre de animație. Dar adevărata întrebare este: cum compunem aceste blocuri împreună? Punând totul laolaltă Am văzut că combinarea simbolurilor de cadre cheie de bază este simplă. Nu avem nevoie de nimic special decât să definim prima animație, să o definim pe a doua, să setăm variabilele după cum este necesar și atât. /* Fade in + slide in */ .toast { animatie: kf-fade-in 0,4s, kf-slide-in 0,4s cubic-bezier(0,34, 1,56, 0,64, 1); --kf-slide-de la: 0 40px; }
/* Mărire + estompare */ .modal { animatie: kf-fade-in 0,3s, kf-zoom 0,3s cubic-bezier(0,34, 1,56, 0,64, 1); --kf-zoom-de la: 0,7; --kf-zoom-to: 1; }
/* Glisați + puls */ .notificare { animatie: alunecare kf 0,5 s, kf-pulse 1.2s ease-in-out infinit alternativ; --kf-slide-de la: -100px 0; --kf-scale-puls-de la: 0,95; --kf-puls-scale-to: 1,05; }
Aceste combinații funcționează frumos, deoarece fiecare animație vizează o proprietate diferită: opacitate, transformare (traducere/scalare), etc. Dar uneori apar conflicte și trebuie să știm de ce și cum să le facem față. Când două animații încearcă să anime aceeași proprietate - de exemplu, ambele scară de animație sau ambele opacitate de animație - rezultatul nu va fi cel așteptat. În mod implicit, numai una dintre animații este aplicată efectiv acelei proprietăți, care este ultima din lista de animații. Aceasta este o limitare a modului în care CSS gestionează mai multe animații pe aceeași proprietate. De exemplu, acest lucru nu va funcționa așa cum a fost intenționat, deoarece se va aplica doar animația kf-pulse. .bad-combo { animatie: kf-zoom 0.5s înainte, kf-pulse 1.2s infinit alternat; --kf-zoom-de la: 0,5; --kf-zoom-to: 1,2; --kf-scale-impuls-de la: 0,8; --kf-puls-scale-to: 1,1; }
Adăugare de animație Cel mai simplu și mai direct mod de a gestiona mai multe animații care afectează aceeași proprietate este utilizarea proprietății animație-compoziție. În ultimul exemplu de mai sus, animația kf-pulse înlocuiește animația kf-zoom, așa că nu vom vedea zoom-ul inițial și nu vom obține scara așteptată la 1,2. Setând animația-compoziție de adăugat, îi spunem browserului să combine ambele animații. Acest lucru ne oferă rezultatul pe care ni-l dorim. .component-două { animatie-compozitie: adauga; }
Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 8 [forked] de Amit Sheen. Această abordare funcționează bine pentru majoritatea cazurilor în care dorim să combinăm efectele asupra aceleiași proprietăți. De asemenea, este util atunci când trebuie să combinăm animații cu valori de proprietăți statice. De exemplu, dacă avem un element care folosește proprietatea translate pentru a-l poziționa exact unde vrem și apoi vrem să-l animam cu cadrele cheie kf-slide-in, obținem un salt vizibil urât fără animație-compoziție. Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 9 [forked] de Amit Sheen. Cu animația-compoziție setată pentru a adăuga, animația este combinată fără probleme cu cea existentătransforma, astfel încât elementul să rămână pe loc și să se anime așa cum era de așteptat. Stagger de animație Un alt mod de a gestiona mai multe animații este să le „eșaloneze” - adică să pornești a doua animație puțin după ce prima se termină. Nu este o soluție care funcționează pentru fiecare caz, dar este utilă atunci când avem o animație de intrare urmată de o animație continuă. /* fade in + impuls de opacitate */ .notificare { animatie: kf-fade-in 2s ease-out, kf-pulse 0,5s 2s ease-in-out infinit alternativ; --kf-opacitate-puls-la: 0,5; }
Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 10 [forked] de Amit Sheen. Ordinea contează O mare parte din animațiile cu care lucrăm folosesc proprietatea transform. În cele mai multe cazuri, acest lucru este pur și simplu mai convenabil. De asemenea, are un avantaj de performanță, deoarece animațiile de transformare pot fi accelerate de GPU. Dar dacă folosim transformări, trebuie să acceptăm că ordinea în care efectuăm transformările contează. multe. Până acum, în cadrele noastre cheie, am folosit transformări individuale. Conform specificațiilor, acestea sunt întotdeauna aplicate într-o ordine fixă: mai întâi, elementul se translată, apoi se rotește, apoi se scalează. Acest lucru are sens și este ceea ce majoritatea dintre noi se așteaptă. Totuși, dacă folosim proprietatea transform, ordinea în care sunt scrise funcțiile este ordinea în care sunt aplicate. În acest caz, dacă mișcăm ceva cu 100 de pixeli pe axa X și apoi îl rotim cu 45 de grade, nu este același lucru cu rotirea lui cu 45 de grade și apoi mutarea cu 100 de pixeli. /* Pătrat roz: mai întâi traduceți, apoi rotiți */ .exemplu-unu { transformare: translateX(100px) rotire(45deg); }
/* Pătrat verde: mai întâi rotiți, apoi traduceți */ .exemplu-doi { transforma: rotește(45deg) translateX(100px); }
Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 11 [furcat] de Amit Sheen. Dar, conform ordinii de transformare, toate transformările individuale - tot ce am folosit pentru simbolurile cadrelor cheie - au loc înaintea funcțiilor de transformare. Asta înseamnă că orice setați în proprietatea de transformare se va întâmpla după animații. Dar dacă setați, de exemplu, traducerea împreună cu cadrele cheie kf-spin, traducerea se va întâmpla înainte de animație. Inca confuz?! Acest lucru duce la situații în care valorile statice pot provoca rezultate diferite pentru aceeași animație, ca în următorul caz:
/* Animație comună pentru ambii rotori */ .spinner { animație: kf-spin 1s liniar infinit; }
/* Roz spinner: traduceți înainte de rotire (transformare individuală) */ .spinner-roz { traduce: 100% 50%; }
/* Rotitor verde: rotiți apoi traduceți (ordinea funcției) */ .spinner-green { transforma: traduce(100%, 50%); }
Vedeți Jetoanele pentru cadre cheie pentru stilou - Demo 12 [furcat] de Amit Sheen. Puteți vedea că primul spinner (roz) primește o translație care se întâmplă înainte de rotirea kf-spin, așa că mai întâi se mută la locul său și apoi se învârte. Cel de-al doilea spinner (verde) primește o funcție translate() care are loc după transformarea individuală, astfel încât elementul se rotește mai întâi, apoi se mișcă în raport cu unghiul său curent și obținem acel efect de orbită largă. Nu, acesta nu este un bug. Este doar unul dintre acele lucruri pe care trebuie să le știm despre CSS și pe care trebuie să le ținem cont atunci când lucrăm cu mai multe animații sau transformări multiple. Dacă este necesar, puteți crea și un set suplimentar de cadre cheie kf-spin-alt care rotesc elementele utilizând funcția rotate(). Mișcare redusă Și în timp ce vorbim despre cadre cheie alternative, nu putem ignora opțiunea „fără animație”. Unul dintre cele mai mari avantaje ale utilizării simbolurilor de cadre cheie este că accesibilitatea poate fi inclusă și, de fapt, este destul de ușor de realizat. Prin proiectarea cadrelor cheie ținând cont de accesibilitate, ne putem asigura că utilizatorii care preferă mișcarea redusă beneficiază de o experiență mai fluidă, mai puțin distragătoare, fără muncă suplimentară sau duplicare a codului. Semnificația exactă a „Mișcare redusă” se poate schimba puțin de la o animație la alta și de la proiect la proiect, dar iată câteva puncte importante de reținut: Dezactivarea cadrelor cheie În timp ce unele animații pot fi atenuate sau încetinite, există altele care ar trebui să dispară complet atunci când se solicită o mișcare redusă. Animațiile cu puls sunt un bun exemplu. Pentru a ne asigura că aceste animații nu rulează în modul de mișcare redusă, pur și simplu le putem include în interogarea media corespunzătoare.
@media (preferă-mișcare redusă: fără preferințe) { @keyfrmaes kf-pulse { de la { scară: var(--kf-puls-scale-from, 1); opacitate: var(--kf-opacitate-impuls-de la, 1); } la { scară: var(--kf-pulse-scale-to, 1); opacitate:var(--kf-opacitate-puls-to, 1); } } }
Acest lucru asigură că utilizatorii care au setat mișcarea de preferințe reduse pentru a reduce nu vor vedea animația și vor avea o experiență care se potrivește preferințelor lor. Instant In Există câteva cadre cheie pe care nu le putem elimina pur și simplu, cum ar fi animațiile de intrare. Valoarea trebuie să se schimbe, trebuie să se anime; în caz contrar, elementul nu va avea valorile corecte. Dar în mișcare redusă, această tranziție de la valoarea inițială ar trebui să fie instantanee. Pentru a realiza acest lucru, vom defini un set suplimentar de cadre cheie în care valoarea sare imediat la starea finală. Acestea devin cadrele noastre cheie implicite. Apoi, vom adăuga cadrele cheie obișnuite într-o interogare media pentru preferințe-mișcare redusă setate la fără preferințe, la fel ca în exemplul anterior. /* apare instantaneu pentru o mișcare redusă */ @keyframes kf-zoom { de la, la { scară: var(--kf-zoom-to, 1); } }
@media (preferă-mișcare redusă: fără preferințe) { /* Cadre cheie de zoom originale */ @keyframes kf-zoom { de la { scară: var(--kf-zoom-from, 0,8); } la { scară: var(--kf-zoom-to, 1); } } }
În acest fel, utilizatorii care preferă mișcarea redusă vor vedea elementul apărând instantaneu în starea sa finală, în timp ce toți ceilalți primesc tranziția animată. Abordarea soft Există cazuri în care vrem să păstrăm o mișcare, dar mult mai blândă și mai calmă decât animația originală. De exemplu, putem înlocui o intrare de respingere cu un fade-in ușor.
@keyframes kf-bounce { /* Fade-in moale pentru mișcare redusă */ }
@media (preferă-mișcare redusă: fără preferințe) { @keyframes kf-bounce { /* Cadre cheie de respingere originale */ } }
Acum, utilizatorii cu mișcare redusă activată au încă un sentiment de aspect, dar fără mișcarea intensă a unei sărituri sau a unei animații elastice. Cu elementele de bază la locul lor, următoarea întrebare este cum să le faceți parte din fluxul de lucru real. Scrierea cadrelor cheie flexibile este un lucru, dar a le face fiabile într-un proiect mare necesită câteva strategii pe care a trebuit să le învăț pe cale grea. Strategii de implementare și bune practici Odată ce avem o bibliotecă solidă de simboluri de cadre cheie, adevărata provocare este cum să le aducem în munca de zi cu zi.
Tentația este de a introduce toate cadrele cheie simultan și de a declara problema rezolvată, dar în practică am constatat că cele mai bune rezultate provin din adoptarea treptată. Începeți cu cele mai comune animații, cum ar fi fade sau slide. Acestea sunt câștiguri ușoare care arată valoare imediată, fără a necesita rescrieri mari. Numirea este un alt punct care merită atenție. Un prefix consecvent sau un spațiu de nume face evident care animații sunt simboluri și care sunt unice locale. De asemenea, previne coliziunile accidentale și ajută noii membri ai echipei să recunoască sistemul partajat dintr-o privire. Documentația este la fel de importantă ca și codul în sine. Chiar și un scurt comentariu deasupra fiecărui jeton de cadre cheie poate economisi ore de ghicire mai târziu. Un dezvoltator ar trebui să poată deschide fișierul jetoane, să scaneze efectul de care are nevoie și să copieze modelul de utilizare direct în componenta sa. Flexibilitatea este ceea ce face ca această abordare să merite efortul. Prin expunerea proprietăților personalizate sensibile, oferim echipelor spațiu pentru a adapta animația fără a distruge sistemul. În același timp, încercați să nu vă complicați prea mult. Furnizați mânerele care contează și păstrați-i pe restul cu părere. În cele din urmă, amintiți-vă de accesibilitate. Nu orice animație are nevoie de o alternativă cu mișcare redusă, dar multe au nevoie. Aducerea devreme a acestor ajustări înseamnă că nu trebuie niciodată să le adaptăm mai târziu și arată un nivel de grijă pe care utilizatorii noștri îl vor observa chiar dacă nu îl vor menționa niciodată.
Din experiența mea, tratarea jetoanelor cadre-cheie ca parte a fluxului nostru de lucru pentru jetoane de design este ceea ce le face să rămână. Odată ce sunt la locul lor, nu se mai simt ca efecte speciale și devin parte a limbajului de design, o extensie naturală a modului în care produsul se mișcă și răspunde. Încheierea Animațiile pot fi una dintre cele mai vesele părți ale interfețelor de construcție, dar fără structură, ele pot deveni și una dintre cele mai mari surse de frustrare. Tratând cadrele cheie ca simboluri, luați ceva care este de obicei dezordonat și greu de gestionat și îl transformați într-un sistem clar și previzibil. Valoarea reală nu constă doar în salvarea câtorva linii de cod. Este sigur că atunci când utilizați o fade, slide, zoom sau spin, știți exact cum se va comporta în cadrul proiectului. Este în flexibilitatea care vine de la proprietăți personalizate fără haosul variațiilor nesfârșite. Și este în accesibilitatea construită în fundație, mai degrabă decât adăugată caun gând ulterior. Am văzut aceste idei funcționând în echipe diferite și baze de cod diferite, iar modelul este întotdeauna același. Odată ce jetoanele sunt la locul lor, cadrele cheie nu mai sunt o colecție dispersă de trucuri și devin parte a limbajului de design. Ele fac ca produsul să se simtă mai intenționat, mai consistent și mai viu. Dacă luați un lucru din acest articol, lăsați-l să fie acesta: animațiile merită aceeași îngrijire și structură pe care o acordăm deja culorilor, tipografiei și spațiilor. O investiție mică în jetoane de cadre cheie se plătește de fiecare dată când interfața se mișcă.