Actualizarea animației CSS cu curbe de mișcare

Publicat: 2022-03-10
Rezumat rapid ↬ Există o animație UI și apoi o animație UI bună . O animație bună te face să faci „Wow!” — este neted, frumos și, mai ales, natural, nu blocat, rigid sau robotizat. Dacă frecventezi Dribbble sau UpLabs, vei ști despre ce vorbesc. Cu atât de mulți designeri uimitori care creează astfel de animații frumoase, orice dezvoltator ar dori în mod natural să le recreeze în propriile proiecte. Acum, CSS oferă unele presetări pentru transition-timing-function , cum ar fi ease-in , ease-out și ease-in-out , care adaugă un anumit nivel de netezime și realism, dar sunt foarte generice, nu-i așa? Cât de plictisitor ar fi dacă fiecare animație de pe web ar urma aceleași trei funcții de sincronizare?

Există animație UI și apoi animație UI bună . O animație bună te face să faci „Wow!” — este neted, frumos și, mai ales, natural, nu blocat, rigid sau robotizat. Dacă frecventezi Dribbble sau UpLabs, vei ști despre ce vorbesc.

Citiri suplimentare despre Smashing:

  • Animații SVG și CSS cu traseu clip
  • Tehnici practice de animație
  • Crearea de animații „desenate manual” cu SVG
  • Noul API de animație web

Cu atât de mulți designeri uimitori care creează astfel de animații frumoase, orice dezvoltator ar dori în mod natural să le recreeze în propriile proiecte. Acum, CSS oferă unele presetări pentru transition-timing-function , cum ar fi ease-in , ease-out și ease-in-out , care adaugă un anumit nivel de netezime și realism, dar sunt foarte generice, nu-i așa? Cât de plictisitor ar fi dacă fiecare animație de pe web ar urma aceleași trei funcții de sincronizare?

(Credit: Lukaš Stranak)
Mai multe după săritură! Continuați să citiți mai jos ↓

Una dintre proprietățile transition-timing-function este cubic-bezier(n1, n2, n3, n4) , în care puteți trece patru numere pentru a vă crea propria funcție de sincronizare. Spre sfârșitul acestui articol, veți ști exact ce reprezintă aceste patru numere - totuși, credeți-mă, să veniți cu patru numere pentru a surprinde tranziția pe care o imaginați în capul vostru nu este deloc ușor de făcut. Dar datorită lui cubic-bezier și Ceasar, nu trebuie. Aceste instrumente aduc curbe de mișcare pe web.

Curbele de mișcare sunt utilizate în principal de animatori (de exemplu, în Adobe After Effects) pentru a crea animații avansate, realiste. Cu cubic-bezier și Ceasar, puteți manipula pur și simplu forma unei curbe, iar acele patru numere ( n1, n2, n3, n4 ) vor fi completate pentru dvs., ceea ce este absolut grozav! Totuși, pentru a utiliza și a profita la maximum de curbele de mișcare, trebuie să înțelegeți cum funcționează acestea și asta vom face în acest articol. Sa incepem.

Înțelegerea curbelor de mișcare

O curbă de mișcare nu este altceva decât o diagramă între orice proprietate animabilă și timp. O curbă de mișcare definește modul în care viteza unei animații care rulează sub influența sa variază în timp.

Curba de mișcare este o diagramă între proprietatea animabilă și timp.
O curbă de mișcare este o diagramă între o proprietate animabilă și timp. (Vezi versiunea mare)

Să luăm distanța ( translateX ) ca exemplu de proprietate animabilă. (Explicația este valabilă pentru orice altă proprietate animabilă.)

Calcularea vitezei la momentul t1 pe o diagramă distanță-timp.
Calcularea vitezei la momentul t1 pe graficul distanță-timp. (Vezi versiunea mare)

Dacă ați avut experiență cu fizica și calculul de bază, veți ști că descifrarea vitezei dintr-un grafic distanță-timp este foarte simplă. Prima derivată a distanței în funcție de timp , în raport cu timpul , este viteza, ceea ce înseamnă că un obiect care urmează o curbă distanță-timp ar avea o viteză mai mare în locurile în care curba este abruptă și mai mică în locurile în care curba este mai plată. . Dacă știi cum funcționează, grozav! Sunteți gata și puteți sări la secțiunea următoare.

Acum, sunt conștient de faptul că proiectarea și dezvoltarea este un domeniu divers și nu toată lumea are același background. Poate că cele două paragrafe de mai sus au fost toate jargon pentru tine. Nu te supăra. Vom continua și vom înțelege jargonul.

Luați în considerare caseta roșie de mai jos. Să luăm puțină callow aici și să numim caseta roșie „Boxy”; va fi mai ușor să te referi la asta în acest fel. Bine, deci Boxy se va muta de la o margine la alta a ecranului într-un mod liniar și vom analiza mișcarea acestuia.

Una dintre presetări ale transition-timing-function este linear . Pentru a-l face pe Boxy să se miște, tot ce facem este să adăugăm următoarea clasă.

 .moveForward { transform: translateX(1000px); }

Pentru a controla animația, am seta proprietatea de transition pentru Boxy după cum urmează:

 #boxy { width: 200px; height: 200px; background: red; transition-property: transform; transition-duration: 1s; transition-timing-function: linear; }

Acesta este un mod foarte pronunțat de a specifica transition . În realitate, aproape întotdeauna veți găsi transition scrisă în forma ei scurtă:

 #boxy { width: 200px; height: 200px; background: red; transition: transform 1s linear; }

Să vedem că merge.

Boxy în curs de mișcare liniară
Cutie aflată în mișcare liniară.

Robotic, nu-i așa? Ați putea spune că această mișcare pare robotică deoarece este liniară, ceea ce este un răspuns perfect plauzibil. Dar ai putea explica de ce? Putem vedea că stabilirea linear are ca rezultat mișcarea robotică, dar ce se întâmplă exact în spatele scenei? Asta ne vom da seama mai întâi; vom ajunge la interior și vom înțelege de ce această mișcare pare robotică, blocată și nu naturală.

Să începem prin a reprezenta grafic mișcarea lui Boxy pentru a vedea dacă putem obține o perspectivă. Graficul nostru va avea două axe, prima fiind distanța și a doua timp. Boxy acoperă o distanță totală de 1000 de pixeli (distanță) în 1 secundă (timp). Acum, nu vă speriați de toate matematicile de mai jos - este foarte simplu.

Iată graficul nostru foarte simplu, cu axele așa cum am menționat.

Grafic gol cu ​​axe
Grafic gol cu ​​axe (Vezi versiunea mare)

Chiar acum, este gol. Să-l completăm cu câteva date.

Pentru început, știm că la 0 secunde, când animația nu a început încă, Boxy se află în poziția inițială (0 pixeli). Și după ce a trecut 1 secundă, Boxy a parcurs un total de 1000 de pixeli, ajungând pe marginea opusă a afișajului.

Pozițiile inițiale și finale ale lui Boxy
Pozițiile inițiale și finale ale lui Boxy (Vezi versiunea mare)

Să reprezentăm aceste date pe grafic.

Grafic cu pozițiile inițiale și finale ale lui Boxy
Grafic cu pozițiile inițiale și finale ale lui Boxy reprezentate (Vezi versiunea mare)

Până acum, bine. Dar două puncte de date nu sunt suficiente - avem nevoie de mai multe. Următoarea figură arată pozițiile lui Boxy în diferite momente de timp (toate datorită camerei mele de mare viteză).

Pozițiile lui Boxy în momente diferite
Pozițiile lui Boxy în momente diferite (Vezi versiunea mare)

Să adăugăm aceste date la graficul nostru.

Grafic cu diferite poziții reprezentate
Grafic cu diferite poziții reprezentate (Vezi versiunea mare)

Desigur, puteți avea mai multe puncte de date pentru timpi diferiți (de exemplu, 0,375 secunde, 0,6 secunde etc.), dar ceea ce avem este suficient pentru a ne completa graficul. Unind toate punctele, am completat graficul. Bate palma!

Graficul final
Graficul final (Vezi versiunea mare)

Cool, dar ce ne spune asta? Îți amintești că ne-am început investigația cu scopul de a înțelege de ce mișcarea liniară a lui Boxy este nenaturală și robotică? La o privire, acest grafic pe care tocmai l-am construit nu ne spune nimic despre asta. Trebuie să mergem mai adânc.

Tine cont de grafic si hai sa vorbim un minut despre viteza. Știu că știi ce este viteza — aș dori doar să o exprim în termeni matematici. În continuare, formula vitezei este următoarea:

Formula matematică pentru viteză
Formula matematică pentru viteză (Vezi versiunea mare)

Prin urmare, dacă o mașină parcurge o distanță de 100 de kilometri într-o oră, spunem că viteza ei este de 100 de kilometri pe oră.

Reprezentând viteza
Reprezentând viteza (Vezi versiunea mare)

Dacă mașina își dublează viteza, va începe să parcurgă dublul distanței (200 de kilometri) în același interval (1 oră), sau, cu alte cuvinte, va parcurge distanța inițială de 100 de kilometri în jumătate de timp (0,5 ore). . Are sens?

În mod similar, dacă mașina și-ar înjumătăți viteza (adică încetinește la jumătate), ar începe să parcurgă o distanță de 50 de kilometri în același interval (1 oră), sau, cu alte cuvinte, ar parcurge distanța inițială de 100 de kilometri. kilometri în timp de două ori (2 ore).

Grozav! Cu asta din drum, să reluăm de unde am rămas. Încercam să ne dăm seama cum graficul dintre distanță și timp ne poate ajuta să înțelegem de ce mișcarea liniară a lui Boxy se simte robotică.

Hei, așteaptă o secundă! Avem un grafic între distanță și timp, iar viteza poate fi calculată din distanță și timp, nu-i așa? Să încercăm să calculăm viteza lui Boxy la diferite intervale de timp.

Calcularea vitezei la diferite intervale
Calcularea vitezei la diferite intervale (Vezi versiunea mare)

Aici, am ales trei intervale de timp diferite: unul lângă început, unul la mijloc și unul la sfârșit, lângă poziția finală. După cum este evident, la toate cele trei intervale, Boxy are exact aceeași viteză (s1 = s2 = s3) de 1000 de pixeli pe secundă; adică indiferent de intervalul pe care îl alegeți în graficul de mai sus, îl veți găsi pe Boxy mișcându-se la 1000 de pixeli pe secundă. Nu este ciudat? Lucrurile din viața reală nu se mișcă cu o viteză constantă; pornesc încet, își măresc treptat viteza, se mișcă un timp și apoi încetinesc din nou înainte de a se opri, dar Boxy începe brusc cu o viteză de 1000 de pixeli pe secundă, mișcându-se cu aceeași viteză și oprindu-se brusc la exact aceeași viteză. Acesta este motivul pentru care mișcarea lui Boxy pare robotică și nefirească. Va trebui să ne schimbăm graficul pentru a remedia acest lucru. Dar înainte de a ne scufunda, va trebui să știm cum vor afecta modificările vitezei graficul desenat între distanță și timp. Gata? Asta o să fie amuzant.

Să dublăm viteza lui Boxy și să vedem cum se schimbă aspectul graficului ca răspuns. Viteza originală a lui Boxy, așa cum am calculat mai sus, este de 1000 de pixeli pe secundă. Pentru că am dublat viteza, Boxy va putea acum să parcurgă distanța de 1000 de pixeli în jumătate din timp, adică în 0,5 secunde. Să punem asta pe un grafic.

Graficul care arată viteza dublă
Grafic care arată viteza dublă (Vezi versiunea mare)

Dacă triplăm viteza? Boxy acoperă acum 1000 de pixeli într-o treime din timp (o treime de secundă).

Grafic care arată viteza triplă
Grafic care arată viteza triplă (Vezi versiunea mare)

Hmm, ai observat ceva? Observați cum, atunci când graficul se schimbă, unghiul pe care linia îl face cu axa timpului crește pe măsură ce viteza crește.

În regulă, să mergem înainte și să reducem la jumătate viteza lui Boxy. Reducerea la jumătate a vitezei înseamnă că Boxy va putea acoperi doar 500 de pixeli (jumătate din distanța inițială) într-o secundă. Să punem asta pe un grafic.

Graficul care arată jumătate de viteză
Grafic care arată jumătate de viteză (Vezi versiunea mare)

Să încetinim mai mult Boxy, făcând viteza la o treime față de cea originală. Boxy va putea acoperi o treime din distanța inițială în 1 secundă.

Graficul care arată o treime din viteza
Grafic care arată o treime din viteza (Vezi versiunea mare)

Vezi un model? Linia devine din ce în ce mai abruptă pe măsură ce creștem viteza lui Boxy și începe să se aplatizeze pe măsură ce îl încetinim pe Boxy.

Linia devine mai abruptă pe măsură ce viteza crește și se aplatizează pe măsură ce viteza scade
Linia devine mai abruptă pe măsură ce viteza crește și se aplatizează pe măsură ce viteza scade. (Vezi versiunea mare)

Acest lucru are sens deoarece, pentru o linie mai abruptă, un mic progres în timp produce o schimbare mult mai mare a distanței, implicând o viteză mai mare.

O mică modificare a timpului produce o modificare relativ mare a distanței, ceea ce face un grafic mai abrupt.
O mică modificare a timpului produce o modificare relativ mare a distanței, ceea ce face un grafic mai abrupt. (Vezi versiunea mare)
O mică modificare a timpului produce o modificare relativ mare a distanței, ceea ce face un grafic mai abrupt.
O mică modificare a timpului produce o modificare relativ mare a distanței, ceea ce face un grafic mai abrupt. (Vezi versiunea mare)

Pe de altă parte, pentru o linie mai puțin abruptă, o schimbare mare a timpului produce doar o mică modificare a distanței, adică o viteză mai mică.

Schimbarea timpului față de modificarea distanței într-un grafic care este mai puțin abrupt
Modificarea timpului versus modificarea distanței într-un grafic care este mai puțin abrupt (Vedeți versiunea mare)
Modificarea timpului versus modificarea distanței într-un grafic care este mai puțin abrupt
Modificarea timpului versus modificarea distanței într-un grafic care este mai puțin abrupt (Vedeți versiunea mare)

Cu toate schimbările pe care le-am făcut, Boxy se mișcă în continuare într-o manieră liniară, doar la viteze diferite. Cu toate acestea, având în vedere noile noastre cunoștințe despre modul în care modificările distanței în raport cu timpul pot afecta viteza, putem experimenta și desena un grafic care să-l facă pe Boxy să se miște într-un mod care să pară natural și realist.

Să o luăm pas cu pas. În primul rând, lucrurile în viața reală încep încet și cresc încet în viteză. Deci, hai să facem asta.

În toate iterațiile graficului prezentat mai jos, veți observa că punctele din colțurile opuse rămân fixe. Acest lucru se datorează faptului că nu modificăm durata pentru care rulează animația și nici distanța pe care Boxy o parcurge.

Construirea unei curbe de mișcare personalizată
Construirea unei curbe de mișcare personalizată (Vedeți versiunea mare)

Dacă Boxy urmează să urmeze graficul de mai sus, se va deplasa cu o viteză mai mică timp de 0,25 secunde, deoarece linia este mai puțin abruptă începând de la 0 la 0,25 secunde, iar apoi va trece brusc la o viteză mai mare după 0,25 secunde (motivul fiind că linia din grafic devine mai abruptă după 0,25 secunde). Totuși, va trebui să netezim această tranziție; nu vrem colțuri — până la urmă se numește curbă de mișcare. Să transformăm acel colț într-o curbă.

Construirea unei curbe de mișcare personalizată
Construirea unei curbe de mișcare personalizată (Vedeți versiunea mare)

Observați tranziția lină pe care o trece Boxy de la starea de repaus la creșterea treptată a vitezei.

Boxy urmând curba de mișcare de mai sus
Caseta care urmează curba de mișcare de mai sus (Vezi versiunea mare)

Bun! Apoi, obiectele din viața reală încetinesc progresiv înainte de a se opri. Să schimbăm graficul pentru a face acest lucru. Din nou, vom relua un moment după care ne-am dori ca Boxy să înceapă să încetinească. Ce zici de aproximativ 0,6 secunde? Am netezit deja colțul tranziției la o curbă aici.

Curba finală de mișcare personalizată
Curba finală de mișcare personalizată (Vezi versiunea mare)

Uită-te la Boxy go! Mult mai natural, nu-i așa?

Boxy urmând curba de mișcare personalizată
Boxy urmând curba de mișcare personalizată (Vezi versiunea mare)

Curba pe care am trasat-o în locul colțului este de fapt o colecție de multe segmente de linie mici; și, după cum știți deja, cu cât linia de pe grafic este mai abruptă, cu atât viteza este mai mare și cu cât linia este mai plată, cu atât viteza este mai mică. Observați cum, în partea stângă a imaginii, segmentele de linie care alcătuiesc curba devin din ce în ce mai abrupte, ceea ce duce la o creștere treptată a vitezei și se aplatizează progresiv pe partea dreaptă, ceea ce duce la o scădere progresivă a vitezei?

O curbă nu este altceva decât o colecție de mai multe segmente de linie.
O curbă nu este altceva decât o colecție de mai multe segmente de linie. (Vezi versiunea mare)

Cu toate aceste cunoștințe, înțelegerea curbelor de mișcare devine mult mai ușoară. Să ne uităm la câteva exemple.

(Vezi versiunea mare)
Exemplul 1
Exemplul 1 (Vedeți versiunea mare)
(Vezi versiunea mare)
Exemplul 2
Exemplul 2 (Vezi versiunea mare)
(Vezi versiunea mare)
Exemplul 3
Exemplul 3 (Vedeți versiunea mare)

Utilizarea curbelor de mișcare în animația UI

Data viitoare când va trebui să animați un element UI, veți avea la dispoziție puterea curbelor de mișcare. Fie că este vorba de o bară glisantă, de o fereastră modală sau de un meniu derulant, adăugarea cantității potrivite de animație și făcându-l să arate neted și natural va crește foarte mult calitatea interfeței dvs. de utilizator. Va face ca interfața cu utilizatorul să se simtă bine. Luați meniul glisant de mai jos:

Vedeți Pen nJial de Nash Vail (@nashvail) pe CodePen.

Vedeți Pen nJial de Nash Vail (@nashvail) pe CodePen.

Făcând clic pe meniul de hamburger, apare meniul din stânga, dar animația pare blocată. Linia 51 din CSS arată că animația are transition-timing-function setată la linear . Putem îmbunătăți acest lucru. Să trecem la cubic-bezier și să creăm o funcție de sincronizare personalizată.

Dacă citiți acest lucru, este sigur să presupuneți că sunteți un designer sau un dezvoltator sau ambele și, prin urmare, nu sunteți străin de curbele cubice Bezier; sunt șanse mari să le fi întâlnit măcar o dată. Curbele Bezier sunt o minune. Ele sunt utilizate în principal în grafica computerizată pentru a desena forme și sunt utilizate în instrumente precum Sketch și Adobe Illustrator pentru a desena grafică vectorială. Motivul pentru care curbele cubice Bezier sunt atât de populare este că sunt atât de ușor de utilizat: trebuie doar să modificați pozițiile celor patru puncte diferite și să creați tipul de curbă de care aveți nevoie.

Deoarece știm întotdeauna stările inițiale și finale ale obiectului animat, putem fixa două dintre puncte. Mai rămân doar două puncte ale căror poziții trebuie să le modificăm. Cele două puncte fixe se numesc puncte de ancorare, iar cele două puncte rămase sunt puncte de control.

Părți ale unei curbe Bezier
Părți ale unei curbe Bezier (Vezi versiunea mare)

După cum vă amintiți, cubic-bezier acceptă patru numere ( n1, n2, n3, n4 ) atunci când creați o transition-timing-function . Aceste patru numere nu reprezintă altceva decât pozițiile celor două puncte de control: n1, n2 reprezintă coordonatele x și y ale primului punct de control, iar n3, n4 reprezintă coordonatele celui de-al doilea punct de control. Deoarece schimbarea poziției punctelor de control va schimba forma curbei și, prin urmare, animația noastră în ansamblu, rezultatul este același atunci când oricare sau toate dintre n1, n2, n3, n4 sunt modificate. De exemplu, figura de mai jos reprezintă cubic-bezier(.14, .78, .89, .35) :

O curbă bezier cubică reprezentând (.14, .78, .89, .35).
O curbă bezier cubică reprezentând (.14, .78, .89, .35) (Vezi versiunea mare)

Matematica din spatele acestor curbe aparent simple este fascinantă.

În regulă, în regulă, să revenim la locul în care mergeam cu cubic-bezier: crearea unei transition-timing-function . Vreau genul de animație în care meniul alunecă foarte repede și apoi încetinește cu grație și se termină:

Reglarea curbei bezier cubice
Reglarea curbei bezier cubice (Vezi versiunea mare)

Asta arată bine. Animația va începe rapid și apoi va încetini, mai degrabă decât să se miște cu o viteză constantă. Pur și simplu o să copiez cubic-bezier(.05, .69, .14, 1) din partea de sus a paginii și să înlocuiesc linear cu acesta.

Vedeți Pen nJial de Nash Vail (@nashvail) pe CodePen.

Vedeți Pen nJial de Nash Vail (@nashvail) pe CodePen.

Vezi diferenta? A doua iterație pare mult mai naturală și atrăgătoare. Imaginează-ți dacă fiecare animație din interfața ta de utilizare ar urma o funcție de sincronizare naturală. Cât de grozav ar fi?

După cum am văzut, curbele de mișcare nu sunt deloc complicate. Sunt foarte ușor de înțeles și de folosit. Cu ele, îți poți duce interfața la următorul nivel.

Sper că ați învățat cum funcționează curbele de mișcare. Dacă treceai prin multe încercări și erori pentru ca curbele de mișcare să funcționeze așa cum ți-ai dori sau dacă nu le foloseai deloc, acum ar trebui să te simți confortabil să le îndoiești după voința ta și să creezi animații frumoase. Pentru că, până la urmă, animația contează.