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.

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.

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:

rAf

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

Käyttäjien kommentit

Kommentoi Lisää kommentti
Informaatioteknologia - Jyväskylän yliopiston informaatioteknologian tiedekunta