web-dev-qa-db-fra.com

Forcer le navigateur à déclencher la redistribution lors du changement de CSS

Je crée un curseur d'image non jQuery responsive basé sur des transitions CSS3.

La structure est simple: une fenêtre et un UL relativement positionné avec des LI flottants à gauche.

Je suis confronté à un problème dans une telle situation:

  1. L'utilisateur clique sur la flèche "prev".
  2. JS ajoute le LI approprié avant le nœud LI actuellement affiché.
  3. Pour l'instant, UL a défini la transition CSS sur none 0s linear pour empêcher les changements d'animation. En ce moment, je diminue la valeur gauche UL CSS de la largeur du curseur (disons: de 0px à -1200px) pour rendre la vue identique.
  4. Maintenant, je change la propriété de transition d'UL en all 0.2s ease-out.
  5. Maintenant, je modifie la propriété gauche d'UL pour déclencher une animation CSS3. (disons: de -1200px à 0px).

Quel est le problème? Le navigateur simplifie les modifications et ne fait aucune animation.

Stoyan Stefanov a écrit sur le problème de refusion sur son blog ici , mais dans ce cas, essayer de forcer une refusion sur un élément ne fonctionne pas.

Ceci est un morceau de code faisant cela (j'ai sauté les préfixes du navigateur pour simplifier):

ul.style.transition = 'none 0s linear 0s';ul.style.left = '-600px';ul.style.transition = 'all 0.2s ease-out';ul.style.left = '0px';

Voici un violon pour voir le problème en action: http://jsfiddle.net/9WX5b/1/

26
Simon

Demander le offsetHeight d'un élément fait tout bien. Vous pouvez forcer une refusion en utilisant cette fonction et en lui passant l'élément sur lequel les styles ont été modifiés:

function reflow(elt){
    console.log(elt.offsetHeight);
}

Et appelez cela là où des redistributions sont nécessaires. Voir cet exemple: http://jsfiddle.net/9WX5b/2/

EDIT: récemment nécessaire pour le faire, et s'est demandé s'il y avait un meilleur moyen que de le console.log. Vous ne pouvez pas simplement écrire elt.offsetHeight Comme sa propre déclaration, car l'optimiseur (Chrome, au moins) ne déclenchera pas de redistribution car il accède simplement à une propriété sans getter défini, pas même besoin de l'évaluer. Ainsi, AFAIK le moyen le moins cher de le faire est void(elt.offsetHeight), car il ne sait pas avec certitude si void a des effets secondaires ou non. (pourrait être remplacé ou quelque chose, idk).

25
markasoftware
function reflow( element ) {
    if ( element === undefined ) {
        element = document.documentElement;
    }
    void( element.offsetHeight );
}

Cela fonctionne bien avec Chrome et FF, et semble être le moyen le plus simple et le plus portable de le faire en ATM).

3
vaxquis