Comment puis-je forcer WebKit à redessiner / repeindre pour propager les modifications de style?

J’ai un JavaScript sortingvial 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 sur les dernières versions de Chrome et Safari.

Elle affecte deux descendants, qui sont des frères et soeurs. Les premiers frères et sœurs mettent à jour, mais le second ne le fait pas. Un enfant du second élément a également le focus et contient la balise qui contient le code ci-dessus dans un atsortingbut onclick .

Dans la fenêtre Chrome «Developer Tools» (Outils de développement) de Chrome, si je décale (par exemple, décochez et cochez) tout atsortingbut d’ un élément quelconque , le deuxième frère se met à jour avec le style correct.

Existe-t-il une solution pour «décaler» WebKit de manière simple et par programmation afin de faire ce qu’il faut?

J’ai trouvé des suggestions compliquées et de nombreuses suggestions simples qui ne marchaient pas, mais un commentaire de Vasil Dinkov a fourni une solution simple pour forcer un redessinage / repeindre qui fonctionne très bien:

 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 commenter si cela fonctionne pour des styles autres que «bloquer».

Merci Vasil!

Nous avons récemment rencontré ceci et avons découvert que la promotion de l’élément affecté dans un calque composite avec translateZ dans CSS a corrigé le problème sans avoir besoin de JavaScript supplémentaire.

 .willnotrender { transform: translateZ(0); } 

Comme ces problèmes de peinture apparaissent principalement dans Webkit / Blink, et que ce correctif cible principalement Webkit / Blink, il est préférable dans certains cas. Surtout que la réponse acceptée provoque presque certainement un refonte et repeint , pas seulement un repeint.

Webkit et Blink ont ​​travaillé d’arrache-pied sur les performances de rendu, et ce type d’effets indésirables est l’effet secondaire des optimisations visant à réduire les stream et les peintures inutiles. CSS va changer ou une autre spécification sera la solution la plus probable.

Il existe d’autres moyens de réaliser un calque composite, mais c’est le plus courant.

La solution 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’a pas été mis à jour avant la fin; et la modification de className n’entraînerait pas de nouvelle version.

J’ai accidentellement découvert que ma solution consistait à append un élément de style vide au corps, après le script.

  ...   ... 

Cela a corrigé C’est bizarre ça? J’espère que cela est utile pour quelqu’un.

Comme le déclencheur d’affichage + offset 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)'; 

Je souffrais du même problème. Le correctif de danorton “toggling display” a fonctionné pour moi lorsqu’il a été ajouté à la fonction step de mon animation mais j’étais préoccupé par la performance et j’ai cherché d’autres options.

Dans mon cas, l’élément qui ne repeignait pas était dans un élément absolument positionné qui, à l’époque, n’avait pas d’indice z. L’ajout d’un index z à cet élément a modifié le comportement de Chrome et les repaints ont eu lieu comme prévu -> les animations sont devenues régulières.

Je doute qu’il s’agisse d’une panacée, j’imagine que cela dépend de la raison pour laquelle Chrome a choisi de ne pas redessiner l’élément, mais je publie cette solution spécifique dans l’aide qu’elle espère.

Cheers, Rob

tl; dr >> Essayez d’append un index z à l’élément ou à un parent.

Les travaux suivants Il suffit de le définir une seule fois en CSS pur. Et cela fonctionne de manière plus fiable qu’une fonction JS. La performance ne semble pas affectée.

 @-webkit-keyframes androidBugfix {from { padding: 0; } to { padding: 0; }} body { -webkit-animation: androidBugfix infinite 1s; } 

Pour une raison quelconque, je ne pouvais pas obtenir la réponse de danorton au travail, je pouvais voir ce que c’était censé faire, je l’ai un peu modifié:

 $('#foo').css('display', 'none').height(); $('#foo').css('display', 'block'); 

et ça a fonctionné pour moi.

Je suis tombé sur cela aujourd’hui: Element.redraw () pour prototype.js

En utilisant:

 Element.addMethods({ redraw: function(element){ element = $(element); var n = document.createTextNode(' '); element.appendChild(n); (function(){n.parentNode.removeChild(n)}).defer(); return element; } }); 

Cependant, j’ai parfois remarqué que vous devez appeler directement redraw () sur l’élément problématique. Parfois, le fait de redessiner l’élément parent ne résoudra pas le problème rencontré par l’enfant.

Bon article sur la façon dont les navigateurs rendent les éléments: Rendu: repeindre, redissortingbuer / relayer, restyler

Je suis venu ici parce que je devais redessiner les barres de défilement dans Chrome après avoir changé son css.

Si quelqu’un a le même problème, je l’ai résolu en appelant cette fonction:

 //Hack to force scroll redraw function scrollReDraw() { $('body').css('overflow', 'hidden').height(); $('body').css('overflow', 'auto'); } 

Cette méthode n’est pas la meilleure solution, mais elle peut fonctionner avec tout, cacher et montrer l’élément qui doit être redessiné peut résoudre tous les problèmes.

Voici le violon où je l’ai utilisé: http://jsfiddle.net/promatik/wZwJz/18/

J’ai eu ce problème avec un certain nombre de divs qui ont été insérés dans une autre div avec position: absolute , les divs insérés n’avaient aucun atsortingbut de position. Quand j’ai changé cela en position:relative ça marchait bien. (était vraiment difficile de cerner le problème)

Dans mon cas, les éléments ont été insérés par Angular avec ng-repeat .

Je ne peux pas croire que cela rest un problème en 2014. Je viens d’avoir ce problème en rafraîchissant une boîte de légende de position fixe dans le coin inférieur gauche de la page tout en défilant, la légende monte à l’écran. Après avoir essayé tout ce qui précède sans succès, j’ai remarqué que beaucoup de choses étaient soit lentes / causant des problèmes dus à la création de relais relais très courts, etc. provoquant un défilement peu naturel, etc.

J’ai fini par créer une position fixe, div pleine taille avec pointer-events: none et appliquer la réponse de danorton à cet élément, ce qui semble forcer un redessin sur tout l’écran sans interférer avec le DOM.

HTML:

 

CSS:

 div#redraw-fix { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 25; pointer-events: none; display: block; } 

JS:

 sel = document.getElementById('redraw-fix'); sel.style.display='none'; sel.offsetHeight; // no need to store this anywhere, the reference is enough sel.style.display='block'; 

Non pas que cette question nécessite une autre réponse, mais j’ai trouvé que le simple fait de changer la couleur d’un seul coup a forcé à repeindre dans ma situation particulière.

 //Assuming black is the starting color, we tweak it by a single bit elem.style.color = '#000001'; //Change back to black setTimeout(function() { elem.style.color = '#000000'; }, 0); 

setTimeout s’est avéré essentiel pour déplacer le deuxième changement de style en dehors de la boucle d’événements en cours.

La seule solution pour moi est similaire à la réponse de sowasred2012:

 $('body').css('display', 'table').height(); $('body').css('display', 'block'); 

J’ai beaucoup de blocs de problèmes sur la page, donc je change la propriété d’ display de l’élément racine. Et j’utilise display: table; au lieu de l’ display: none; , car none ne réinitialisera le décalage de défilement.

Puisque tout le monde semble avoir ses propres problèmes et solutions, j’ai pensé que j’appendais quelque chose qui fonctionne pour moi. Sur Android 4.1 avec Chrome actuel, essayez de faire glisser un canevas à l’intérieur d’un div avec un débordement: hidden, je ne pourrais pas obtenir de nouvelle trace à moins que j’ajoute un élément au div parent (où il ne ferait aucun mal).

 var parelt = document.getElementById("parentid"); var remElt = document.getElementById("removeMe"); var addElt = document.createElement("div"); addElt.innerHTML = " "; // Won't work if empty addElt.id="removeMe"; if (remElt) { parelt.replaceChild(addElt, remElt); } else { parelt.appendChild(addElt); } 

Pas de scintillement de l’écran ou de mise à jour réelle, et de nettoyage après moi. Pas de variables globales ou classées, juste des sections locales. Cela ne semble pas faire de mal à Mobile Safari / iPad ou aux navigateurs de bureau.

Je travaille sur l’application html5 ionique, sur quelques écrans j’ai absolute élément positionné absolute , quand défiler vers le haut ou le bas dans les appareils IOS (iPhone 4,5,6, 6+), j’ai eu un bogue de repeindre.

Essayé beaucoup de solution, aucun d’entre eux ne fonctionnait sauf que celui-ci résolvait mon problème.

J’ai utiliser la classe css .fixRepaint sur ces éléments de positions absolues

 .fixRepaint{ transform: translateZ(0); } 

Cela a corrigé mon problème, cela peut aider quelqu’un

C’est bon pour JS

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

Mais dans Jquery, et en particulier lorsque vous ne pouvez utiliser que $ (document) .ready et que vous ne pouvez pas vous lier à un événement .load d’un object pour une raison particulière, les éléments suivants fonctionneront.

Vous devez récupérer le conteneur OUTER (MOST) des objects / divs, puis supprimer tout son contenu dans une variable, puis le rappend. Cela rendra visible TOUS les changements effectués dans le conteneur externe.

 $(document).ready(function(){ applyStyling(object); var node = $("div#body div.centerContainer form div.centerHorizontal").parent().parent(); var content = node.html(); node.html(""); node.html(content); } 

J’ai trouvé cette méthode utile pour travailler avec des transitions

 $element[0].style.display = 'table'; $element[0].offsetWidth; // force reflow $element.one($.support.transition.end, function () { $element[0].style.display = 'block'; }); 

le hack “display / offsetHeight” ne fonctionnait pas dans mon cas, du moins quand il était appliqué à l’élément en cours d’animation.

J’avais un menu déroulant ouvert / fermé sur le contenu de la page. les artefacts étaient laissés sur le contenu de la page après la fermeture du menu (uniquement dans les navigateurs Webkit). la seule façon dont le hack “display / offsetHeight” a fonctionné est si je l’applique au corps, ce qui me semble désagréable.

Cependant, j’ai trouvé une autre solution:

  1. avant que l’élément ne commence à animer, ajoutez une classe qui définit “-webkit-backface-visibility: hidden;” sur l’élément (vous pouvez également utiliser le style en ligne, je suppose)
  2. une fois l’animation terminée, supprimez la classe (ou le style)

c’est encore assez pirate (il utilise une propriété CSS3 pour forcer le rendu du matériel), mais au moins cela n’affecte que l’élément en question, et a fonctionné pour moi sur le safari et le chrome sur PC et Mac.

Cela semble lié à ceci: le style jQuery n’est pas appliqué dans Safari

La solution proposée dans la première réponse a bien fonctionné pour moi dans ces scénarios, à savoir: appliquer et supprimer une classe factice au corps après avoir apporté les modifications de style:

 $('body').addClass('dummyclass').removeClass('dummyclass'); 

Cela oblige le safari à se redessiner.

Les suggestions ci-dessus n’ont pas fonctionné pour moi. mais le dessous fait.

Vous voulez changer le texte à l’intérieur de l’ancre dynamicment. Le mot “Rechercher”. Création d’une balise interne “font” avec un atsortingbut id. Géré le contenu en utilisant javascript (ci-dessous)

 Chercher

contenu du script:

  var searchText = "Search"; var editSearchText = "Edit Search"; var currentSearchText = searchText; function doSearch() { if (currentSearchText == searchText) { $('#pSearch').panel('close'); currentSearchText = editSearchText; } else if (currentSearchText == editSearchText) { $('#pSearch').panel('open'); currentSearchText = searchText; } $('#searchtxt').text(currentSearchText); } 

J’avais un problème avec un SVG qui disparaissait sur Chrome pour Android lorsque l’orientation a été modifiée dans certaines circonstances. Le code ci-dessous ne le reproduit pas, mais est la configuration que nous avions.

 body { font-family: tahoma, sans-serif; font-size: 12px; margin: 10px; } article { display: flex; } aside { flex: 0 1 10px; margin-right: 10px; min-width: 10px; position: relative; } svg { bottom: 0; left: 0; position: absolute; right: 0; top: 0; } .backgroundStop1 { stop-color: #5bb79e; } .backgroundStop2 { stop-color: #ddcb3f; } .backgroundStop3 { stop-color: #cf6b19; } 
 

Donec et eros nibh. Nullam porta, elit ut sagittis pulvinar, lacus augue lobortis mauris, sed sollicitudin elit orci non massa. Proin condimentum in nibh sed vestibulum. Donec accumsan fringilla est, porttitor vestibulum dolor ornare id. Sed elementum urna sollicitudin commodo ulsortingcies. Curabitur sortingstique orci et ligula interdum, eu condimentum metus eleifend. Nam libero augue, pharetra at maximus in, pellentesque imperdiet orci.

Fusce commodo ullamcorper ullamcorper. Etiam eget pellentesque quam, id sodales erat. Vestibulum risus magna, efficitur sed nisl et, rutrum consectetur odio. Sed at lorem non ligula consequat tempus vel nec risus.

Je recommanderais un moyen moins piquant et plus formel pour forcer une redissortingbution: utilisez forceDOMReflowJS . Dans votre cas, votre code ressemblerait à ceci.

 sel = document.getElementById('my_id'); forceReflowJS( sel ); return false; 

Une solution simple avec jquery:

 $el.html($el.html()); 

ou

 element.innerHTML = element.innerHTML; 

Avait un SVG qui ne montrait pas quand il a été ajouté au HTML.

Cela peut être ajouté après que les éléments svg soient à l’écran.

Une meilleure solution est d’utiliser:

 document.createElementNS('http://www.w3.org/2000/svg', 'svg'); 

et avec jQuery:

 $(svgDiv).append($(document.createElementNS('http://www.w3.org/2000/svg', 'g')); 

Cela sera rendu correctement sur Chrome.