¿Cómo puedo forzar a WebKit a volver a dibujar / volver a pintar para propagar los cambios de estilo?

Tengo un JavaScript trivial para efectuar un cambio de estilo:

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

Esto funciona bien con las últimas versiones de FF, Opera e IE, pero falla en las últimas versiones de Chrome y Safari.

Afecta a dos descendientes, que resultan ser hermanos. El primer hermano actualiza, pero el segundo no. Un elemento secundario del segundo elemento también tiene foco y contiene la etiqueta que contiene el código anterior en un atributo onclick .

En la ventana “Herramientas de desarrollador” de Chrome si hago un pequeño empujón (por ejemplo, desmarque y marque) cualquier atributo de cualquier elemento, el segundo hermano se actualiza al estilo correcto.

¿Hay alguna solución alternativa para “empujar” WebKit fácil y programáticamente a hacer lo correcto?

Encontré algunas sugerencias complicadas y muchas simples que no funcionaron, pero un comentario de Vasil Dinkov a una de ellas proporcionó una solución simple para forzar un redibujado / repintado que funciona bien:

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

Dejaré que alguien más comente si funciona para otros estilos que no sean “bloquear”.

Gracias, Vasil!

Recientemente nos encontramos con esto y descubrimos que la promoción del elemento afectado a una capa compuesta con translateZ en CSS solucionó el problema sin necesidad de JavaScript adicional.

 .willnotrender { transform: translateZ(0); } 

Como estos problemas de pintura aparecen principalmente en Webkit / Blink, y esta solución se dirige principalmente a Webkit / Blink, es preferible en algunos casos. Especialmente dado que la respuesta aceptada casi con certeza causa un reflujo y un repintado , no solo un repintado.

Webkit y Blink han estado trabajando arduamente en el rendimiento de la renderización, y este tipo de problemas técnicos son el desafortunado efecto secundario de las optimizaciones que apuntan a reducir flujos y pinturas innecesarios. CSS will-change u otra especificación siguiente será la solución futura, lo más probable.

Hay otras maneras de lograr una capa compuesta, pero esta es la más común.

La solución de Danorton no funcionó para mí. Tenía algunos problemas realmente extraños donde webkit no dibujaba algunos elementos; donde el texto en entradas no se actualizó hasta onblur; y cambiar className no daría como resultado un redibujado.

Mi solución, descubrí accidentalmente, era agregar un elemento de estilo vacío al cuerpo, después del guión.

  ...   ... 

Eso lo solucionó ¿Qué tan extraño es eso? Espero que esto sea útil para alguien.

Como el activador de desplazamiento + pantalla no funcionaba para mí, encontré una solución aquí:

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

es decir

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

Estaba sufriendo el mismo problema. La solución de “cambio de pantalla” de danorton funcionó para mí cuando se agregó a la función de paso de mi animación, pero estaba preocupado por el rendimiento y busqué otras opciones.

En mi circunstancia, el elemento que no estaba repintando estaba dentro de un elemento de posición absoluta que, en ese momento, no tenía un índice z. Agregar un índice z a este elemento cambió el comportamiento de Chrome y los repintados se realizaron como se esperaba: las animaciones se volvieron suaves.

Dudo que esto sea una panacea, imagino que depende de por qué Chrome ha elegido no volver a dibujar el elemento, pero estoy publicando esta solución específica aquí en la ayuda que espera a alguien.

Saludos, Rob

tl; dr >> Intente agregar un índice z al elemento o a uno de sus padres.

Los siguientes trabajos. Solo tiene que establecerse una vez en CSS puro. Y funciona de manera más confiable que una función JS. El rendimiento no se ve afectado.

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

Por alguna razón no pude hacer que la respuesta de Danorton funcionara, pude ver lo que se suponía que debía hacer, así que lo puse un poco en esto:

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

Y funcionó para mí.

Me encontré con esto hoy: Element.redraw () para prototype.js

Utilizando:

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

Sin embargo, he notado a veces que debes llamar a redraw () directamente sobre el elemento problemático. A veces, volver a dibujar el elemento principal no resolverá el problema que está experimentando el niño.

Buen artículo sobre la forma en que los navegadores rinden elementos: Rendering: repaint, reflow / relayout, restyle

Vine aquí porque necesitaba volver a dibujar las barras de desplazamiento en Chrome después de cambiar su CSS.

Si alguien tiene el mismo problema, lo resolví llamando a esta función:

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

Este método no es la mejor solución, pero puede funcionar con todo, ocultar y mostrar el elemento que debe volver a dibujarse puede resolver todos los problemas.

Aquí está el violín donde lo usé: http://jsfiddle.net/promatik/wZwJz/18/

Tuve este problema con un número de divs que se insertaron en otro div con position: absolute , los divs insertados no tenían ningún atributo de posición. Cuando cambié esto a position:relative funcionó bien. (fue realmente difícil identificar el problema)

En mi caso, los elementos fueron insertados por Angular con ng-repeat .

No puedo creer que esto siga siendo un problema en 2014. Acabo de tener este problema al actualizar un cuadro de subtítulos de posición fija en la esquina inferior izquierda de la página mientras se desplaza, el título “fantasma” en la pantalla. Después de probar todo lo anterior sin éxito, noté que muchas cosas eran lentas o causaban problemas debido a la creación de retransmisiones de DOM muy cortas, etc., lo que causaba una sensación un tanto antinatural al desplazarse, etc.

Terminé creando una posición fija, div completo con pointer-events: none y aplicando la respuesta de danorton a ese elemento, lo que parece forzar un redibujado en toda la pantalla sin interferir con el 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'; 

No es que esta pregunta necesite otra respuesta, pero descubrí que simplemente cambiando el color por un solo bit forzaba un repintado en mi situación particular.

 //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); 

El setTimeout resultó crítico para mover el segundo cambio de estilo fuera del bucle de evento actual.

La única solución que funciona para mí es similar a la respuesta de sowasred2012:

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

Tengo muchos bloques problemáticos en la página, así que cambio la propiedad de display del elemento raíz. Y uso display: table; en lugar de display: none; , porque none restablecerá el desplazamiento de desplazamiento.

Como todos parecen tener sus propios problemas y soluciones, pensé que agregaría algo que me funciona. En Android 4.1 con Chrome actual, tratando de arrastrar un canvas dentro de un div con overflow: oculto, no pude obtener un redibujado a menos que añadiera un elemento al div principal (donde no causaría ningún daño).

 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); } 

Sin parpadeo de pantalla o actualización real, y limpieza después de mí. No hay variables de ámbito global o de clase, solo locales. No parece herir nada en Mobile Safari / iPad o navegadores de escritorio.

Estoy trabajando en la aplicación iónica html5, en algunas pantallas tengo absolute elemento de posición absolute , cuando me muevo hacia arriba o hacia abajo en dispositivos IOS (iPhone 4,5,6, 6+) tuve un error de repintado.

Intenté muchas soluciones, ninguna de ellas funcionaba, excepto que esta solucionó mi problema.

He usado css class .fixRepaint en esos elementos de posiciones absolutas

 .fixRepaint{ transform: translateZ(0); } 

Esto ha solucionado mi problema, puede ayudar a alguien

Esto está bien para JS

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

Pero en Jquery, y particularmente cuando solo puede usar $ (document) .ready y no puede vincularse a un evento .load de un objeto por algún motivo en particular, lo siguiente funcionará.

Necesitas obtener el contenedor EXTERIOR (MÁS) de los objetos / divs y luego eliminar todo su contenido en una variable, luego volver a agregarlo. Hará visibles TODOS los cambios realizados dentro del contenedor externo.

 $(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); } 

He encontrado que este método es útil cuando se trabaja con transiciones

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

el truco “display / offsetHeight” no funcionó en mi caso, al menos cuando se aplicó al elemento animado.

Tenía un menú desplegable que se abría / cerraba sobre el contenido de la página. los artefactos se dejaban en el contenido de la página después de que el menú se cerró (solo en navegadores webkit). la única forma en que el truco “display / offsetHeight” funcionó es si lo apliqué al cuerpo, lo cual parece desagradable.

sin embargo, encontré otra solución:

  1. antes de que el elemento comience a animarse, agregue una clase que defina “-webkit-backface-visibility: hidden;” en el elemento (también se podría usar el estilo en línea, supongo)
  2. cuando haya terminado de animar, elimine la clase (o estilo)

esto todavía es bastante hacky (usa una propiedad CSS3 para forzar el procesamiento de hardware), pero al menos solo afecta al elemento en cuestión, y funcionó para mí tanto en safari como en Chrome para PC y Mac.

Esto parece estar relacionado con esto: el estilo jQuery no se aplica en Safari

La solución sugerida en la primera respuesta me ha funcionado en estos escenarios, a saber: aplicar y eliminar una clase ficticia para el cuerpo después de realizar los cambios de estilo:

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

Esto obliga a safari a redibujar.

las sugerencias anteriores no funcionaron para mí. pero el de abajo sí.

Desea cambiar el texto dentro del ancla dinámicamente. La palabra “Buscar”. Creado una etiqueta interna “fuente” con un atributo de id. Gestioné los contenidos usando javascript (abajo)

 Buscar

contenido de 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); } 

Estaba teniendo un problema con un SVG que desaparecía en Chrome para Android cuando se cambiaba la orientación en determinadas circunstancias. El siguiente código no lo reproduce, pero es la configuración que teníamos.

 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 ultricies. Curabitur tristique 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.

Recomendaría una forma menos formal y más hackish para forzar un reflujo: use forceDOMReflowJS . En su caso, su código se verá de la siguiente manera.

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

Una solución simple con jquery:

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

o

 element.innerHTML = element.innerHTML; 

Tenía un SVG que no se mostraba cuando se agregaba al html.

Esto se puede agregar después de que los elementos svg estén en la pantalla.

Mejor solución es usar:

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

y con jQuery:

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

esto se renderizará correctamente en Chrome.