Hacker CSS-animáció állapota és lejátszási ideje PlatoBlockchain adatintelligencia. Függőleges keresés. Ai.

Hacker CSS-animáció állapota és lejátszási ideje

Csak CSS-t használó Wolfenstein egy kis projekt, amit néhány hete készítettem. Ez egy kísérlet volt CSS 3D transzformációkkal és animációkkal.

Ihlette FPS demó és egy másik Wolfenstein CodePen, úgy döntöttem, hogy elkészítem a saját verziómat. Lazán az eredeti Wolfenstein 1D-s játék 9. epizódja – 3. emeletén alapul.

Szerkesztő: Ez a játék szándékosan igényel gyors reakciót, hogy elkerülje a Game Over képernyőt.

Itt egy átjátszó videó:

[Beágyazott tartalmat]

Dióhéjban a projektem nem más, mint egy gondosan megszerkesztett hosszú CSS-animáció. Plusz néhány példa a checkbox hack.

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

A környezet 3D rácslapokból áll, az animációk pedig többnyire sima 3D fordítások és elforgatások. Semmi igazán divatos.

Két problémát azonban különösen nehéz volt megoldani:

  • Játssza le a „fegyverlövés” animációt, amikor a játékos rákattint egy ellenségre.
  • Amikor a gyorsan mozgó főnök megkapta az utolsó találatot, írjon be egy drámai lassítást.

Technikai szinten ez a következőket jelentette:

  • Játsszon újra egy animációt, ha a következő jelölőnégyzet be van jelölve.
  • Lassítsa le az animációt, ha egy jelölőnégyzet be van jelölve.

Valójában egyik sem volt megfelelően megoldva a projektemben! Vagy elkerülő megoldásokat használtam, vagy egyszerűen feladtam.

Másrészt némi ásás után végül megtaláltam mindkét probléma kulcsát: a CSS-animációk futtatásának tulajdonságainak megváltoztatását. Ebben a cikkben részletesebben foglalkozunk ezzel a témával:

  • Sok interaktív példa.
  • Boncolás: hogyan működnek (vagy nem működnek) az egyes példák?
  • A színfalak mögött: hogyan kezelik a böngészők az animációs állapotokat?

Hadd „dobd fel a téglaimat”.

1. probléma: Animáció újrajátszása

Az első példa: „csak egy jelölőnégyzet”

Az első megérzésem az volt, hogy „csak adj hozzá még egy jelölőnégyzetet”, ami nem működik:

Mindegyik jelölőnégyzet külön-külön működik, de együtt nem. Ha az egyik jelölőnégyzet már be van jelölve, a másik már nem működik.

Így működik (vagy „nem működik”):

  1. A animation-name of <div> is none alapértelmezés szerint.
  2. A felhasználó egy jelölőnégyzetre kattint, animation-name válik spin, és az animáció elölről kezdődik.
  3. Egy idő után a felhasználó rákattint a másik jelölőnégyzetre. Egy új CSS-szabály lép életbe, de animation-name is még mindig spin, ami azt jelenti, hogy a rendszer nem ad hozzá animációt és nem távolítja el. Az animáció egyszerűen folytatódik, mintha mi sem történt volna.

A második példa: „animáció klónozása”

Az egyik működő megközelítés az animáció klónozása:

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

Itt van, hogyan működik:

  1. animation-name is none alapvetően.
  2. A felhasználó rákattint a „Pörgetés!” gombra, animation-name válik spin1. Az animáció spin1 elölről indul, mert most lett hozzáadva.
  3. A felhasználó rákattint a „Pörgetés újra!” gombra, animation-name válik spin2. Az animáció spin2 elölről indul, mert most lett hozzáadva.

Vegye figyelembe, hogy a 3. lépésben spin1 a CSS-szabályok sorrendje miatt eltávolítva. Nem fog működni, ha „Pörgessen újra!” először ellenőrzik.

A harmadik példa: „ugyanannak az animációnak a hozzáfűzése”

Egy másik működő megközelítés az „ugyanannak az animációnak a hozzáfűzése”:

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

Ez hasonló az előző példához. Valójában a következőképpen értheti meg a viselkedést:

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

Vegye figyelembe, hogy amikor a „Pörgessen újra!” be van jelölve, akkor a régi futó animáció lesz a második animáció az új listán, ami nem biztos, hogy intuitív. Ennek egyenes következménye: a trükk nem fog működni, ha animation-fill-mode is forwards. Íme egy demó:

Ha kíváncsi, miért van ez így, íme néhány támpont:

  • animation-fill-mode is none alapértelmezés szerint, ami azt jelenti, hogy „Az animációnak nincs hatása, ha nem játszik le”.
  • animation-fill-mode: forwards; azt jelenti, hogy „Miután az animáció lejátszása befejeződött, örökre az utolsó kulcskockánál kell maradnia”.
  • spin1döntése mindig felülírja spin2azért, mert spin1 később jelenik meg a listában.
  • Tegyük fel, hogy a felhasználó rákattint a „Pörgetés!” gombra, megvárja a teljes pörgetést, majd rákattint a „Pörgetés újra!” gombra. Ebben a pillanatban. spin1 már elkészült, és spin2 csak indul.

Megbeszélés

Ökölszabály: meglévő CSS-animációt nem lehet „újraindítani”. Ehelyett új animációt szeretne hozzáadni és lejátszani. Ezt megerősítheti a W3C spec:

Amint egy animáció elindult, addig folytatódik, amíg véget nem ér, vagy az animáció nevét el nem távolítják.

Az utolsó két példát összehasonlítva azt gondolom, hogy a gyakorlatban az „animációk klónozásának” gyakran jobban kell működnie, különösen, ha elérhető a CSS előfeldolgozó.

2. probléma: Lassítás

Azt gondolhatnánk, hogy az animáció lelassítása csak egy hosszabb beállítás kérdése animation-duration:

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

Valóban, ez működik:

… vagy mégis?

Néhány módosítással könnyebben átláthatja a problémát.

Igen, az animáció le van lassítva. És nem, nem néz ki jól. A kutya (majdnem) mindig „ugrik”, amikor átkapcsolja a jelölőnégyzetet. Továbbá úgy tűnik, hogy a kutya véletlenszerű pozícióba ugrik, nem pedig az eredeti pozícióba. Hogy-hogy?

Könnyebb lenne megérteni, ha bevezetnénk két „árnyékelemet”:

Mindkét árnyékelem ugyanazt az animációt futtatja, eltérően animation-duration. És nem érinti őket a jelölőnégyzet.

A jelölőnégyzet átkapcsolásával az elem azonnal átvált két árnyékelem állapota között.

idézve a W3C spec:

Az animáció tulajdonságainak értékeinek módosítása az animáció futása közben úgy érvényesül, mintha az animáció kezdete óta rendelkezne ezekkel az értékekkel.

Ez követi a hontalan design, amely lehetővé teszi a böngészők számára, hogy könnyen meghatározzák az animált értéket. A tényleges számítás leírása itt és a itt.

Újabb kísérlet

Az egyik ötlet az, hogy szüneteltesse az aktuális animációt, majd adjon hozzá egy lassabb animációt, amely átveszi onnan:

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

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

Tehát működik:

… vagy mégis?

Lelassul, ha rákattint a „Slowmo!” gombra. De ha kivársz egy teljes kört, akkor "ugrást" fogsz látni. Valójában mindig arra a pozícióra ugrik, amikor „Slowmo!” rá van kattintva.

Ennek az az oka, hogy nincs nálunk a from kulcskocka definiálva – és nem kellene. Amikor a felhasználó a „Slowmo!” gombra kattint, spin1 valamilyen helyen szünetel, és spin2 pontosan ugyanabban a pozícióban kezdődik. Egyszerűen nem tudjuk előre megjósolni ezt a helyzetet… vagy igen?

Működő Megoldás

Tudunk! Egy egyéni tulajdonság használatával rögzíthetjük a szöget az első animációban, majd átadhatjuk a második animációnak:

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);
  }
}

Jegyzet: @property ebben a példában használatos, ami az nem minden böngésző támogatja.

A "tökéletes" megoldás

Van egy figyelmeztetés az előző megoldáshoz: az „exiting slowmo” nem működik jól.

Itt van egy jobb megoldás:

Ebben a verzióban a lassított felvétel zökkenőmentesen be- vagy kiléphet. Nem használnak kísérleti funkciót sem. Szóval ez a tökéletes megoldás? Igen és nem.

Ez a megoldás úgy működik, mint a „fokozatok” „váltása”:

  • Fogaskerekek: kettő van <div>s. Az egyik a másik szülője. Mindkettőnek megvan a spin animáció, de más animation-duration. Az elem végső állapota mindkét animáció felhalmozódása.
  • Váltás: Az elején csak egy <div> fut az animációja. A másik szünetel. Ha a jelölőnégyzet be van kapcsolva, mindkét animáció felcseréli az állapotát.

Bár nagyon szeretem az eredményt, van egy probléma: ez egy szép kiaknázása a spin animáció, ami más típusú animációknál általában nem működik.

Praktikus megoldás (JS-vel)

Az általános animációknál a lassított funkció elérhető egy kis JavaScript segítségével:

Gyors magyarázat:

  • Egy egyéni tulajdonságot használunk az animáció előrehaladásának nyomon követésére.
  • Az animáció „újraindul”, ha a jelölőnégyzet be van kapcsolva.
  • A JS kód kiszámítja a helyes értéket animation-delay a zökkenőmentes átmenet biztosítása érdekében. ajánlom ezt a cikket ha nem ismeri a negatív értékeket animation-delay.

Ezt a megoldást az „újraindító animáció” és a „sebességváltó” megközelítés hibridjeként tekinthetjük.

Itt fontos az animáció előrehaladásának helyes nyomon követése. Megoldások lehetségesek, ha @property nem elérhető. Példaként ez a verzió használja z-index a fejlődés nyomon követéséhez:

Mellékes megjegyzés: eredetileg megpróbáltam létrehozni egy csak CSS-verziót is, de nem sikerült. Bár nem 100%-ig biztos, szerintem azért animation-delay is nem animálható.

Itt van egy verzió minimális JavaScripttel. Csak a „slowmo belépés” működik.

Kérem, jelezze, ha sikerül működőképes CSS-verziót létrehoznia!

Lassított bármilyen animáció (JS-vel)

Végezetül egy olyan megoldást szeretnék megosztani, ami (majdnem) minden animációnál működik, még ha több bonyolult is @keyframes:

Alapvetően hozzá kell adnia egy animációs folyamatkövetőt, majd gondosan ki kell számolnia animation-delay az új animációhoz. Néha azonban trükkös lehet (de lehetséges) a helyes értékek meghatározása.

Például:

  • animation-timing-function nem linear.
  • animation-direction nem normal.
  • több értéket tartalmaz animation-name különböző animation-durationés animation-delay„S.

Ezt a módszert is ismertetjük itt az Web Animations API.

Köszönetnyilvánítás

Ezen az úton indultam el, miután találkoztam a csak CSS-projektekkel. Valahol finom műalkotás, és néhányan az is voltak összetett konstrukciók. A kedvenceim a 3D objektumokat tartalmazók, például ez pattogó labda és ez a csomagoló kocka.

Kezdetben fogalmam sem volt, hogyan készülnek. Később sokat olvastam és tanultam belőle ez a szép oktatóanyag Ana Tudortól.

Mint kiderült, a 3D objektumok CSS-sel való építése és animálása nem sokban különbözik a CSS-sel való készítéstől keverőgép, csak egy kicsit más ízzel.

Következtetés

Ebben a cikkben megvizsgáltuk a CSS-animációk viselkedését, amikor egy animate-* ingatlan megváltozik. Különösen az „animáció újrajátszására” és az „animáció lassítására” dolgoztunk ki megoldásokat.

Remélem, érdekesnek találja ezt a cikket. Kérem ismertesse velem a gondolatait!

Időbélyeg:

Még több CSS trükkök