Introduction aux animations CSS3

Les applications HTML5 d’aujourd’hui peuvent désormais fournir des expériences inédites grâces aux nouvelles spécifications CSS3. L’une d’entre elles est nommée CSS3 Animations. Elle vous permet de créer des animations évoluées sur des éléments HTML. Cela ouvre d’intéressantes perspectives afin de fournir des retours pertinents à l’utilisateur et construire des applications rapides & fluides. De plus, comme ces nouvelles animations sont la plupart du temps accélérées matériellement par le GPU, elles permettent de monter la qualité de la nouvelle génération d’applications HTML5 vers de nouveaux sommets.

Si l’on traduit une partie des spécifications “CSS Animation Module Level 3” du site officiel du W3C, on découvre que ces spécifications CSS3 introduisent des animations définies, indiquant les propriétés CSS qui évolueront selon un intervalle de temps donné. Cette spécification est une extension du module CSS Transitions.

Comme CSS3 Animations est une extension des CSS3 Transitions, je vous invite à lire dans un 1er temps l’article dédié à ce sujet de mon collègue David Catuhe: Introduction aux transitions CSS3.

A travers cet article, nous allons découvrir une démo intéressante mettant en avant le potentiel des animations CSS3, comment construire des animations simples et finalement comment gérer un éventuel mode dégradé via JavaScript:

  1. CSS3 Animations
  2. Support dans les navigateurs
  3. Librairie JavaScript pour simuler les animations CSS3
  4. Conclusion

Commençons tout d’abord par rapidement découvrir ce que sont les animations CSS3. Voici un exemple d’animation d’un TB-TT (ou AT-AT en anglais) issu de l’univers de StarWars et utilisant CSS3 Animations pour animer les différentes parties du transport. Si votre navigateur ne supporte pas les spécifications CSS3 animations, une librairie JavaScript sera chargée pour simuler son action:

Vous pouvez également tester cet exemple dans une fenêtre séparée ici : https://david.blob.core.windows.net/html5/css3atat/index.htm

Note : cet exemple a été testé avec succès sous IE10/IE10 Mobile (Windows Phone 8), Chrome, Firefox 16+, Opera 12 et iPad 2 pour le support natif des animations. La librairie de “fallback” fonctionne très bien sous IE9 classique et mobile (Windows Phone 7.5). Cet article a été mis à jour le 14/12/2012 pour retirer les préfixes –ms et –moz puisque IE10+, Firefox 16+ & Opera 12.1 supportent désormais les versions non-préfixées de transitions, animations et transforms! D’ailleurs, la liste des spécifications non-préfixées pour IE10 se trouvent ici: Moving the Stable Web Forward in IE10. Chrome 25 devraient également retirer les préfixes.

Cet exemple est basé sur le super boulot réalisé par Anthony Calzadilla. Vous pouvez découvrir d’autres superbes démos mettant en œuvre CSS3 Animations sur son site ici : https://www.anthonycalzadilla.com . J’apprécie particulièrement son exemple I twitty the fool utilisant SVG & CSS3 Animation combinés. Clignement d'œil

CSS3 Animations

Introduction

Commençons par analyser sur quelles parties vous pouvez jouer pour fabriquer des animations. CSS3 Animations travaille tout simplement sur les mêmes valeurs que CSS3 Transitions.

Les voici: cliquez ici pour les afficher/cacher

  • couleur : interpolée via ses composantes rouge, verte, bleue et alpha (qui sont considérées comme des nombres)
  • longueur : interpolée comme un nombre
  • pourcentage : interpolée comme un nombre
  • entier :interpolé de manière discrète (en fait l’interpolation se fait sur une version décimale qui est ensuite tronquée vers un entier en utilisant floor())
  • nombre: interpolé directement comme un réel
  • liste de transformation : voir la spécification des CSS3 2D Transforms (https://www.w3.org/TR/css3-2d-transforms)
  • rectangle: interpolé via ses composantes x, y, largeur, hauteur
  • visibilité: interpolé de manière discrète (en fait l’interpolation est effectuée sur un nombre réel allant de 0 à 1 ou 0 vaut caché et 1 vaut visible)
  • ombre: interpolé via ses composantes de couleur, x, y et flou
  • gradient: interpolé au travers de la position et la couleur de chacune des étapes. La valeur d’origine et la valeur de destination de la transitions doivent par contre avoir le même type (linéaire ou radial) et le même nombre d’étapes
  • paint server (SVG): l’interpolation est uniquement supporté de gradient ver gradient ou de couleur vers couleur
  • liste séparée par des espaces d’un type ci-dessus : si les listes d’origine et de destination de la transition ont le même nombre d’éléments, les règles ci-dessus s’applique et l’interpolation a bien lieu. Dans le cas contraire, l’interpolation n’est pas jouée
  • propriété synthétique (shorthand property) :si toutes les parties de la synthèse peuvent être animées alors l’interpolation a lieu comme si chaque propriété avait été spécifiée individuellement

Et les propriétés suivantes doivent être supportées pour les animations: cliquez ici pour les afficher/cacher

  • background-color (couleur)
  • background-image (que les gradients)
  • background-position (pourcentage et longueur)
  • border-bottom-color (couleur)
  • border-bottom-width (longueur)
  • border-color (couleur)
  • border-left-color (couleur)
  • border-left-width (longueur)
  • border-right-color (couleur)
  • border-right-width (longueur)
  • border-spacing (longueur)
  • border-top-color (couleur)
  • border-top-width (longueur)
  • border-width (longueur)
  • bottom (longueur et pourcentage)
  • color (couleur)
  • crop (rectangle)
  • font-size (longueur et pourcentage)
  • font-weight (nombre)
  • grid-* (divers)
  • height (longueur et pourcentage)
  • left (longueur et pourcentage)
  • letter-spacing (longueur)
  • line-height (nombre, longueur et pourcentage)
  • margin-bottom (longueur)
  • margin-left (longueur)
  • margin-right (longueur)
  • margin-top (longueur)
  • max-height (longueur et pourcentage)
  • max-width (longueur et pourcentage)
  • min-height (longueur et pourcentage)
  • min-width (longueur et pourcentage)
  • opacity (nombre)
  • outline-color (couleur)
  • outline-offset (entier)
  • outline-width (longueur)
  • padding-bottom (longueur)
  • padding-left (longueur)
  • padding-right (longueur)
  • padding-top (longueur)
  • right (longueur et pourcentage)
  • text-indent (longueur et pourcentage)
  • text-shadow (ombre)
  • top (longueur et pourcentage)
  • vertical-align (keywords, longueur et pourcentage)
  • visibility (visibilité)
  • width (longueur et pourcentage)
  • word-spacing (longueur et pourcentage)
  • z-index (entier)
  • zoom (nombre)

SVG

Les propriétés des objets SVG sont animables lorsque qu’elles sont définies comme animatable:true dans les spécifications SVG : https://www.w3.org/TR/SVG/struct.html. Cependant, à l’heure où j’ai écrit cet article, je n’ai pas réussi à combiner avec succès des animations CSS3 directement sur des éléments SVG dans aucune des dernières versions des navigateurs.  Les exemples que vous pourrez trouver utilisent alors une petite astuce: il embarque les ressources SVG dans différents DIV eux-mêmes animés via CSS3 comme l’exemple I twitty the fool d’Anthony.

Déclarations

Pour déclarer une animation dans un fichier CSS, voici le type de code générique que vous aurez à taper:

 @keyframes nom_de_l_animation {
  from {
   propriété_à_animer: valeur_initiale;
  }
  50% {
     propriété_à_animer: valeur_intermédiaire;
  }
  to {
    propriété_à_animer: valeur_finale;
  }
}

qui pourrait également s’écrire ainsi :

 @keyframes nom_de_l_animation {
    0% {
        propriété_à_animer: valeur_initiale;
    }
    50% {
        propriété_à_animer: valeur_intermédiaire;
    }
    100% {
        propriété_à_animer: valeur_finale;
    }
}

Cette animation définit 3 étapes 0, 50 & 100%. Pour construire une animation valide, vous devez au moins avoir un from (ou 0%) et un to (ou 100%) soit 2 étapes minimum. Après cela, vous pouvez ajouter autant d’étapes (ou keyframes) que vous le souhaitez entre 0 et 100% pour contrôler de manière fine les différentes phases de votre animation.

Une fois la définition faite, vous pouvez l’affecter à un élément en utilisant les sélecteurs CSS3 classiques et il ne vous restera plus qu’à configurer les options de l’animation. Pour cela, voici le type de bloc qu’il faut utiliser:

 #id_de_l_element_html {
    animation-name: nom_de_l_animation;
    animation-duration: nombre_de_secondes s;
    animation-iteration-count: nombre | infinite;
}

Pour mieux comprendre, observons un exemple réel. Regardons comme la tête de notre TB-TT est animée.

Voici la déclaration de l’animation:

 @keyframes rotate-skull {
    0% {
        transform: rotate(0deg)
    }
    25% {
        transform: rotate(15deg)
    }
    50% {
        transform: rotate(-5deg)
    }
    55% {
        transform: rotate(0deg)
    }
    75% {
        transform: rotate(-10deg)
    }
    100% {
        transform: rotate(0deg)
    }
} 

Nous avons définit 6 étapes (0, 25, 50, 55, 75 & 100%) qui vont agir sur la propriétés CSS3 2D Transform en jouant sur la valeur de la rotation.

Cette animation est alors appliquée via cette règle CSS:

 #skull 
{
    animation-name: rotate-skull;
    animation-duration: 7s;
    animation-iteration-count: infinite;       
}

On vise l’élément <div> ayant pour “id=skull” et nous lui appliquons l’animation nommée “rotate-skull” dessus. L’animation devra être terminée en 7s et devra être jouée un nombre infini de fois.

Note : vous devez copier/coller ces blocs afin d’utiliser –webkit-keyframes/-webkit-transform/–webkit-animation pour faire fonctionner ce code dans Chrome/Safari puisqu’ils ne supportent pas encore les versions finales non préfixées des spécifications associés.

Voici le résultat animé si votre navigateur supporte CSS3 Animations :

Nous aurions très bien pu d’ailleurs écrire cette règle de manière raccourcie ainsi :

 #skull {
    animation: rotate-skull 7s infinite;
}

L’animation sera lancée dès qu’une règle qui correspond sera appliquée. Vous pouvez donc jouer ou stopper une animation simplement par JavaScript ou via CSS3 en travaillant sur les classes affectées à un tag.

Animations non linéaires

La propriété “animation-timing-function” doit être utilisée si vous souhaitez mettre en place des animations non linéaires. Vous pouvez même mixer plusieurs types d’animations entre chaque keyframe si vous le souhaitez.

CSS3 animations va utiliser une courbe de Bézier cubique pour “fluidifier” la transition en calculant une vitesse de progression différente tout au long de sa durée.

Les valeurs suivantes sont supportées:

  • linear: Vitesse constante (comportement par défaut)
  • cubic-bezier: La vitesse sera calculée grâce à une courbe de Bézier cubique définie par deux points de contrôles : P0 et P1 (Il faudra donc fournir 4 paramètres : P0x, P0y, P1x et P1y).
  • ease: La vitesse sera calculée avec la formule suivante : cubic-bezier(0.25, 0.1, 0.25, 1)
  • ease-in: La vitesse sera calculée avec la formule suivante : cubic-bezier(0.42, 0, 1, 1)
  • ease-inout: La vitesse sera calculée avec la formule suivante : cubic-bezier(0.42, 0, 0.58, 1)
  • ease-out: La vitesse sera calculée avec la formule suivante : cubic-bezier(0, 0, 0.58, 1)

Voici un outil de simulation écrit par David Catuhe qui utilise du JavaScript 100% pur jus pour démontrer l’impact de chacune des fonctions non linéaires:

Note : cet outil utilise du SVG “in-line” supporté par Firefox, Chrome, Opera 11.60+ & IE9/10. Il ne fonctionnera donc pas correctement sous Opera 11.50 et sous Safari sur iPad.

Ce super outil utilise donc SVG. Vous pouvez alors même jouer avec votre souris à éditer la courbe de la fonction “custom”. Si vous souhaitez en savoir davantage sur cet outil, rendez-vous à nouveau sur l’article de David Catuhe sur les transitions.

Si votre navigateur supporte les animations CSS3, regardons maintenant une démo toute simple utilisant les fonctions non linéaires pour bouger un élément <canvas> via CSS3 contenant un sprite animé.

Voici le bloc de CSS3 Animations qui sera utilisé dans cette démo:

 @-ms-keyframes demo {
    from {
      animation-timing-function: ease;
      transform: translateX(0px);
    }
    50% {
      animation-timing-function: ease-in;
      transform: translateX(300px);
    }
    to {
      animation-timing-function: ease-inout;
      transform: translateX(900px);
    }
}

#testCanvas
{
    animation-delay: 0s;
    animation-duration: 6s;
    animation-iteration-count: infinite;
    animation-name: demo;
}

Ainsi que toutes les variations de préfixes pour pouvoir fonctionner sous Google Chrome & Opera. Voici le résultat en image:

Si votre navigateur ne supporte pas CSS3 Animation mais uniquement canvas, l’animation du sprite en train de courir devrait être relativement statique car le personnage ne bougera pas sur toute la largeur de l’écran.

Note : si vous souhaitez en savoir davantage sur <canvas> et l’animation de sprites, je vous invite à lire cet article : Jeux HTML5: animation de sprites dans l’élément Canvas grâce à EaselJS

Délais

Ta propriété “animation-delay” permet tout simplement de lancer l’animation un peu plus tard que prévu. Rien de bien sorcier.

Evènements

3 évènements peuvent être levés pendant une animation. Ils sont nommés “animationstart”, “animationend” et “animationiteration”. En fonction du navigateur, le nom correctement préfixé sera alors:

  • IE10+, Firefox 16+ & Opera 12.1+: animationend
  • Chrome: webkitAnimationEnd

Ces évènements vous donneront les détails suivants:

  • animationName: nom de l’animation ayant levée l’évènement
  • elapsedTime: le temps écoulé depuis le début de l’animation, en secondes

En voici un exemple d’usage pour IE10, Firefox & Opera supportant tous les 3 la version définitive:

 elementToAnimate.addEventListener("animationend", function () {
    alert("the end !");
}, false);

D’autres choses à propos des animations CSS3

Les animations CSS3 sont vraiment utiles pour 2 raisons principales :

  • L’accélération matérielle: les animations CSS3 sont la plupart du temps gérées directement par le GPU et peuvent donc produire des résultats plus fluides. Cela peut donc être particulièrement intéressant pour les scénarios visant les périphériques mobiles.
  • Meilleure séparation entre le code et le design: je sais qu’il existe de nombreux débats à ce sujet mais avec David, nous avons tendance à penser qu’un développeur ne devrait pas s’occuper des animations ou de toute autre chose ayant rapport au design autant que possible. De la même manière, un designer/graphiste ne devrait pas s’occuper de JavaScript. CSS3 offre donc cette possibilité et peut permettre aux designers/intégrateurs de travailler avec leurs outils classiques pour générer les animations sur les bons éléments, les changements entre écrans, etc.

Pour illustrer l’importance des performances, sachez que le jeu HTML5 suivant HTML5 Platformer que j’ai écrit et utilisant une balise <canvas> en plein écran tourne à 60 fps sous IE9/IE10 sur mon PC mais à maximum 10 fps sur certaines tablettes. C’est tout simplement du au fait que le CPU de ces memes tablettes est bien moins puissant et qu’elles n’utilisent pas encore l’accélération matérielle sur le tag <canvas>. L’utilisation de transitions ou d’animations CSS3 pour animer plusieurs petits éléments <canvas> pourrait ainsi fournir un gain très net de performance pour ce jeu. Ne l’oubliez donc pas lorsque vous aurez un projet visant les périphériques mobiles !

Support dans les navigateurs

Comme vous pouvez le voir sur le rapport suivant généré depuis le site caniuse.com, les animations CSS3 sont désormais supportées dans un large panel de navigateurs :

image

Mais vous devrez encore utiliser le préfixe –webkit- pour construire des applications compatibles avec tous les navigateurs.

Mais la question qui devrait alors rapidement se poser est la suivante: comment prendre en charge les navigateurs ne supportant pas cette nouvelle fonctionnalité ?

La première option consiste simplement à ne rien faire. Grâce à la beauté de la dégradation élégante (ou graceful degradation en anglais), vous pouvez simplement offrir une image statique à l’utilisateur. Cela est par exemple le cas des 2 démonstrations d’Anthony : I Twitty the Fool! et Pure CSS3 AT-AT Walker . Lorsqu’affichés sous IE9, vous avez l’impression de n’avoir qu’une image statique. Cependant, lorsque vous les affichez sous IE10, le même code affiche alors de belles animations. Les utilisateurs sous IE10 disposeront d’une version améliorée tant dis que les utilisateurs sous IE9 continueront de pouvoir bénéficier du site. Plus votre navigateur sera moderne, plus vous aurez de bonus visuels.

La deuxième option consiste à détecter le support de la fonctionnalité via une librairie JavaScript comme Modernizr puis de tenter de fournir la même animation avec une autre librairie JavaScript qui s’occupera de copier les animations CSS3. C’est ce que nous appelons communément un mécanisme de “fallback”. Malheureusement, je n’ai pas réussi à trouver aujourd’hui une librairie fonctionnelle et complète pouvant totalement remplacer les animations CSS3 lorsque non supportées par le navigateur.

Il n’en fallait pas plus pour me donner l’envie d’en écrire une petite plus ou moins spécialement étudiée pour notre exemple initial de TB-TT.

Librairie JavaScript pour simuler les animations CSS3

Les animations ne sont finalement qu’une série de transitions séparées pour une certaine durée définie par les keyframes. J’ai donc ré-utilisé les concepts introduits par David Catuhe dans sa librairie pour palier à l’absence éventuelle de CSS3 Transitions. Je vous laisse donc le soin de revoir son article détaillant les concepts derrière ce code si ce n’est déjà fait.

De mon côté, j’ai ajouté le support des animations sur les propriétés rotation & translation de CSS3 2D tranform ainsi qu’une manière d’itérer à travers chacun des keyframes.

Voici la partie principale de la librairie que vous devrez étudier :

 // Objet Animation 
// Il a besoin de l’élément HTML visé, du nom de l’animation, de sa durée, du nombre de fois qu’il faut la jouer et
// des keyframes contenus au sein d’un tableau
// Imaginez ainsi une animation comme une simple séquence de transitions jouées un certain nombre de fois
ANIMATIONSHELPER.animation = function (target, name, duration, iterationcount, keyframes) {
    // on sauvegarde les valeurs de nos propriétés
    this.name = name;
    this.duration = duration;
    this.iterationcount = iterationcount;
    this.target = target;

    var elapsedtime = 0;
    var keyframeduration = 0;
    var elapsedtime = 0;

    // On transforme les pourcentages de chaque keyframe en une valeur de durée
    for (var i = 0; i < keyframes.length; i++) {
        keyframeduration = ((keyframes[i].percentage * duration) / 100) - elapsedtime;
        keyframes[i].duration = keyframeduration;
        elapsedtime += keyframeduration;
    }

    this.currentTransition = { isPlaying: false };
    this.keyframes = keyframes;
    this.keyframesCount = keyframes.length;
    this.currentKeyFrameIndex = 0;

    // La fonction nextTransition() retourne la prochaine transition à jouer
    // en fonction du keyframe courant à lancer
    this.nextTransition = function (keyframe, ease, customEaseP1X, customEaseP1Y, customEaseP2X, customEaseP2Y) {
        var properties = [];
        var finalValues = [];
        var transition;

        // Comparé au TRANSITIONSHELPER original de David Catuhe
        // Nous avons besoin de code spécifique supplémentaire pour jouer sur les valeurs de 2D Transform
        if (keyframe.propertyToAnimate === "transform") {
            for (var i = 0; i < keyframe.transformType.length; i++) {
                properties.push(keyframe.transformType[i].type);
                if (keyframe.transformType[i].type == "rotate") {
                    finalValues.push({ deg: keyframe.transformType[i].value1 });
                }
                else {
                    finalValues.push({ x: keyframe.transformType[i].value1, y: keyframe.transformType[i].value2 });
                }
            }

            // Création d’une nouvelle transition
            transition = {
                name: this.name + this.currentKeyFrameIndex,
                target: this.target,
                properties: properties,
                finalValues: finalValues,
                originalValues: ANIMATIONSHELPER.extractValues(target.style[ANIMATIONSHELPER.currentTransformProperty], this.name),
                duration: keyframe.duration,
                startDate: (new Date).getTime(),
                currentDate: (new Date).getTime(),
                ease: ease,
                customEaseP1X: customEaseP1X,
                customEaseP2X: customEaseP2X,
                customEaseP1Y: customEaseP1Y,
                customEaseP2Y: customEaseP2Y,
                isPlaying: true,
                type: "transform"
            };

            return transition;
        }
        // Si c’est une propriété simple à animer, on peut tout simplement utiliser le TRANSITIONSHELPER presque tel quel
        else {
            return TRANSITIONSHELPER.transition(this.target, keyframe.propertyToAnimate, keyframe.value, keyframe.duration, TRANSITIONSHELPER.easingFunctions.linear);
        }
    };

    // chaque instance d’animation dispose d’une fonction tick
    // qui sera appelée toutes les 17 ms (pour tenter de viser les 60 fps)
    // Ce ticker surveille l’état de la transition en cours et 
    // en créé une nouvelle dès qu’elle est terminée ou morte
    this.tick = function () {
        if (this.iterationcount > 0) {
            if (!this.currentTransition.isPlaying) {
                this.currentTransition = this.nextTransition(this.keyframes[this.currentKeyFrameIndex], ANIMATIONSHELPER.easingFunctions.linear);
                // Nous utilisons le ticker global de ANIMATIONSHELPER uniquement pour les transformations 2D
                // Sinon, on utilise celui de la librairie TRANSITIONSHELPER
                if (this.currentTransition.type === "transform") {
                    ANIMATIONSHELPER.currentTransitions.push(this.currentTransition);
                }
                this.currentKeyFrameIndex++;

                // Nous avons atteint le dernier keyframe (100%). On peut recommencer au début donc.
                if (this.currentKeyFrameIndex >= this.keyframesCount) {
                    this.currentKeyFrameIndex = 0;
                    this.iterationcount--;
                }
            }
        }
    };
};

La 1ère partie du code parcourt la collection des keyframes pour calculer la durée exacte engendrée par chacun des pourcentages. On définit alors une fonction nextTransition() qui va construire dynamiquement la prochaine transition à jouer en se basant sur l’index courant dans la collection de keyframes associés à l’animation en cours. Pour finir, nous avons une function tick() qui surveille l’état de la transition actuellement affectée. Dès que cette dernière se termine, nous demandons la prochaine transition, on la pousse sur la pile des transitions à jouer et on bouge les différents indexes.

La function tick() est rappelée grâce à ce code :

 ANIMATIONSHELPER.launchAnimation = function (animation) {
    // On lance le service global de ticker si nécessaire
    if (ANIMATIONSHELPER.tickIntervalID == 0) {
        ANIMATIONSHELPER.tickIntervalID = setInterval(ANIMATIONSHELPER.tick, 17);
    }

    // Petite closure pour lancer la méthode tick sur la bonne instance d’animation
    setInterval(function () { animation.tick(); }, 17);
};

Pour finir, nous avons ce type de code pour nous aider à fabriquer les keyframes :

 // Objet pour construire des keyframes génériques (et pas pour les CSS3 2D Transform donc)
ANIMATIONSHELPER.keyframe = function (percentage, propertyToAnimate, value) {
    this.percentage = percentage;
    this.propertyToAnimate = propertyToAnimate;
    this.value = value;
};

//Objet pour construire des keyframes dédiés aux rotations
ANIMATIONSHELPER.rotationkeyframe = function (percentage, value) {
    this.percentage = percentage;
    this.propertyToAnimate = "transform";
    this.transformType = [];
    this.transformType.push(new ANIMATIONSHELPER.transformType("rotate", value));
};

Pour illustrer son usage, amusons-nous à refaire le 1er exemple d’animations simples effectuées sur la tête de notre TB-TT avec cette librairie :

 // nombre de fois que vous souhaitez voir l’animation tourner
var iterationsNumber = 100;

var skullElement = document.getElementById("skull");
var keyframes = [];
keyframes.push(new ANIMATIONSHELPER.rotationkeyframe(25, 15));
keyframes.push(new ANIMATIONSHELPER.rotationkeyframe(50, -5));
keyframes.push(new ANIMATIONSHELPER.rotationkeyframe(55, 0));
keyframes.push(new ANIMATIONSHELPER.rotationkeyframe(75, -10));
keyframes.push(new ANIMATIONSHELPER.rotationkeyframe(100, 0));

var animation1 = new ANIMATIONSHELPER.animation(skullElement, "rotate-skull", 7000, 
                                                iterationsNumber, keyframes);

ANIMATIONSHELPER.launchAnimation(animation1, ANIMATIONSHELPER.easingFunctions.linear);

Et voici le résultat animé qui devrait maintenant fonctionner dans tous les navigateurs supportant CSS3 2D Transform :

Pour finir, si l’on revient sur la toute première démonstration au début de cet article, vous verrez qu’elle utilise Modernizr pour vérifier le support des animations CSS3. Si ce n’est pas le cas, on charge le code qui s’occupera de copier le comportement défini par les keyframes présents dans master.css, moz-master.css & ms-master.css :

 // On vérifie le support des animations CSS3
if (!Modernizr.cssanimations) {
    // Si ce n’est pas le cas, on invoque notre librairie JavaScript de secours 
    supportElement.innerHTML = "CSS3 Animations <strong>are not supported</strong>";
    LoadJSAnimationsFallback();
}
else {
    // Si CSS3 Animations est supportée, nous n’avons rien à faire. 
    // Les feuilles de style *master.css seront automatiquement appliquées et utilisées.
    supportElement.innerHTML = "CSS3 Animations <strong>are supported</strong>";
}

La fonction LoadJSAnimationsFallback() est définie dans le fichier jsfallback-master.js qui contient simplement les déclarations de keyframes ainsi que les 19 animations nécessaires à recréer le comportement défini par Anthony en pur CSS3. Avec cette approche, le designer doit donc potentiellement ré-écrire toutes ses règles en faisant appel à la librairie JavaScript. Une autre approche pourrait consister à parser l’un des fichiers CSS en le t��léchargeant via une requête XHR puis d’en déduire dynamiquement les appels JavaScript à faire vers la librairie. Cela nécessite cependant bien plus de travail car il vous faut quasiment ré-implémenter l’ensemble de la spécification CSS3 Animations en JavaScript !

Vous avez normalement maintenant une idée de la manière de créer une mécanisme de “fallback” pour supporter le plus grand nombre de navigateurs tout en commençant à utiliser les dernières spécifications CSS3.

Vous pouvez télécharger les fichiers pour l’exemple principal de cet article ici : https://david.blob.core.windows.net/html5/css3atat/CSS3ATATNonMinified.zip

Il contient les versions non minimisées des fichiers JavaScript animationsHelper.js, transitionsHelper.js, jsfallback-master.js ainsi que les différentes déclinaisons des feuilles de style CSS3 pour les différentes préfixes.

Conclusion

Les animations CSS3 représente une technologie puissante pour repousser les applications HTML5 vers un nouveau niveau. Elles offrent des scénarios intéressants. Les designers/intégrateurs peuvent les utiliser pour créer une nouvelle génération d’expérience utilisateur avec des écrans rapides et fluides sans avoir besoin de faire appel à un développeur. Comme elles sont la plupart du temps accélérées matériellement, les développeurs doivent également malgré tout y jeter un œil. Pour finir, les 2 populations peuvent collaborer. Les designers pourraient concevoir une série d’animations prédéfinies répondant aux besoins les plus courants et offrant une expérience homogène. Les développeurs pourraient alors récupérer le fruit de ce travail pour en créer des librairies JavaScript qui implémenteront ces animations. Ces librairies pourraient alors offrir une manière transparente de fournir 2 implémentations sous-jacentes : de la génération dynamique d’animations CSS3 à la volée ou une version de secours en pur JavaScript pour les anciens navigateurs.

Pour aller plus loin

 

David Rousset