Opera : combien de transitions ?

Alors que je cherchais à simplifier l'objet javascript qui me sert à gérer les animations, je me suis retrouver face à un problème dont je n'ai pas encore trouver la solution : comment savoir, sous Opera, quand une transition CSS est terminée ?

Lorsque vous animez une série de propriétés CSS avec les transitions, un événement transitionend est émis pour chaque propriété. Donc, si vous animez la largeur (width) et la couleur (color) d'un élément, vous recevrez 2 événements transitionend.

Dans la plupart des cas, nous souhaitons être informé uniquement quand toutes les transitions sont terminées. Pour cela, nous pourrions utiliser la propriété transition-property, qui définit les propriétés à animer, en déduire leur nombre et ne déclencher l'action finale que lors du dernier transitionend reçu. Il nous faut donc à un moment ou un autre lire la valeur de la propriété CSS transition-property. Et là, c'est le drame, du moins sous Opera ! Explications.

Pour lire la valeur d'une propriété CSS appliquée à un élément DOM, on passe généralement par la méthode globale getComputedStyle :

/**
 *  @param {HTMLElement} element Elément à analyser.
 *  @param {String} property Nom de la propriété CSS.
 *  @return {String} La valeur de la propriété.
 */
var getStyle = function (element, property) {
    return window.getComputedStyle(element, null).
            getPropertyValue(property);
};
Version simplifiée d'une fonction permettant de récupérer la valeur d'une propriété CSS appliquée à un élément.

Voyons donc ce que nous recevons comme valeur pour un élément auquel sont appliquées les règles suivantes :

#element {
    background: red;
    margin-bottom: 20px;
    -webkit-transition: background 1s;
       -moz-transition: background 1s;
        -ms-transition: background 1s;
         -o-transition: background 1s;
            transition: background 1s;
}
Exemple de règles CSS appliquées à un élément.
Valeurs rendues par getComputedStyle pour différentes propriétés.
Propriétés Firefox 11 Opera 11.62 Chromium 18
font-size 16px 16px 16px
line-height 19px normal normal
background rgb(255, 0, 0) rgb(255, 0, 0) none repeat scroll 0% 0%
background-color rgb(255, 0, 0) rgb(255, 0, 0) rgb(255, 0, 0)
margin 0px 0px 20px 0px 0px 20px
margin-bottom 20px 20px 20px
transition null
-(o|moz|webkit)-transition
transition-property null
-(o|moz|webkit)-transition-property background background

Quelques remarques en aparté, non liées à ce qui nous occupe ici mais qu'il est toujours utile de connaitre. D'abord concernant les propriétés héritées : pour font-size, les 3 navigateurs fournissent sa valeur calculée ; Pour line-height, par contre, Firefox renvoit une valeur calculée tandis qu'Opera et Chromium retournent le mot-clé correspondant à la valeur par défaut(1).

Viennent ensuite des propriétés qui possèdent une déclaration compacte : pour les 2 propriétés concernées (background et margin), Firefox ne renvoit rien ; Opera renvoit uniquement la valeur déclarée dans le cas de background et une forme compacte pour margin ; Chromium renvoit la forme complète de la propriété pour background et la même forme compacte qu'Opera pour margin(2). Si on intérroge les propriétés spécifiques, background-color et margin-bottom, les 3 navigateurs renvoient la bonne valeur(3).

Venons-en enfin à l'objet de ce billet : la récupération de la valeur de transition-property. C'est une propriété particulière dans le sens où les transitions sont encore une fonctionnalité à l'état d'ébauche ; il ne faut donc pas intérroger la propriété elle-même mais sa version préfixée selon le navigateur ou le moteur de rendu.

Ici, contrairement aux autres propriétés compactes, les 3 navigateurs (et pas seulement Firefox) ne renseignent pas la propriété -prefix-transition(4). On arrive toujours à récupérer la valeur recherchée en demandant la propriété spécifique (-prefix-transition-property), mais pas sous Opera, qui continue à ne rien renvoyer.

Pourquoi ? Voilà la question à 100 000 roupies ! S'agit-il d'un bug ? D'une implémentation délibérée des développeurs d'Opera ? Je n'ai rien trouvé qui puisse m'aiguiller sur le sujet, à part un post datant d'octobre 2011 sur un forum communautaire et qui n'a reçu aucune réponse.

Revenons à nos moutons : nous ne pouvons donc pas récupérer une valeur utilisable de la propriété transition-property sous Opera ; mais nous pourrions avoir la même difficulté avec les autres navigateurs si le mot-clé all était utilisé en lieu et place d'une liste de propriétés(5). Alors que faire ? Compter sur le timeStamp des événements émis ? Pas plus : outre le fait que chaque propriété peut être animée avec une durée différente, il n'est pas forcément identique pour tous les événements sous Chromium ; il est par ailleurs nul sous Firefox 11 (là aussi, s'agit-il d'un bug ?).

Bref, il paraît bien difficile de connaître la fin de toutes les transitions appliquées à un élément avec les objet et les API disponibles nativement.

Mise à jour (2012-04-30) : le problème de lecture de la propriété transition-property n'existe plus avec Opera 12 beta.

JACKSON, Dean ; HYATT, David ; MARRIN, Chris, et al.. CSS Transitions Module Level 3. W3C,

CSS transitions. Mozilla Developer Network,

BOS, Bert ; ÇELIK, Tantek ; HICKSON, Ian, et al.. CSS 2.1 Specification. W3C, . 6.2 Inheritance

BOS, Bert ; ÇELIK, Tantek ; HICKSON, Ian, et al.. CSS 2.1 Specification. W3C,

BOS, Bert ; ÇELIK, Tantek ; HICKSON, Ian, et al.. CSS 2.1 Specification. W3C, . 4.1.2.1 Vendor-specific extensions