262 votes

Comment forcer WebKit à redessiner/peindre pour propager les changements de style ?

J'ai quelques JavaScript triviaux pour effectuer un changement de style :

sel = document.getElementById('my_id');
sel.className = sel.className.replace(/item-[1-9]-selected/,'item-1-selected');
return false;

Cela fonctionne bien avec les dernières versions de FF, Opera et IE, mais échoue avec les dernières versions de Chrome et Safari.

Elle affecte deux descendants, qui se trouvent être des frères et sœurs. Le premier frère est mis à jour, mais le second ne l'est pas. Un enfant du deuxième élément a également le focus et contient la balise <a> qui contient le code ci-dessus dans une balise onclick attribut.

Dans la fenêtre "Developer Tools" de Chrome, si je modifie (par exemple en décochant et en cochant) les éléments suivants cualquier attribut de cualquier le deuxième élément de la fratrie est mis à jour avec le style correct.

Existe-t-il une solution de contournement permettant de "pousser" WebKit à faire ce qu'il faut, de manière simple et programmatique ?

0 votes

Je pense que je rencontre ce problème sur Android 4.2.2 (Samsung I9500) lorsque je place mon application canvas dans une WebView. C'est ridicule !

6 votes

what-forces-layout.md un très bon lieu de lecture

329voto

danorton Points 3458

J'ai trouvé des suggestions compliquées et de nombreuses suggestions simples qui n'ont pas fonctionné, mais un commentaire à l'une d'entre elles par Vasil Dinkov a fourni une solution simple pour forcer un redessin/répeinture qui fonctionne parfaitement :

sel.style.display='none';
sel.offsetHeight; // no need to store this anywhere, the reference is enough
sel.style.display='';

Je laisserai à quelqu'un d'autre le soin de dire si cela fonctionne pour d'autres styles que le "bloc".

Merci, Vasil !

0 votes

Curieusement, cela semble définir un bit "sale" différent de celui qui a permis à la première fratrie de se mettre à jour correctement. Ce fragment fait tout repeindre même si je le mets à la place de antes de le fragment original !

33 votes

Pour éviter le scintillement, vous pouvez essayer 'inline-block' , 'table' o 'run-in' au lieu de 'none' mais cela peut avoir des effets secondaires. De plus, un délai de 0 déclenche un reflux, tout comme l'interrogation de offsetHeight ne : sel.style.display = 'run-in'; setTimeout(function () { sel.style.display = 'block'; }, 0);

0 votes

Nous travaillons avec GWT et utilisons simplement sel.style.display='block' ; qui a fait l'affaire.

106voto

morewry Points 1112

Nous avons récemment rencontré ce problème et découvert qu'en promouvant l'élément concerné en couche composite con traduireZ en CSS a permis de résoudre le problème sans nécessiter de JavaScript supplémentaire.

.willnotrender { 
   transform: translateZ(0); 
}

Comme ces problèmes de peinture apparaissent principalement dans Webkit/Blink, et que ce correctif vise principalement Webkit/Blink, il est préférable dans certains cas. D'autant plus que la réponse acceptée provoque presque certainement un refusion et repeindre , no juste un repeint.

Webkit et Blink ont travaillé dur sur les performances de rendu, et ce type de problèmes est l'effet secondaire malheureux des optimisations qui visent à réduire les flux et les peintures inutiles. CSS will-change ou une autre spécification ultérieure sera très probablement la solution future.

Il existe d'autres façons d'obtenir une couche composite, mais c'est la plus courante.

1 votes

Cela a fonctionné pour moi lorsque j'ai utilisé angular-carousel !

1 votes

Correction d'un problème où le rayon de la bordure était perdu dans un élément à l'intérieur d'un panneau coulissant

1 votes

Fonctionne aussi pour les projets cordova !

51voto

Gerben Points 10821

La solution de danorton n'a pas fonctionné pour moi. J'ai eu des problèmes vraiment bizarres où webkit ne dessinait pas du tout certains éléments, où le texte dans les entrées n'était pas mis à jour jusqu'à onblur, et où le changement de className n'entraînait pas de redessin.

Ma solution, que j'ai découverte accidentellement, consistait à ajouter un élément de style vide au corps, après le script.

<body>
...
<script>doSomethingThatWebkitWillMessUp();</script>
<style></style>
...

Cela a réglé le problème. C'est bizarre, non ? J'espère que cela aidera quelqu'un.

3 votes

Si je le pouvais, j'augmenterais mon score de 1 000 000 de fois. C'est le seul moyen que j'ai trouvé pour que chrome repeigne une div stupide que je traînais. Au fait, il n'est pas nécessaire d'ajouter un élément de style (du moins, je ne l'ai pas fait), n'importe quel élément peut faire l'affaire. J'ai créé un div et je lui ai donné un id pour pouvoir supprimer puis ajouter l'élément à chaque étape, afin de ne pas remplir le DOM avec des balises inutiles.

6 votes

Je viens de l'utiliser en combinaison avec le commentaire de Pumbaa80 sur une autre réponse. La solution que j'ai trouvée est la suivante var div = $('<div>').appendTo(element); setTimeout(function(){ div.remove(); }, 0);

33 votes

Cette ligne unique fonctionne très bien pour moi ! $('<style></style>').appendTo($(document.body)).remove();

35voto

EricG Points 1723

Comme le déclenchement de l'affichage + décalage n'a pas fonctionné pour moi, j'ai trouvé une solution ici :

http://mir.aculo.us/2009/09/25/force-redraw-dom-technique-for-webkit-based-browsers/

c'est-à-dire

element.style.webkitTransform = 'scale(1)';

3 votes

J'ai utilisé cela dans un hack que j'essayais, mais au lieu de scale(1) Je l'ai assigné à lui-même en tant que element.style.webkitTransform = element.style.webkitTransform . La raison en est que le choix de l'ancienne valeur déformait légèrement la page pour l'utilisateur. absolute des éléments bien positionnés !

0 votes

Cela a fonctionné pour moi, et je n'ai pas eu de problèmes de scintillement ou de réinitialisation de la position de défilement que l'on peut trouver dans la fenêtre de l'application. display a fait.

0 votes

J'avais une application Cordova qui utilisait beaucoup de SVG dynamiques. Cela fonctionnait bien partout sauf sous iOS7, où if n'affichait pas les éléments SVG au démarrage. J'ai ajouté un simple $('body')[0].style.webkitTransform = 'scale(1)' ; au code d'initialisation et le problème a disparu !

24voto

Rob Murphy Points 311

J'ai eu le même problème. La solution de danorton pour "basculer l'affichage" a fonctionné pour moi lorsqu'elle a été ajoutée à la fonction de pas de mon animation, mais j'étais préoccupé par les performances et j'ai cherché d'autres options.

Dans mon cas, l'élément qui ne se repeignait pas se trouvait à l'intérieur d'un élément de position absolue qui n'avait pas, à l'époque, d'indice z. L'ajout d'un indice z à l'élément a modifié le comportement de Chrome. L'ajout d'un indice z à cet élément a modifié le comportement de Chrome et les repeints se sont produits comme prévu -> les animations sont devenues fluides.

Je doute qu'il s'agisse d'une panacée, j'imagine que cela dépend de la situation. pourquoi Chrome a choisi de ne pas redessiner l'élément mais je poste cette solution spécifique ici dans l'espoir d'aider quelqu'un.

Santé, Rob

tl;dr >> Essayez d'ajouter un indice z à l'élément ou à l'un de ses parents.

8 votes

Brillant. C'est génial et cela a résolu le problème pour moi. A+++, je referai l'indexation.

0 votes

Cela n'a pas fonctionné dans ma situation avec les barres de défilement et les transformations.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X