Cum să abordați animațiile SVG în CSS
Publicat: 2022-03-11Animațiile sunt o parte omniprezentă a web-ului. Spre deosebire de imaginile GIF intermitente care au afectat site-urile web în zilele anterioare ale internetului, animațiile de astăzi sunt mai subtile și cu gust. Designerii și specialiștii front-end le folosesc pentru a face site-urile web să pară mai rafinate, pentru a îmbunătăți experiența utilizatorului, pentru a atrage atenția asupra elementelor importante și pentru a transmite informații.
Dezvoltatorii web pot beneficia de combinarea puterii SVG și CSS pentru a crea animații fără a utiliza biblioteci externe. Acest tutorial de animație SVG arată cum să creați animații personalizate pentru proiecte din lumea reală.
Animație SVG folosind CSS: Concepte de bază
Înainte de a anima SVG-urile cu CSS, dezvoltatorii trebuie să înțeleagă cum funcționează SVG-urile la nivel intern. Din fericire, este similar cu HTML: definim elementele SVG cu sintaxa XML și le stilăm cu CSS, la fel ca și cum ar fi HTML.
Elementele SVG sunt construite intenționat pentru desenarea grafică. Putem folosi <rect> pentru a desena un dreptunghi, <circle> pentru a desena cercuri etc.—SVG definește, de asemenea, <ellipse> , <line> , <polyline> , <polygon> și <path> .
Notă: lista completă de elemente SVG include chiar și <animate> , care vă permite să creați animații folosind limbajul de integrare multimedia sincronizat (SMIL). Cu toate acestea, viitorul său este incert și echipa Chromium recomandă utilizarea unei abordări CSS sau JavaScript pentru animarea SVG-urilor ori de câte ori este posibil.
Atributele disponibile depind de element, așa că în timp ce <rect> are atribute width și height , elementul <circle> are atributul r , care îi definește raza.
În timp ce majoritatea elementelor HTML pot avea copii, majoritatea elementelor SVG nu pot. O excepție este elementul de grup <g> , pe care îl putem folosi pentru a aplica stiluri și transformări CSS la mai multe elemente simultan.
Elementul <svg> și atributele sale
O altă diferență importantă între HTML și SVG este modul în care poziționăm elementele, în special prin atributul viewBox al unui anumit element <svg> exterior. Valoarea sa constă din patru numere separate prin spații albe sau virgulă: min-x , min-y , width și height . Împreună, acestea specifică cât de mult din desenul nostru SVG dorim să redea browserul. Zona respectivă va fi scalată pentru a se potrivi cu limitele ferestrei de vizualizare , așa cum sunt definite de atributele de width și height ale elementului <svg> .
Când vine vorba de letterboxing, raportul dintre atributele de width și height ale ferestrei de vizualizare poate diferi într-adevăr de raportul dintre părțile de width și height ale atributului viewBox .
În mod implicit, raportul de aspect al pânzei SVG va fi păstrat în detrimentul unei casete de vizualizare mai mari decât cele specificate, viewBox astfel o redare mai mică, cu letterbox în fereastra de vizualizare. Dar puteți specifica un comportament diferit prin atributul preserveAspectRatio .
Acest lucru ne permite să desenăm imagini izolate și să fim încrezători că toate elementele vor fi poziționate corect, indiferent de context sau dimensiunea randării.
Deși puteți codifica manual imaginile SVG, imaginile mai complexe pot necesita un program de grafică vectorială (tutorialul nostru de animație SVG demonstrează ambele tehnici). Editorul meu ales este Affinity Designer, dar orice editor ar trebui să ofere suficientă funcționalitate pentru operațiunile simple descrise aici.
Tranziții și animații CSS
Tranzițiile CSS ne permit să definim rata și durata modificărilor de proprietate. În loc să săriți instantaneu de la valoarea inițială la valoarea finală, valorile trec ușor ca în acest exemplu în care culoarea unui cerc SVG se schimbă atunci când treceți cu mouse-ul peste el:
Vezi exemplul Tranziția stiloului de Filip Defar (@dabrorius) pe CodePen.
Putem defini tranziții cu proprietatea de transition , care acceptă numele proprietății pe care dorim să o facem tranziția, durata tranziției, o funcție de sincronizare a tranziției (cunoscută și sub numele de funcție de relaxare) și durata întârzierii înainte de începerea efectului. :
/* property name | duration | easing function | delay */ transition: margin-right 4s ease-in-out 1s;Putem defini tranziții pentru mai multe proprietăți CSS, fiecare dintre acestea putând avea valori separate de tranziție. Cu toate acestea, există două limitări evidente ale acestei abordări.
Prima limitare este că tranzițiile sunt declanșate automat atunci când valoarea unei proprietăți se modifică. Acest lucru este incomod în unele cazuri de utilizare. De exemplu, nu putem avea o animație care circulă la infinit.
A doua limitare este că tranzițiile au întotdeauna doi pași: starea inițială și starea finală. Putem prelungi durata animației, dar nu putem adăuga cadre cheie diferite.
Acesta este motivul pentru care există un concept mai puternic: animațiile CSS. Cu animațiile CSS, putem avea mai multe cadre cheie și o buclă infinită:
Vezi exemplul Pen Animation de Filip Defar (@dabrorius) pe CodePen.
Pentru a anima proprietățile CSS pe mai multe cadre cheie, mai întâi trebuie să definim cadrele cheie folosind o @keyframes . Timpul cadrelor cheie este definit în unități relative (procente), deoarece în acest moment nu am definit încă durata animației. Fiecare cadru cheie descrie valorile uneia sau mai multor proprietăți CSS la acel moment. Animațiile CSS vor asigura tranziții ușoare între cadrele cheie.
Aplicam animatia cu cadre cheie descrise la elementul dorit folosind proprietatea animation . Similar cu proprietatea de transition , acceptă o durată, o funcție de relaxare și o întârziere.
Singura diferență este că primul parametru este numele nostru @keyframes în loc de numele unei proprietăți:
/* @keyframes name | duration | easing-function | delay */ animation: my-sliding-animation 3s linear 1s;Animarea unui Hamburger Comutare de meniu
Acum că avem o înțelegere de bază a modului în care funcționează animarea SVG-urilor, putem începe să construim o animație clasică - o comutare de meniu care trece ușor între o pictogramă „hamburger” și un buton de închidere (un „X”):
Vezi Pen Hamburger de Filip Defar (@dabrorius) pe CodePen.
Aceasta este o animație subtilă, dar valoroasă. Acesta atrage atenția utilizatorului, informându-l că pictograma poate fi folosită pentru a închide meniul.
Începem demonstrația prin crearea unui element SVG cu trei linii:
<svg class="hamburger"> <line x1="0" y1="50%" x2="100%" y2="50%" class="hamburger__bar hamburger__bar--top" /> <line x1="0" y1="50%" x2="100%" y2="50%" class="hamburger__bar hamburger__bar--mid" /> <line x1="0" y1="50%" x2="100%" y2="50%" class="hamburger__bar hamburger__bar--bot" /> </svg> Fiecare linie are două seturi de atribute. x1 și y1 reprezintă coordonatele începutului liniei, în timp ce x2 și y2 reprezintă coordonatele sfârșitului liniei. Am folosit unități relative pentru a stabili pozițiile. Aceasta este o modalitate simplă de a vă asigura că conținutul imaginii este redimensionat pentru a se potrivi cu elementul SVG care îl conține. Deși această abordare funcționează în acest caz, există un mare dezavantaj: nu putem menține raportul de aspect al elementelor poziționate în acest fel. Pentru asta, ar trebui să folosim atributul viewBox al elementului <svg> .
Rețineți că am aplicat clase CSS elementelor SVG. Există multe proprietăți care pot fi modificate prin CSS, așa că haideți să aplicăm câteva stiluri de bază elementelor noastre SVG.
Vom seta dimensiunea elementului <svg> , precum și vom schimba tipul de cursor pentru a indica faptul că se poate face clic pe acesta. Dar pentru a seta culoarea și grosimea liniilor, vom folosi proprietățile stroke și stroke-width . S-ar putea să vă fi așteptat să utilizați color sau border , dar spre deosebire de <svg> în sine, subelementele SVG nu sunt elemente HTML, deci au adesea nume de proprietate diferite:
.hamburger { width: 62px; height: 62px; cursor: pointer; } .hamburger__bar { stroke: white; stroke-width: 10%; } Dacă redăm în acest moment, vom vedea că toate cele trei linii au aceeași dimensiune și poziție, suprapunându-se complet. Din păcate, nu putem schimba pozițiile de început și de sfârșit în mod independent prin CSS, dar putem muta elemente întregi. Să mutăm barele de sus și de jos cu proprietatea CSS de transform :
.hamburger__bar--top { transform: translateY(-40%); } .hamburger__bar--bot { transform: translateY(40%); }Prin mutarea barelor pe axa Y ajungem la un hamburger cu aspect decent.
Acum este timpul să ne codificăm a doua stare: butonul de închidere. Ne bazăm pe o clasă CSS .is-opened aplicată elementului SVG pentru a comuta între cele două stări. Pentru a face rezultatul mai accesibil, să înfășurăm SVG-ul nostru într-un element <button> și să gestionăm clicurile la acel nivel.
Procesul de adăugare și eliminare a clasei va fi gestionat de un simplu fragment JavaScript:
const hamburger = document.querySelector("button"); hamburger.addEventListener("click", () => { hamburger.classList.toggle("is-opened"); }); Pentru a crea X-ul nostru, putem aplica o proprietate de transform diferită barurilor noastre cu hamburger. Deoarece noua proprietate de transform o va înlocui pe cea veche, punctul nostru de plecare va fi poziția inițială, comună, a celor trei bare.
De acolo, putem roti bara de sus cu 45 de grade în sensul acelor de ceasornic în jurul centrului său și bara de jos cu 45 de grade în sens invers acelor de ceasornic. Putem micșora bara de mijloc pe orizontală până când este suficient de îngustă pentru a fi ascunsă în spatele centrului X:
.is-opened .hamburger__bar--top { transform: rotate(45deg); } .is-opened .hamburger__bar--mid { transform: scaleX(0.1); } .is-opened .hamburger__bar--bot { transform: rotate(-45deg); } În mod implicit, proprietatea transform-origin pentru elementele SVG este în mod normal 0,0 . Aceasta înseamnă că barele noastre vor fi rotite în jurul colțului din stânga sus al ferestrei de vizualizare, dar dorim ca acestea să se rotească în jurul centrului. Pentru a remedia acest lucru, să setăm proprietatea transform-origin la center pentru clasa .hamburger__bar .

Animarea proprietăților CSS cu transition
Proprietatea CSS de transition îi spune browserului să facă tranziția fără probleme între două stări diferite ale proprietăților CSS. Aici dorim să animem modificările aduse proprietății de transform , care dictează pozițiile, orientarea și scara barelor.
De asemenea, putem controla durata tranziției folosind proprietatea transition-duration . Pentru a face animația să pară captivantă, vom seta o durată scurtă de 0,3 secunde:
.hamburger__bar { transition-property: transform; transition-duration: 0.3s; ... }Singura bucată de JavaScript de care avem nevoie este bitul care face ca starea pictogramei să fie comutată:
const hamburger = document.querySelector("button"); hamburger.addEventListener("click", () => { hamburger.classList.toggle("is-opened"); }); Aici, selectăm elementul SVG exterior după clasa sa .mute folosind querySelector() . Apoi adăugăm un ascultător de evenimente clic. Când se declanșează un eveniment de clic, comutăm clasa .is-active numai pe <svg> în sine — nu mai profund în ierarhie. Deoarece am făcut ca animația CSS să se aplice doar elementelor cu clasa .is-active , comutarea acestei clase va activa și dezactiva animația.
Ca o atingere finală, vom converti corpul HTML într-un container flexibil, ceea ce ne va ajuta să centram pictograma orizontal și vertical. De asemenea, vom actualiza culoarea de fundal la un gri foarte închis și culoarea pictogramei la alb, pentru a obține un aspect și un aspect elegant „mod întunecat”:
body { display: flex; justify-content: center; align-items: center; background-color: #222; height: 100vh; }Cu asta, am creat un buton animat complet funcțional, folosind niște CSS de bază și un scurt fragment JavaScript. Este ușor să schimbați transformările pe care le-am aplicat pentru a realiza o varietate de animații. Cititorii pot pur și simplu bifurca CodePen – care include un pic de CSS suplimentar pentru lustruire – și pot fi creativi.
Lucrul cu date SVG de la editori externi
Meniul nostru de hamburgeri este extrem de simplu. Dacă vrem să facem ceva mai complex? Acolo devine dificilă codarea manuală SVG, iar software-ul de editare a graficelor vectoriale poate ajuta.
A doua noastră animație SVG este un buton de dezactivare a sunetului care arată o pictogramă pentru căști. Când muzica este activă, icoana va pulsa și va dansa; când este dezactivată, pictograma va fi tăiată:
Vedeți butonul Pen Mute - 5 - barat roșu de Filip Defar (@dabrorius) pe CodePen.
Pictogramele de desen ar fi în afara domeniului de aplicare al acestui tutorial (și probabil descrierea postului dvs.), așa că vom începe cu o pictogramă SVG desenată în prealabil. De asemenea, ne vom dori același stil de body ca exemplul nostru de meniu de hamburger.
Poate doriți să curățați codul SVG înainte de a lucra cu el. Puteți face acest lucru cu svgo, un instrument de optimizare SVG cu sursă deschisă, bazat pe Node.js. Acest lucru va elimina elementele inutile și va face codul mai ușor de editat manual, ceea ce va trebui să faceți pentru a adăuga clase și a combina diferite elemente.
Pictogramele SVG create în software-ul de editare a imaginilor este puțin probabil să folosească unități relative. În plus, dorim să ne asigurăm că raportul de aspect al pictogramei este menținut, indiferent de raportul de aspect al elementului SVG care o conține. Pentru a face posibil acest nivel de control, vom folosi atributul viewBox .
Este o idee bună să redimensionați SVG, astfel încât viewBox să poată fi setat la niște valori ușor de utilizat. În acest caz, l-am convertit într-un viewBox care are 100 x 100 pixeli.
Să ne asigurăm că pictograma este centrată și dimensionată corespunzător. Vom aplica clasa mute la elementul nostru SVG de bază și apoi vom adăuga următoarele stiluri CSS:
.mute { fill: white; width: 80px; height: 70px; cursor: pointer; } Aici, width este puțin mai mare decât height pentru a evita tăierea în timpul rotațiilor animației noastre.
Punctul nostru de pornire al animației SVG
SVG-ul acum curat conține un singur element <g> care conține trei elemente <path> .
Elementul cale ne permite să desenăm linii, curbe și arce. Căile sunt descrise cu o serie de comenzi care descriu modul în care trebuie desenată forma. Deoarece pictograma noastră constă din trei forme neconectate, avem trei căi pentru a le descrie.
Elementul g SVG este un container folosit pentru a grupa alte elemente SVG. Îl folosim pentru a aplica simultan transformările pulsatoare și dansante pe toate cele trei căi.
<svg class="mute" viewBox="0 0 100 100"> <g> <path d="M92.6,50.075C92.213,26.775 73.25,7.938 50,7.938C26.75,7.938 7.775,26.775 7.388,50.075C3.112,51.363 -0.013,55.425 -0.013,60.25L-0.013,72.7C-0.013,78.55 4.575,83.3 10.238,83.3L18.363,83.3L18.363,51.6C18.4,51.338 18.438,51.075 18.438,50.813C18.438,33.275 32.6,19 50,19C67.4,19 81.563,33.275 81.563,50.813C81.563,51.088 81.6,51.338 81.638,51.6L81.638,83.313L89.763,83.313C95.413,83.313 100.013,78.563 100.013,72.713L100.013,60.263C100,55.438 96.875,51.362 92.6,50.075Z" /> <path d="M70.538,54.088L70.538,79.588C70.538,81.625 72.188,83.275 74.225,83.275L74.225,83.325L78.662,83.325L78.662,50.4L74.225,50.4C72.213,50.4 70.538,52.063 70.538,54.088Z" /> <path d="M25.75,50.4L21.313,50.4L21.313,83.325L25.75,83.325L25.75,83.275C27.788,83.275 29.438,81.625 29.438,79.588L29.438,54.088C29.45,52.063 27.775,50.4 25.75,50.4Z" /> </g> </svg> Pentru a face căștile să pulseze și să danseze, transition nu va fi suficientă. Acesta este un exemplu suficient de complex pentru a avea nevoie de cadre cheie.
În acest caz, cadrele cheie de început și de sfârșit (la 0% și, respectiv, 100% din animație) folosesc o pictogramă pentru căști ușor micșorată. Pentru primele 40% din animație creștem ușor imaginea și o înclinăm cu 5 grade. Apoi, pentru următorii 40% din animație, o reducem la 0,9x și o rotim cu 5 grade spre cealaltă parte. În cele din urmă, pentru ultimele 20% din animație, transformarea pictogramei revine la aceiași parametri inițiali pentru a se desfășura fără probleme.
@keyframes pulse { 0% { transform: scale(0.9); } 40% { transform: scale(1) rotate(5deg); } 80% { transform: scale(1) rotate(-5deg); } 100% { transform: scale(0.9) rotate(0); } }Optimizări de animație CSS
Pentru a arăta cum funcționează cadrele cheie, am lăsat CSS-ul cadrelor cheie mai detaliate decât trebuie. Există trei moduri în care l-am putea scurta.
Deoarece cadrul nostru cheie 100% setează întreaga listă de transform , dacă ar fi să omitem complet rotate() , valoarea lui ar fi implicit 0:
100% { transform: scale(0.9); } În al doilea rând, știm că vrem ca cadrele cheie 0% și 100% să se potrivească, deoarece facem buclă animația. Prin definirea lor cu aceeași regulă CSS, nu va trebui să ne amintim să le modificăm pe ambele dacă vrem să schimbăm acest punct comun în bucla de animație:
0%, 100% { transform: scale(0.9); } În cele din urmă, vom aplica în curând transform: scale(0.9); la clasa mute__headphones și, atunci când o facem, nu va fi deloc nevoie să definim cadrele cheie de început și de sfârșit! Se vor folosi implicit stilul static folosit de mute__headphones .
Acum că am definit cadrele cheie de animație, putem aplica animația. Adăugăm clasa .mute__headphones la elementul <g> , astfel încât să afecteze toate cele trei părți ale pictogramei căști. În primul rând, setăm din nou transform-origin la center , deoarece dorim ca pictograma să se rotească în jurul centrului său. De asemenea, o scalam astfel încât dimensiunea sa să se potrivească cu cadrul cheie de animație inițială. Fără acest pas, trecerea de la pictograma statică „dezactivată” la cea animată va duce întotdeauna la o creștere bruscă a dimensiunii. (În orice caz, revenirea la dezactivat va provoca un salt în scară – și probabil și o rotație – dacă utilizatorul face clic în timp ce scara este mai mare de 0,9x. Nu putem face mare lucru în privința acestui efect numai cu CSS.)
Aplicam animația folosind proprietatea CSS de animation , dar numai atunci când clasa părinte .is-active este prezentă, similar cu modul în care am animat meniul nostru hamburger.
.mute__headphones { transform-origin: center; transform: scale(0.9); } .is-active .mute__headphones { animation: pulse 2s infinite; }JavaScript de care avem nevoie pentru a ne permite să comutăm între stări urmează același model ca și meniul hamburger:
const muteButton = document.querySelector(".mute"); muteButton.addEventListener("click", () => { muteButton.classList.toggle("is-active"); }); Următoarea piesă pe care o vom adăuga este o linie barată care apare atunci când pictograma este inactivă. Deoarece acesta este un element de design simplu, îl putem codifica manual. Aici este util să aveți valori viewBox simple și rezonabile. Știm că marginile pânzei sunt la 0 și 100, așa că este ușor să calculăm pozițiile de început și de sfârșit pentru linia noastră:
<line x1="12" y1="12" x2="88" y2="88" class="mute__strikethrough" />Redimensionare vs. Utilizarea unităților relative
Se poate face un caz pentru utilizarea unităților relative în loc de redimensionarea imaginii. Acest lucru se aplică în exemplul nostru, deoarece adăugăm doar o simplă linie SVG peste pictograma noastră.
În scenariile din lumea reală, este posibil să doriți să combinați conținut SVG mai complex din mai multe surse diferite. Aici este util să le facem pe toate o dimensiune uniformă, deoarece nu putem codifica manual valorile relative așa cum am făcut în exemplul nostru.
Deoarece am aplicat o clasă direct elementului <line> barat, o putem stila prin CSS. Trebuie doar să ne asigurăm că linia nu este vizibilă atunci când pictograma este activă:
.mute__strikethrough { stroke: red; opacity: 0.8; stroke-width: 12px; } .is-active .mute__strikethrough { opacity: 0; } Opțional, putem adăuga clasa .is-active direct la SVG. Acest lucru va face ca animația să înceapă de îndată ce pagina este încărcată, așa că vom schimba efectiv starea inițială a pictogramei de la neanimată (dezactivată) la animată (nedezactivată).
Animația SVG bazată pe CSS este aici pentru a rămâne
Am zgâriat doar suprafața tehnicilor de animație CSS și modul în care funcționează ferestrele de vizualizare. Merită să știți cum să scrieți manual codul SVG pentru a menține animațiile simple simple, dar este, de asemenea, important să știți cum și când să folosiți grafica creată cu editori externi. În timp ce browserele moderne ne permit să creăm animații impresionante folosind doar funcționalitatea încorporată, pentru cazuri de utilizare (foarte) complexe, dezvoltatorii ar putea dori să exploreze biblioteci de animații precum GSAP sau anime.js.
Animațiile nu trebuie rezervate pentru proiecte extravagante. Tehnicile moderne de animație CSS ne permit să creăm o gamă largă de animații captivante și șlefuite într-un mod simplu, compatibil între browsere.
Mulțumiri speciale lui Mike Zeballos pentru recenzia tehnică a acestui articol!
