Animointi CSS:llä ja Javascriptilla
WWW-sivun sisällön animointiin on kolme eri tapaa: CSS-animaatiot, Javascript-animaatiot ja SVG-kuvilla toimivat SMIL-animaatiot.
Suositelluin ja yksinkertaisin ja usein myös tehokkain animointitapa on
käyttää CSS-animaatioita. SMIL-animaatioiden tuen jatkuminen on epävarmaa joten
niitä lienee paras välttää. Puhtaita Javascript-animaatioita kannattaa tehdä
vasta, kun muuta vaihtoehtoa ei ole. Yleensä animaation pohja kirjoitetaan
CSS:llä ja Javascriptilla muokataan tätä CSS-animaatiota dynaamisesti.
Puhtaasti vain Javascriptilla animoidaan lähinnä canvas
-elementin
sisältöjä.
CSS-animaatiot
Myös CSS-animaatiot ovat helppoja. Käytä CSS-animaatioita ennemmin kuin SMIL-animaatioita. Lue Using CSS animations.
CSS-animaatiot tehdään kahdessa vaiheessa. Ensin animoitavaan tyyliin määritellään animaation kesto, suunta etc.
- animation-delay
- animation-direction
- animation-duration
- animation-iteration-count
- animation-name määrää animaatiossa käytettävän @keyframes-tyylin nimen
- animation-play-state
- animation-timing-function määrää milla tavalla animointi suoritetaan. Voi käyttää valmiita vaihtoehtoja tai luoda itse omab bezier-käyrän
- animation-fill-mode
Näiden jälkeen määritellään varsinainen animaatio @keyframes-lohkossa.
Animaatioon voi lisätä väliaiheita:
@keyframes move {
/* mistä animoidaan */
from {
font-size: 1em;
color: black;
}
50% {
color: blue;
}
/* mihin animoidaan */
to {
font-size: 10em;
color: red;
}
}
Tekstin väriä animoidaan edellisessä eri rytmissä kuin kokoa.
Animaation saa jatkumaan ikuisesti, kun asettaa animation-iteration-countin arvoksi infinite. Animaation saa myös vaihtamaan suuntaa. SVG-animaatioissa suunnan vaihtaminen ei onnistu.
animation-iteration-count: infinite;
animation-direction: alternate;
Samaa animaatiota (keyframes) voi käyttää useammassa yhteydessä ja eri
rytmeissä, jos asettaa animointiin aloitusviiveen. Ilman aloitusviivettä
kaikki animaatiot alkavat samanaikaisesti. Aloitusviivettä voi hyödyntää
myös javascript-koodissa (elementti.style.animationDelay
)
transform
CSS-animaatioissa voit animoida lähes mitä tahansa CSS-ominaisuuksia. Elementtejä sijoiteltaessa näytölle on absoluuttinen asemointi helppo tapa sijoittaa elementti vapaasti mihin kohtaan tahansa näyttöä. Absoluuttista asemointia ei kuitenkaan kannata animoida vaan järkevämpää on käyttää transformointia, joka toimii nykyisillä näytönohjaimilla huomattavasti tehokkaammin. Absoluuttisella asemoinnilla voi kuitenkin määritellä elementin alkusijainnin. Toinen vaihtoehto on kiinnitetty (fixed) asemointi.
CSS-standardi tunnistaa mm. seuraavat transformaatiofunktiot:
Jos joudut huomioimaan animaatiossa animoitavan objektin kokoa niin käytä css-tiedostossa calc()-funktiota. Huomaa, että calc()-funktiolle annetussa laskukaavassa välilyönnit ovat merkityksellisiä. Jos liikutat animaatiolla bittikartta kts. A couple of Use Cases for Calc(). Myös attr()-funktiosta voi olla apua.
Lisätietoa
Javascript ja animaatiot
Yksinkertaisin tapa käynnistää animaatio javascriptilla on asettaa elementille
käyttöön animointia käyttävä tyyli (elementti.className = "tyyli";
):
Samaan tapaan animoinnin voi pysäyttää, kun vaihtaa tyylin nimeä.
Animaatioita voi kontrolloida ja seurata helposti javascriptilla.
-
Animaation etenemistä voidaan seurata tapahtumilla:
h1.addEventListener("animationstart", animlistener); h1.addEventListener("animationend", animlistener); h1.addEventListener("animationiteration", animlistener); function animlistener(e) { console.log( e.type + " : " + e.elapsedTime ); }
- Javascriptilla voi myös suoraan muokata elementin CSS-ominaisuuksia eivätkä animaatio-ominaisuudet ole poikkeus:
Näiden ominaisuuksien kautta ei kuitenkaan pääse käsiksi paraikaa käytössä oleviin tyylimäärityksiin. Esim. jos tyylissä on määritelty marginaaliksi 10% niin todellisuudessa se on jokin oikea pikselimäärä. Jos haluaa todellisen lasketun tyylin niin se on haettava seuraavasti:h1.style.animationDuration = "5s"; h1.style.animationIterationCount= "3";
let style = window.getComputedStyle(h1, null); for (let i of style) { console.log(i+" : "+style.getPropertyValue(i)); }
Web Animations API
Uusin ja ehkä paras tapa toteuttaa monimutkaisia animaatioita on käyttää Javascriptin Web Animations API -rajapintaa. Tutustu seuraaviin MDN-dokumentteihin:
// haetaan elementti, jonka animaatiota halutaan muuttaa
let h1 = document.getElementsByTagName("h1")[0];
// h1-elementin animaatiot ja otetaan niistä ensimmäinen
let anims = h1.getAnimations();
let anim = anims[0];
// haetaan animaation keyframet
let keyframes = anim.effect.getKeyframes();
// muutetaan ensimmäisen keyframen transform-arvoa
keyframes[0].transform = "translate(-50vw, 50vh)";
// asetetaan uudet keyframet
anim.effect.setKeyframes(keyframes);
Katso seuraava esimerkki ja suorita siihen liittyvä koodi, niin animaatio muuttuu:
Vanha tapa, jolla myös pääsee animaatioihin käsiksi
Animaation keyframeja päästään muokkaamaan seuraavalla tavalla, mutta käytä ennemmin Web Animations API -rajapintaa.
@keyframes-lohkoja voidaan muuttaa tai luoda javascriptilla. Tässä on hyvä käyttää seuraavaa apufunktiota, joka on lainattu ja hieman korjailtu Controlling CSS animations and Transitions with JavaScript-dokumentista:
function findKeyframesRule(rule) {
var ss = document.styleSheets;
for (var i = 0; i < ss.length; ++i) {
for (var j = 0; j < ss[i].cssRules.length; ++j) {
if (ss[i].cssRules[j].type == window.CSSRule.KEYFRAMES_RULE &&
ss[i].cssRules[j].name == rule) {
return ss[i].cssRules[j]; }
}
}
return null;
}
// haetaan keyframet
let keyframes = findKeyframesRule("slide") ;
console.log(keyframes);
// käydään läpi kaikki animaation liittyvät css-säännöt
for(let keyframe of keyframes.cssRules) {
// cssText on tässä vain readonly
console.log(keyframe.cssText);
// muuttamalla seuraavien keyText- ja style.cssText-ominaisuuksien sisältöä voi muuttaa animaatiota
// kts. CSSKeyFrameRule
console.log(keyframe.keyText);
console.log(keyframe.style.cssText);
}
requestAnimationFrame
Javascriptilla voi myös suoraan tuottaa animaatioita eli muutella haluttuja CSS- tai muita ominaisuuksia HTML- tai SVG-elementeistä. Yleensä kannattaa käyttää CSS-animaatioita jos suinkin mahdollista, koska selaimet on optimoitu näiden suhteen ja osaavat hyödyntää mm. näytönohjaimia. Jos teet puhdasta Javascript-animointia niin siinä on käytettävä requestAnimationFrame-metodia
requestAnimationFrame päivittää näyttöä samaan tahtiin kuin käytössä oleva näyttöä. Esim. jos näytön virkistystaajuus on 60 Hz niin requestAnimationFramen päivitystaajuus on 60 FPS. Jossain tilanteissa voi olla ongelma, että tiedossa ei ole tarkka päivitystaajuus. Lisätietoa: Controlling fps with requestAnimationFrame?
// kutsutaan requestAnimationFrame ja järjestelmä pitää huolen, että
// jossain vaiheessa kutsutaan parametrina tuotua js_animaatio-funktiota
// jos ikkuna tai tab on taustalla niin tätä ei välttämättä tapahdu
window.requestAnimationFrame(js_animaatio);
let paikka = 0;
// emme tiedä kuinka usein / nopeasti tätä funktiota kutsutaan. Jos ajoitus
// on tarkkaa niin voi käyttää apuna parametrina tulevaa timestampia
function js_animaatio(timestamp) {
// tämä kannattaisi hakea valmiiksi muistiin globaaliin muuttujaan
let anim = document.getElementById("animsvg");
// animoidaan koko objekti näytön yli muuttamalla left-ominaisuutta. animoitava
// objektin täytyy olla absoluuttisesti asemoitu
anim.style.left = paikka + "px";
paikka++;
if ( paikka > document.body.clientWidth ) paikka = 0;
// täytyy itse kutsua uudelleen jos halutaan jatkaa samaa
window.requestAnimationFrame(js_animaatio);
}
Jos halutaan varmistaa animaation käytetty aika, niin on itse laskettava paljonko pitää animoida ja milloin:
Monessa paikassa neuvottu vaihtoehto käyttää animointiin Javascriptin timereita on ehdottomasti huono idea. Timereille on omat käyttötapauksensa, mutta animaatiot eivät ole niitä. Timerit eivät pysähdy ikkunan joutuessa taustalle. setInterval()-metodilla voisi ehkä käynnistää animaatioita, mutta muuhun animointitoimintaan se on hyvin epätehokas verrattuna requestAnimationFrameen.
Lisätietoa
- Animating with javascript: from setInterval to requestAnimationFrame
- Why is requestAnimationFrame better than setInterval or setTimeout
- css-animations
- JS-animation
- CSS animation
- Bezier-curve
- CSS versus Javascript animations
- Web animations
- CSS GPU Animation: Doing It Right
- The whole web at maximum FPS: How WebRender gets rid of jank
- An Introduction and Guide to the CSS Object Model (CSSOM)
- Animate Anything Along an SVG Path
Käyttäjien kommentit