Webanimaties - element.animate() is nu beschikbaar in Chrome 36

Brendan Kenny
Brendan Kenny

Animatie op internet was ooit de provincie van JavaScript, maar toen de wereld overging op mobiel, verhuisden animaties naar CSS vanwege de declaratieve syntaxis en de optimalisaties die browsers ermee konden doorvoeren. Omdat 60 fps op mobiel altijd uw doel is, is het logisch om nooit buiten de grenzen te treden van wat browsers efficiënt kunnen weergeven.

Er verschijnen steeds meer tools om JavaScript-gestuurde animaties efficiënter te maken, maar de heilige graal is een unificatie van declaratieve en imperatieve animaties , waarbij de beslissing over hoe je animaties schrijft gebaseerd is op wat de duidelijkste code is, en niet op wat mogelijk is in één vorm. en niet in de andere.

Webanimaties kunnen die oproep beantwoorden, en het eerste deel ervan is in Chrome 36 beland in de vorm van element.animate() . Met deze nieuwe functie kunt u een animatie puur in JavaScript maken en deze net zo efficiënt laten draaien als elke CSS-animatie of -overgang (in feite stuurt vanaf Chrome 34 exact dezelfde Web Animations-engine al deze methoden aan ).

De syntaxis is eenvoudig en de onderdelen ervan zouden je bekend moeten voorkomen als je ooit een CSS-overgang of animatie hebt geschreven:

element.animate([
    {cssProperty: value0},
    {cssProperty: value1},
    {cssProperty: value2},
    //...
], {
    duration: timeInMs,
    iterations: iterationCount,
    delay: delayValue
});

Het grootste voordeel van deze nieuwe functie is het elimineren van een heleboel lastige hoepels waar we vroeger doorheen moesten springen om een ​​vloeiende, stootvrije animatie te krijgen.

Voor Santa Tracker vorig jaar wilden we bijvoorbeeld continu sneeuw laten vallen, en we besloten het via CSS te animeren, zodat het zo efficiënt kon worden gedaan .

We wilden echter de horizontale positie van de sneeuw dynamisch bepalen op basis van het scherm en de gebeurtenissen die plaatsvinden in de scène zelf, en natuurlijk zou de hoogte van de sneeuwval (de hoogte van het browservenster van de gebruiker) pas bekend zijn als we daadwerkelijk wisten rennen. Dit betekende dat we echt CSS-overgangen moesten gebruiken, omdat het schrijven van een CSS-animatie tijdens runtime snel complex wordt (en honderden sneeuwvlokken betekent honderden nieuwe stijlregels).

Daarom hebben we de volgende aanpak gevolgd, die bekend zou moeten zijn:

snowFlake.style.transform = 'translate(' + snowLeft + 'px, -100%)';
// wait a frame
snowFlake.offsetWidth;
snowFlake.style.transitionProperty = 'transform';
snowFlake.style.transitionDuration = '1500ms';
snowFlake.style.transform = 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)';

De sleutel zit in die 'wacht een frame'-opmerking. Om een ​​transitie succesvol te kunnen starten, moet de browser bevestigen dat het element zich in de startpositie bevindt. Er zijn een paar manieren om dit te doen. Een van de meest gebruikelijke manieren is het lezen van een van de elementeigenschappen die de browser dwingt de lay-out te berekenen, waardoor de browser weet dat het element een startpositie heeft voordat hij naar de eindpositie overgaat. Door deze methode te gebruiken, kunt u uzelf feliciteren met uw superieure kennis van de interne browserfuncties, terwijl u zich nog steeds vies voelt bij elke toetsaanslag.

Daarentegen kan de equivalente aanroep element.animate() niet duidelijker zijn en precies zeggen wat de bedoeling is:

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);

Er zijn nog veel meer opties. Net als bij zijn CSS-tegenhangers kunnen webanimaties worden uitgesteld en herhaald:

snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], {
    duration: 1500,
    iterations: 10,
    delay: 300
});

Animatiespeler

element.animate() retourneert feitelijk een AnimationPlayer-object, dat steeds belangrijker zal worden naarmate meer van de Web Animations-specificaties worden gelanceerd. Zowel in JavaScript als in CSS gemaakte animaties hebben bijbehorende AnimationPlayers, waardoor ze naadloos op nuttige en interessante manieren kunnen worden gecombineerd.

Voorlopig heeft AnimationPlayer echter slechts twee functionaliteiten, beide erg handig. Je kunt een animatie op elk moment annuleren met AnimationPlayer.cancel() :

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
// less than 1500ms later...changed my mind
player.cancel();

En tot grote opluchting van iedereen die in het verleden heeft geprobeerd een animatiesysteem rond CSS-animaties of -overgangen te bouwen, activeren webanimaties altijd een gebeurtenis wanneer ze klaar zijn:

var player = snowFlake.animate([
    {transform: 'translate(' + snowLeft + 'px, -100%)'},
    {transform: 'translate(' + snowLeft + 'px, ' + window.innerHeight + 'px)'}
], 1500);
player.onfinish = function(e) {
    console.log('per aspera ad terra!');
}

Probeer het

Dit wordt allemaal verzonden in Chrome 36 en gaat vandaag over naar de bètaversie! Als je het wilt proberen, probeer dan met de native implementatie in Chrome 36 te werken. Er is echter een Web Animations polyfill , die een aanzienlijk groter deel van de volledige Web Animations-specificatie naar alle moderne, groenblijvende browsers brengt.

Er is een demo van het sneeuweffect beschikbaar die u kunt uitproberen met zowel de oorspronkelijke versie van element.animate() als de polyfill .

Laat ons weten wat je denkt

Maar dit is eigenlijk een voorproefje van wat gaat komen en wordt speciaal uitgebracht om meteen feedback van ontwikkelaars te krijgen. We weten nog niet zeker of we alle gebruiksscenario's hebben bereikt, of alle ruwe randjes van de huidige API's voor animatie hebben geschuurd. De enige manier waarop we dit kunnen weten en echt goed kunnen doen, is door ontwikkelaars het uit te laten proberen en ons te laten weten wat ze ervan vinden.

Commentaar op dit bericht is uiteraard waardevol, en commentaar op de standaard zelf kan worden gericht aan de CSS- en SVG-werkgroepen via de public-fx mailinglijst .

Update, oktober 2014 : Chrome 39 voegt ondersteuning toe voor verschillende aanvullende methoden met betrekking tot het regelen van het afspelen, zoals play() , pause() en reverse() . Het ondersteunt ook het springen naar een specifiek punt in de tijdlijn van een animatie via de eigenschap currentTime . U kunt deze functionaliteit in actie zien in deze nieuwe demo .

Met dank aan Addy Osmani en Max Heinritz voor hun hulp bij dit bericht.