Hekiranje Stanje animacije CSS in čas predvajanja PlatoBlockchain Data Intelligence. Navpično iskanje. Ai.

Vdor v stanje animacije CSS in čas predvajanja

Wolfenstein samo za CSS je majhen projekt, ki sem ga naredil pred nekaj tedni. Šlo je za eksperiment s 3D transformacijami in animacijami CSS.

Navdih FPS demo in drugo Wolfenstein CodePen, sem se odločil zgraditi svojo različico. Ohlapno temelji na 1. epizodi – 9. nadstropje izvirne igre Wolfenstein 3D.

Urednik: Ta igra namerno zahteva nekaj hitrega odziva, da se izognete zaslonu Game Over.

Tukaj je videoposnetek predvajanja:

[Vgrajeni vsebina]

Na kratko, moj projekt ni nič drugega kot skrbno skriptirana dolga animacija CSS. Plus nekaj primerov kramp potrditvenega polja.

:checked ~ div { animation-name: spin; }

Okolje je sestavljeno iz ploskev 3D mreže, animacije pa so večinoma navadni 3D prevodi in rotacije. Nič zares elegantnega.

Vendar je bilo dve težavi še posebej težavno rešiti:

  • Predvajaj animacijo »orožje, ki strelja« vsakič, ko igralec klikne na sovražnika.
  • Ko hitri šef dobi zadnji udarec, vnesite dramatičen počasen posnetek.

Na tehnični ravni je to pomenilo:

  • Ponovno predvajajte animacijo, ko je potrjeno naslednje potrditveno polje.
  • Upočasnite animacijo, ko je potrjeno potrditveno polje.

Pravzaprav nobeno ni bilo ustrezno rešeno v mojem projektu! Bodisi sem uporabil rešitve ali pa obupal.

Po drugi strani pa sem po nekaj kopanja končno našel ključ do obeh težav: spreminjanje lastnosti izvajanja animacij CSS. V tem članku bomo podrobneje raziskali to temo:

  • Veliko interaktivnih primerov.
  • Disekcije: kako vsak primer deluje (ali ne deluje)?
  • Zakulisje: kako brskalniki obravnavajo stanja animacije?

Dovoli mi "vrzi moje opeke".

Problem 1: Ponovno predvajanje animacije

Prvi primer: "samo še eno potrditveno polje"

Moja prva intuicija je bila »samo dodaj še eno potrditveno polje«, kar pa ne deluje:

Vsako potrditveno polje deluje posamično, ne pa oboje skupaj. Če je eno potrditveno polje že označeno, drugo ne deluje več.

Evo, kako deluje (ali "ne deluje"):

  1. O animation-name of <div> is none privzeto.
  2. Uporabnik klikne eno potrditveno polje, animation-name postane spin, in animacija se začne od začetka.
  3. Čez nekaj časa uporabnik klikne drugo potrditveno polje. Veljati začne novo pravilo CSS, vendar animation-name is Še vedno spin, kar pomeni, da nobena animacija ni dodana ali odstranjena. Animacija se preprosto nadaljuje s predvajanjem, kot da se ni nič zgodilo.

Drugi primer: "kloniranje animacije"

En delovni pristop je kloniranje animacije:

#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2; }

Tukaj je, kako to deluje:

  1. animation-name is none na začetku.
  2. Uporabnik klikne na “Spin!”, animation-name postane spin1. Animacija spin1 se začne od začetka, ker je bil pravkar dodan.
  3. Uporabnik klikne »Spin again!«, animation-name postane spin2. Animacija spin2 se začne od začetka, ker je bil pravkar dodan.

Upoštevajte, da je v 3. koraku spin1 je odstranjen zaradi vrstnega reda pravil CSS. Ne bo delovalo, če »Spin again!« se najprej preveri.

Tretji primer: "pripenjanje iste animacije"

Drug delovni pristop je "pripenjanje iste animacije":

#spin1:checked ~ div { animation-name: spin; }
#spin2:checked ~ div { animation-name: spin, spin; }

To je podobno prejšnjemu primeru. Vedenje lahko dejansko razumete takole:

#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2, spin1; }

Upoštevajte, da ko se pojavi »Spin again!« je potrjena, postane stara tekoča animacija druga animacija na novem seznamu, kar je lahko neintuitivno. Neposredna posledica je: trik ne bo deloval, če animation-fill-mode is forwards. Tukaj je demo:

Če se sprašujete, zakaj je temu tako, je tukaj nekaj namigov:

  • animation-fill-mode is none privzeto, kar pomeni »Animacija nima nobenega učinka, če se ne predvaja«.
  • animation-fill-mode: forwards; pomeni "Ko se animacija konča s predvajanjem, mora za vedno ostati na zadnji ključni sličici".
  • spin1odločitev vedno prevlada spin2je zato spin1 se pojavi pozneje na seznamu.
  • Recimo, da uporabnik klikne »Spin!«, počaka na popolno vrtenje, nato pa klikne »Spin again!«. Ta trenutek. spin1 je že končano in spin2 šele začne.

Razprava

Osnovno pravilo: ne morete znova zagnati obstoječe animacije CSS. Namesto tega želite dodati in predvajati novo animacijo. To lahko potrdi specifikacije W3C:

Ko se animacija začne, se nadaljuje, dokler se ne konča ali dokler ni odstranjeno ime animacije.

Če sedaj primerjam zadnja dva primera, menim, da bi moralo v praksi "kloniranje animacij" pogosto delovati bolje, zlasti če je na voljo predprocesor CSS.

Problem 2: Slow Motion

Morda bi kdo mislil, da je upočasnitev animacije le stvar nastavitve daljšega animation-duration:

div { animation-duration: 0.5s; }
#slowmo:checked ~ div { animation-duration: 1.5s; }

Dejansko to deluje:

… ali res?

Z nekaj prilagoditvami bi moralo biti lažje videti težavo.

Da, animacija je upočasnjena. In ne, ne izgleda dobro. Pes (skoraj) vedno "skoči", ko preklopite potrditveno polje. Poleg tega se zdi, da pes skoči na naključen položaj in ne na začetni. Kako to?

Lažje bi ga razumeli, če bi uvedli dva "senčna elementa":

Oba senčna elementa izvajata iste animacije z različnimi animation-duration. In potrditveno polje nanje ne vpliva.

Ko preklopite potrditveno polje, element takoj preklopi med stanjema dveh senčnih elementov.

Citiranje specifikacije W3C:

Spremembe vrednosti lastnosti animacije med izvajanjem animacije veljajo, kot da bi imela animacija te vrednosti od začetka.

Temu sledi brez državljanstva design, ki brskalnikom omogoča preprosto določanje animirane vrednosti. Opisan je dejanski izračun tukaj in tukaj.

Še en poskus

Ena ideja je, da začasno ustavite trenutno animacijo in nato dodate počasnejšo animacijo, ki prevzame od tam:

div {
  animation-name: spin1;
  animation-duration: 2s;
}

#slowmo:checked ~ div {
  animation-name: spin1, spin2;
  animation-duration: 2s, 5s;
  animation-play-state: paused, running;
}

Torej deluje:

… ali res?

Ko kliknete »Slowmo!«, se upočasni. Če pa počakate na polni krog, boste videli "skok". Pravzaprav vedno skoči na položaj, ko »Slowmo!« se klikne.

Razlog je, da nimamo from definiran ključni okvir – in ne bi smeli. Ko uporabnik klikne »Slowmo!«, spin1 se ustavi na nekem mestu in spin2 začne na povsem enakem položaju. Tega položaja preprosto ne moremo predvideti vnaprej … ali pa lahko?

Delujoča rešitev

Mi lahko! Z uporabo lastnosti po meri lahko zajamemo kot v prvi animaciji in ga nato posredujemo drugi animaciji:

div {
  transform: rotate(var(--angle1));
  animation-name: spin1;
  animation-duration: 2s;
}

#slowmo:checked ~ div {
  transform: rotate(var(--angle2));
  animation-name: spin1, spin2;
  animation-duration: 2s, 5s;
  animation-play-state: paused, running;
}

@keyframes spin1 {
  to {
    --angle1: 360deg;
  }
}

@keyframes spin2 {
  from {
    --angle2: var(--angle1);
  }
  to {
    --angle2: calc(var(--angle1) + 360deg);
  }
}

Opomba: @property se uporablja v tem primeru, ki je ne podpirajo vsi brskalniki.

"Popolna" rešitev

Pri prejšnji rešitvi obstaja opozorilo: »izhod iz slowmo« ne deluje dobro.

Tukaj je boljša rešitev:

V tej različici lahko počasen posnetek brezhibno vstopite ali izstopite. Prav tako ni uporabljena nobena eksperimentalna funkcija. Je torej popolna rešitev? Da in ne.

Ta rešitev deluje kot "prestavljanje" "prestav":

  • Prestave: sta dve <div>s. Eden je starš drugega. Oba imata spin animacijo, vendar z različnimi animation-duration. Končno stanje elementa je kopičenje obeh animacij.
  • Prestavljanje: Na začetku samo eno <div> ima svojo animacijo. Drugi je zaustavljen. Ko je potrditveno polje preklopljeno, obe animaciji zamenjata svoja stanja.

Čeprav mi je rezultat zelo všeč, obstaja ena težava: gre za lepo izkoriščanje spin animacijo, ki na splošno ne deluje za druge vrste animacij.

Praktična rešitev (z JS)

Za splošne animacije je mogoče doseči funkcijo počasnega posnetka z malo JavaScripta:

Hitra razlaga:

  • Lastnost po meri se uporablja za sledenje napredku animacije.
  • Animacija se »znova zažene«, ko preklopite potrditveno polje.
  • Koda JS izračuna pravilno animation-delay da zagotovimo nemoten prehod. priporočam ta članek če niste seznanjeni z negativnimi vrednostmi animation-delay.

Na to rešitev lahko gledate kot na hibrid »ponovnega zagona animacije« in pristopa »prestavljanja«.

Pri tem je pomembno, da pravilno spremljate potek animacije. Rešitve so možne, če @property ni na voljo. Kot primer uporablja ta različica z-index za spremljanje napredka:

Dodatna opomba: prvotno sem tudi poskušal ustvariti različico samo za CSS, vendar mi ni uspelo. Čeprav nisem 100 % prepričan, mislim, da je to zato, ker animation-delay is ni mogoče animirati.

Tukaj je različica z minimalnim JavaScriptom. Deluje samo »vstop v slowmo«.

Sporočite mi, če vam uspe ustvariti delujočo različico samo s CSS!

Počasna katera koli animacija (z JS)

Na koncu bi rad delil rešitev, ki deluje za (skoraj) vse animacije, tudi z več zapletenimi @keyframes:

V bistvu morate dodati sledilnik napredka animacije in nato natančno izračunati animation-delay za novo animacijo. Vendar je včasih lahko težavno (vendar možno) pridobiti pravilne vrednosti.

Na primer:

  • animation-timing-function ni linear.
  • animation-direction ni normal.
  • več vrednosti v animation-name z različnimi animation-durationje in animation-delayje.

Ta metoda je tudi opisana tukaj za API za spletne animacije.

Priznanja

Po tej poti sem začel po srečanju s projekti, ki uporabljajo samo CSS. Nekateri so bili občutljivo umetniško delo, in nekateri so bili kompleksne naprave. Moji najljubši so tisti, ki vključujejo 3D predmete, na primer to odskočna žoga in to kocka za pakiranje.

Na začetku nisem imel pojma, kako so bili narejeni. Kasneje sem bral in se od njega veliko naučil to lepo vadnico Ane Tudor.

Izkazalo se je, da se gradnja in animiranje 3D-predmetov s CSS ne razlikuje veliko od tega, da to počnete s Blender, le z malo drugačnim okusom.

zaključek

V tem članku smo preučili obnašanje animacij CSS, ko je animate-* nepremičnina se spremeni. Posebej smo izdelali rešitve za "ponovno predvajanje animacije" in "počasni posnetek animacije".

Upam, da vam bo ta članek zanimiv. Prosim, povejte mi svoje misli!

Časovni žig:

Več od Triki CSS