L'animation d'un DIV avec JavaScript rend les artefacts sur Chrome

En tant qu'expérience, j'essaie de reproduire la fonctionnalité Sprite d'AS3 en JavaScript sans utiliser l'objet canvas. Je pensais que l'utilisation de divs absolument positionnés et la manipulation de leurs propriétés css seraient sans évidence, mais dans Chrome, l'animation présente des artefacts étranges (apparemment à cause des problèmes de redimensionnement).

Je ne peux pas trouver ce que je fais mal? Le code est, en fait, assez simple. Voici quelques points que j'ai essayé, ce qui n'a pas aidé:

  • En utilisant des divs relativement positionnés (par opposition à absolument positionnés).
  • Utilisation des marges (par opposition aux propriétés supérieure et gauche).
  • Ajoute des objets directement au corps (par opposition à l'ajout à un conteneur div.)
  • Utilisation de setTimeout (par opposition à requestAnimationFrame)

Vous pouvez voir un violon simplifié ici: http://jsfiddle.net/BVJYJ/2/

EDIT: http://jsfiddle.net/BVJYJ/4/

Et ici, vous pouvez voir les artefacts sur mon navigateur:

Les artefacts en Chrome

Cela peut être un bug dans mon installation (Windows 7 64 bits, Chrome 21.0.1180.75). Aucun autre navigateur ne présente ce comportement. J'apprécierais beaucoup si quelqu'un pouvait commenter ce que je pourrais faire mal. Je suis plus curieux de la raison derrière cela plutôt que d'une solution de contournement. Cela dit, toutes les explications sont les bienvenues. 🙂

EDIT: Il y avait un bug dans l'exemple de code qui a entraîné l'utilisation de setTimeout, même si j'avais l'impression que RAF était utilisé. RequestAnimationFrame résout le problème avec la transformation de base, mais le problème persiste avec les transformations CSS telles que la rotation.

Les artefacts en Chrome avec transformation de la rotation.

J'ai eu le même problème avec mon plugin liteAccordion. Il peut être corrigé en définissant la visibilité de l'arrière-page sur l'élément que vous animez, comme vous pouvez le voir ici: http://jsfiddle.net/ZPQBp/1/

Certaines recherches montrent que setTimeout pourrait causer des problèmes pour diverses raisons. Vous devez vraiment utiliser requestAnimationFrame :

Les minuteries ne sont pas précises à la milliseconde. Voici quelques résolutions de minuterie communes 1 :

  • Internet Explorer 8 et versions antérieures ont une résolution temporisée de 15.625 ms
  • Internet Explorer 9 et versions ultérieures ont une résolution de minuterie de 4ms. Firefox
  • Et Safari ont une résolution temporisée de ~ 10 ms.
  • Chrome a une résolution de minuterie de 4 ms.

Internet Explorer avant la version 9 a une résolution de minuterie de 15.625 ms 1 , donc toute valeur entre 0 et 15 pourrait être 0 ou 15 mais rien d'autre. Internet Explorer 9 a amélioré la résolution de la minuterie à 4 ms, mais ce n'est toujours pas très précis en ce qui concerne les animations.

La résolution de la minuterie de Chrome est de 4 ms tandis que Firefox et Safari est de 10 ms. Donc, même si vous définissez votre intervalle pour une affichage optimal, vous n'êtes que près de la synchronisation souhaitée.

Référence: http://www.nczonline.net/blog/2011/05/03/better-javascript-animations-with-requestanimationframe/

Aussi

setTimeout ne prend pas en compte ce qui se passe dans le navigateur. La page pourrait être cachée derrière un onglet, accaparant votre CPU quand il n'a pas besoin, ou l'animation elle-même aurait pu être déroulée sur la page pour rendre l'appel de mise à jour encore inutile. Chrome n'inclut pas setInterval et setTimeout à 1fps dans les onglets cachés, mais cela ne dépend pas de tous les navigateurs.

Deuxièmement, setTimeout met à jour l'écran uniquement quand il le veut, et non pas lorsque l'ordinateur est capable de le faire. Cela signifie que votre navigateur pauvre doit jongler en redessinant l'animation tout en redessinant l'écran entier, et si votre taux d'image d'animation n'est pas synchronisé avec le redessiner votre écran, il pourrait prendre plus de puissance de traitement. Cela signifie une utilisation plus élevée du processeur et le démarrage de votre ordinateur, ou l'évacuation de la batterie sur votre appareil mobile. Nicolas Zakas fait un excellent travail expliquant la résolution de l'impact de la minuterie sur l'animation dans un article connexe.

Référence: http://creativejs.com/resources/requestanimationframe/

Cela a quelque chose à voir avec le positionnement des sous-pixels . Si vous rallumez vers le pixel le plus proche, vous ne verrez pas ces erreurs de rendu:

 thisRef.block.style.left = Math.round((x + (mouseX - ox - x) * .125)) + "px"; thisRef.block.style.top = Math.round((y + (mouseY - oy - y) * .125)) + "px";