Vain CSS-käyttöinen Wolfenstein on pieni projekti, jonka tein muutama viikko sitten. Se oli kokeilu CSS 3D -muunnoksilla ja -animaatioilla.
Innoittamana FPS demo ja toinen Wolfenstein CodePen, päätin rakentaa oman versioni. Se perustuu löyhästi alkuperäisen Wolfenstein 1D -pelin jaksoon 9 – Floor 3.
Editor: Tämä peli vaatii tarkoituksella nopeaa reagointia Game Over -näytön välttämiseksi.
Tässä läpikäyntivideo:
Lyhyesti sanottuna projektini on vain huolellisesti käsikirjoitettu pitkä CSS-animaatio. Lisäksi muutama tapaus valintaruudun hakkerointi.
:checked ~ div { animation-name: spin; }
Ympäristö koostuu 3D-ruudukosta ja animaatiot ovat enimmäkseen tavallisia 3D-käännöksiä ja rotaatioita. Ei mitään todella hienoa.
Kaksi ongelmaa oli kuitenkin erityisen hankala ratkaista:
- Toista "aselaukaisu"-animaatio aina, kun pelaaja napsauttaa vihollista.
- Kun nopeasti liikkuva pomo sai viimeisen osuman, siirry dramaattiseen hidastukseen.
Teknisellä tasolla tämä tarkoitti seuraavaa:
- Toista animaatio uudelleen, kun seuraava valintaruutu on valittuna.
- Hidasta animaatiota, kun valintaruutu on valittuna.
Itse asiassa kumpaakaan ei projektissani ratkaistu kunnolla! Joko päädyin käyttämään kiertotapoja tai vain luovutin.
Toisaalta pienen kaivamisen jälkeen löysin lopulta avaimen molempiin ongelmiin: CSS-animaatioiden ominaisuuksien muuttamisen. Tässä artikkelissa tutkimme aihetta lisää:
- Paljon interaktiivisia esimerkkejä.
- Dissektiot: miten kukin esimerkki toimii (tai ei toimi)?
- Kulissien takana: miten selaimet käsittelevät animaatiotiloja?
Anna minun "heittä tiiliäni".
Ongelma 1: Toistan animaatiota
Ensimmäinen esimerkki: "vain toinen valintaruutu"
Ensimmäinen intuitioni oli "lisää vain toinen valintaruutu", joka ei toimi:
Jokainen valintaruutu toimii erikseen, mutta ei molempia yhdessä. Jos yksi valintaruutu on jo valittuna, toinen ei enää toimi.
Näin se toimii (tai "ei toimi"):
- -
animation-name
of<div>
isnone
oletuksena. - Käyttäjä napsauttaa yhtä valintaruutua,
animation-name
tuleespin
, ja animaatio alkaa alusta. - Hetken kuluttua käyttäjä klikkaa toista valintaruutua. Uusi CSS-sääntö astuu voimaan, mutta
animation-name
is yhäspin
, mikä tarkoittaa, että animaatiota ei lisätä eikä poisteta. Animaatio vain jatkaa toistoa kuin mitään ei olisi tapahtunut.
Toinen esimerkki: "animaation kloonaaminen"
Yksi toimiva lähestymistapa on kloonata animaatio:
#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2; }
Näin se toimii:
animation-name
isnone
aluksi.- Käyttäjä napsauttaa "Pyörä!",
animation-name
tuleespin1
. Animaatiospin1
aloitetaan alusta, koska se on juuri lisätty. - Käyttäjä napsauttaa "Pyörä uudelleen!",
animation-name
tuleespin2
. Animaatiospin2
aloitetaan alusta, koska se on juuri lisätty.
Huomaa, että vaiheessa 3, spin1
poistetaan CSS-sääntöjen järjestyksen vuoksi. Se ei toimi, jos "Pyörä uudelleen!" tarkistetaan ensin.
Kolmas esimerkki: "lisätään sama animaatio"
Toinen toimiva lähestymistapa on "liitä sama animaatio":
#spin1:checked ~ div { animation-name: spin; }
#spin2:checked ~ div { animation-name: spin, spin; }
Tämä on samanlainen kuin edellinen esimerkki. Voit itse asiassa ymmärtää käyttäytymisen näin:
#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2, spin1; }
Huomaa, että kun "Pyörä uudelleen!" on valittuna, vanhasta käynnissä olevasta animaatiosta tulee toinen animaatio uudessa luettelossa, mikä voi olla epäintuitiivinen. Suora seuraus on: temppu ei toimi, jos animation-fill-mode
is forwards
. Tässä on demo:
Jos ihmettelet, miksi näin on, tässä on joitain vihjeitä:
animation-fill-mode
isnone
oletuksena, mikä tarkoittaa "Animaatiolla ei ole vaikutusta ollenkaan, jos sitä ei toisteta".animation-fill-mode: forwards;
tarkoittaa "Kun animaatio on toistettu, sen on pysyttävä viimeisessä avainkehyksessä ikuisesti".spin1
Päätös kumoaa ainaspin2
koskaspin1
näkyy myöhemmin luettelossa.- Oletetaan, että käyttäjä napsauttaa "Pyörä!", odottaa täyttä pyöräytystä ja sitten napsauttaa "Pyörä uudelleen!". Tällä hetkellä.
spin1
on jo valmis, jaspin2
vasta alkaa.
Keskustelu
Nyrkkisääntö: olemassa olevaa CSS-animaatiota ei voi "käynnistää uudelleen". Sen sijaan haluat lisätä ja toistaa uuden animaation. Tämän voi vahvistaa W3C spec:
Kun animaatio on alkanut, se jatkuu, kunnes se päättyy tai animaation nimi poistetaan.
Nyt kun verrataan kahta viimeistä esimerkkiä, mielestäni käytännössä "kloonausanimaatioiden" pitäisi usein toimia paremmin, varsinkin kun CSS-esiprosessori on saatavilla.
Ongelma 2: Hidastus
Voidaan ajatella, että animaation hidastaminen on vain pidemmän pituuden asettaminen animation-duration
:
div { animation-duration: 0.5s; }
#slowmo:checked ~ div { animation-duration: 1.5s; }
Todellakin, tämä toimii:
… vai onko?
Muutamalla säädöllä ongelman pitäisi olla helpompi nähdä.
Kyllä, animaatio on hidastettu. Ja ei, se ei näytä hyvältä. Koira (melkein) "hyppää" kun vaihdat valintaruutua. Lisäksi koira näyttää hyppäävän satunnaiseen asentoon alkuperäisen aseman sijaan. Kuinka niin?
Se olisi helpompi ymmärtää, jos ottaisimme käyttöön kaksi "varjoelementtiä":
Molemmat varjoelementit käyttävät samoja animaatioita eri tavoin animation-duration
. Eikä valintaruutu vaikuta niihin.
Kun vaihdat valintaruutua, elementti vaihtaa välittömästi kahden varjoelementin tilojen välillä.
Lainaaminen W3C spec:
Animaatio-ominaisuuksien arvojen muutokset animaation ollessa käynnissä ovat ikään kuin animaatiolla olisi kyseiset arvot sen alkaessa.
Tämä on seurausta kansalaisuudeton suunnittelu, jonka avulla selaimet voivat helposti määrittää animoidun arvon. Varsinainen laskenta on kuvattu tätä ja tätä.
Toinen yritys
Yksi idea on keskeyttää nykyinen animaatio ja lisätä sitten hitaampi animaatio, joka ottaa vallan sieltä:
div {
animation-name: spin1;
animation-duration: 2s;
}
#slowmo:checked ~ div {
animation-name: spin1, spin2;
animation-duration: 2s, 5s;
animation-play-state: paused, running;
}
Joten se toimii:
… vai onko?
Se hidastuu, kun napsautat "Slowmo!". Mutta jos odotat täyttä ympyrää, näet "hypyn". Itse asiassa se hyppää aina asentoon, kun "Slowmo!" napsautetaan.
Syynä on, että meillä ei ole a from
avainkehys määritelty – eikä meidän pitäisi. Kun käyttäjä napsauttaa "Slowmo!", spin1
on pysähtynyt jossain kohdassa, ja spin2
alkaa täsmälleen samasta paikasta. Emme yksinkertaisesti voi ennustaa sitä asemaa etukäteen… vai voimmeko?
Toimiva Ratkaisu
Me voimme! Käyttämällä mukautettua ominaisuutta voimme kaapata kulman ensimmäisessä animaatiossa ja siirtää sen sitten toiseen animaatioon:
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);
}
}
Huomautus: @property
käytetään tässä esimerkissä, joka on kaikki selaimet eivät tue.
"Täydellinen" ratkaisu
Edellisessä ratkaisussa on varoitus: "slowmosta poistuminen" ei toimi hyvin.
Tässä parempi ratkaisu:
Tässä versiossa hidastettua kuvaa voidaan syöttää tai siitä poistua saumattomasti. Myöskään kokeellista ominaisuutta ei käytetä. Onko se siis täydellinen ratkaisu? Kyllä ja ei.
Tämä ratkaisu toimii kuten "vaihteiden vaihtaminen":
- Vaihteet: niitä on kaksi
<div>
s. Toinen on toisen vanhempi. Molemmilla onspin
animaatio, mutta erilainenanimation-duration
. Elementin lopullinen tila on molempien animaatioiden kertymä. - Vaihto: Alussa vain yksi
<div>
animaatio on käynnissä. Toinen on tauolla. Kun valintaruutu on päällä, molemmat animaatiot vaihtavat tilojaan.
Vaikka pidän todella tuloksesta, siinä on yksi ongelma: se on mukava hyödyntää spin
animaatio, joka ei yleensä toimi muun tyyppisissä animaatioissa.
Käytännöllinen ratkaisu (JS:n kanssa)
Yleisissä animaatioissa on mahdollista saada hidastettu toiminto pienellä JavaScriptillä:
Nopea selitys:
- Mukautettua ominaisuutta käytetään animaation edistymisen seuraamiseen.
- Animaatio "käynnistetään uudelleen", kun valintaruutua vaihdetaan.
- JS-koodi laskee oikean
animation-delay
varmistaaksesi saumattoman siirtymän. minä suosittelen Tämä artikkeli jos et tunne negatiivisia arvojaanimation-delay
.
Voit nähdä tämän ratkaisun "uudelleenkäynnistyksen animaation" ja "vaihteenvaihdon" yhdistelmänä.
Tässä on tärkeää seurata animaation edistymistä oikein. Ratkaisut ovat mahdollisia, jos @property
ei ole saatavilla. Esimerkkinä tämä versio käyttää z-index
edistymisen seuraamiseksi:
Sivuhuomautus: alun perin yritin myös luoda vain CSS-versiota, mutta en onnistunut. Vaikka en ole 100% varma, luulen sen johtuvan siitä animation-delay
is ei animoitavissa.
Tässä on versio minimaalisella JavaScriptillä. Vain "syöttäminen hitaasti" toimii.
Kerro minulle, jos onnistut luomaan toimivan CSS-version!
Hidastettu mikä tahansa animaatio (JS:n kanssa)
Lopuksi haluaisin jakaa ratkaisun, joka toimii (melkein) missä tahansa animaatiossa, jopa monimutkaisissakin animaatioissa @keyframes
:
Periaatteessa sinun on lisättävä animaation edistymisen seuranta ja laskettava sitten huolellisesti animation-delay
uutta animaatiota varten. Joskus voi kuitenkin olla hankalaa (mutta mahdollista) saada oikeat arvot.
Esimerkiksi:
animation-timing-function
ei olelinear
.animation-direction
ei olenormal
.- useita arvoja sisään
animation-name
erianimation-duration
jaanimation-delay
N.
Tämä menetelmä on myös kuvattu tätä varten Web Animations API.
Kiitokset
Aloitin tällä polulla, kun törmäsin vain CSS-projekteihin. Jotkut olivat herkkä taideteos, ja jotkut olivatkin monimutkaiset keinot. Suosikkini ovat ne, joissa on 3D-objekteja, esimerkiksi tämä pomppiva pallo ja tämä pakkauskuutio.
Alussa minulla ei ollut aavistustakaan, miten nämä tehtiin. Myöhemmin luin ja opin paljon tämä mukava opetusohjelma Ana Tudorilta.
Kuten kävi ilmi, 3D-objektien rakentaminen ja animointi CSS:llä ei eroa paljonkaan sen tekemisestä tehosekoitin, vain hieman erilaisella maulla.
Yhteenveto
Tässä artikkelissa tarkastelimme CSS-animaatioiden käyttäytymistä, kun an animate-*
omaisuutta muutetaan. Erityisesti kehitimme ratkaisuja "animaation toistamiseen" ja "animaatiohidastukseen".
Toivottavasti tämä artikkeli on kiinnostava. Kerro mielipiteesi!