Come posso forzare WebKit a ridisegnare / ridisegnare per propagare le modifiche allo stile?

Ho alcuni JavaScript banali per effettuare un cambio di stile:

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

Funziona bene con le ultime versioni di FF, Opera e IE, ma non funziona sulle ultime versioni di Chrome e Safari.

Colpisce due discendenti, che capita di essere fratelli. Il primo fratello aggiorna, ma il secondo no. Anche un elemento figlio del secondo elemento è attivo e contiene il tag che contiene il codice sopra riportato in un attributo onclick .

Nella finestra “Strumenti di sviluppo” di Chrome, se spingo (ad es. Deseleziona e spunta) qualsiasi attributo di qualsiasi elemento, il secondo fratello aggiorna lo stile corretto.

C’è una soluzione alternativa per “spingere” WebKit in modo semplice e programmatico nel fare la cosa giusta?

Ho trovato alcuni suggerimenti complicati e molti semplici che non hanno funzionato, ma un commento ad uno di loro di Vasil Dinkov ha fornito una soluzione semplice per forzare un ridisegno / ridisegno che funzioni bene:

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

Lascerò che qualcun altro faccia commenti se funziona per stili diversi da “blocco”.

Grazie, Vasil!

Di recente l’abbiamo riscontrato e abbiamo scoperto che la promozione dell’elemento interessato in un livello composito con translateZ in CSS ha risolto il problema senza richiedere JavaScript aggiuntivo.

 .willnotrender { transform: translateZ(0); } 

Poiché questi problemi di verniciatura si presentano principalmente in Webkit / Blink e questa correzione si rivolge principalmente a Webkit / Blink, in alcuni casi è preferibile. Soprattutto dal momento che la risposta accettata quasi certamente causa un ristream e un ridipinto , non solo un ridipinto.

Webkit e Blink hanno lavorato duramente al rendering delle prestazioni e questo tipo di problemi sono il sfortunato effetto collaterale delle ottimizzazioni che mirano a ridurre flussi e vernici non necessari. Il CSS cambierà o un’altra specifica successiva sarà la soluzione futura, molto probabilmente.

Ci sono altri modi per ottenere uno strato composito, ma questo è il più comune.

la soluzione danorton non ha funzionato per me. Ho avuto alcuni problemi davvero strani in cui il webkit non disegnava alcun elemento; dove il testo in input non è stato aggiornato fino a onblur; e cambiando className non si otterrebbe un ridisegno.

La mia soluzione, ho scoperto per caso, era di aggiungere un elemento di stile vuoto al corpo, dopo lo script.

  ...   ... 

Questo l’ha risolto. Quanto è strano? Spero che questo sia utile per qualcuno.

Poiché il trigger display + offset non ha funzionato per me, ho trovato una soluzione qui:

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

vale a dire

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

Stavo soffrendo lo stesso problema. la correzione di ‘toggling display’ di danorton ha funzionato per me quando aggiunta alla funzione step della mia animazione, ma ero preoccupato per le prestazioni e ho cercato altre opzioni.

Nella mia circostanza l’elemento che non era ridipingere era all’interno di un elemento assolutamente di posizione che non aveva, al momento, uno z-index. L’aggiunta di uno z-index a questo elemento ha cambiato il comportamento di Chrome e i rimborsi sono avvenuti come previsto -> le animazioni sono diventate fluide.

Dubito che questa sia una panacea, immagino dipenda il motivo per cui Chrome ha scelto di non ridisegnare l’elemento ma sto postando questa soluzione specifica qui nell’aiuto che spera qualcuno.

Saluti, Rob

tl; dr >> Prova ad aggiungere uno z-index all’elemento o a un genitore di esso.

I seguenti lavori. Deve essere impostato solo una volta in puro CSS. E funziona in modo più affidabile di una funzione JS. Le prestazioni sembrano inalterate.

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

Per qualche motivo non sono riuscito a far funzionare la risposta di danorton, ho potuto vedere cosa avrebbe dovuto fare, quindi l’ho ottimizzato un po ‘su questo:

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

e ha funzionato per me.

Oggi mi sono imbattuto in questo: Element.redraw () per prototype.js

usando:

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

Tuttavia, a volte ho notato che devi chiamare redraw () direttamente sull’elemento problematico. A volte il ridisegno dell’elemento genitore non risolverà il problema che il bambino sta vivendo.

Buon articolo sul modo in cui i browser eseguono il rendering degli elementi: Rendering: repaint, reflow / relayout, restyle

Sono venuto qui perché avevo bisogno di ridisegnare le barre di scorrimento in Chrome dopo aver cambiato il suo css.

Se qualcuno ha lo stesso problema, l’ho risolto chiamando questa funzione:

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

Questo metodo non è la soluzione migliore, ma può funzionare con qualsiasi cosa, nascondendo e mostrando l’elemento che deve essere ridisegnato può risolvere ogni problema.

Ecco il violino dove l’ho usato: http://jsfiddle.net/promatik/wZwJz/18/

Ho avuto questo problema con un numero di div che sono stati inseriti in un altro div con position: absolute , i div inseriti non avevano attributo di posizione. Quando ho cambiato questo in position:relative ha funzionato bene. (era davvero difficile individuare il problema)

Nel mio caso gli elementi sono stati inseriti da Angular con ng-repeat .

Non posso credere che questo sia ancora un problema nel 2014. Ho appena avuto questo problema durante l’aggiornamento di una casella di didascalia della posizione fissa nella parte in basso a sinistra della pagina durante lo scorrimento, la didascalia sarebbe “fantasma” verso l’alto sullo schermo. Dopo aver provato tutto senza successo, ho notato che molte cose erano lente / causavano problemi a causa della creazione di relayout DOM molto brevi ecc. Causando un po ‘di scorrimento innaturale, ecc …

Ho finito per creare una posizione fissa, div full-size con pointer-events: none e applicando la risposta di danorton a quell’elemento, che sembra forzare un ridisegno su tutto lo schermo senza interferire con il 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 che questa domanda abbia bisogno di un’altra risposta, ma ho trovato semplicemente cambiare il colore di un singolo bit costringendo un ridipingere nella mia particolare situazione.

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

Il setTimeout si è rivelato fondamentale per spostare la seconda modifica di stile al di fuori del loop di eventi corrente.

L’unica soluzione per me è simile alla risposta di sowasred2012:

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

Ho un sacco di blocchi di problemi sulla pagina, quindi cambio la proprietà di display dell’elemento root. E io uso display: table; invece di display: none; , perché none ripristinerà l’offset di scorrimento.

Dal momento che tutti sembrano avere i propri problemi e soluzioni, ho pensato di aggiungere qualcosa che funzioni per me. Su Android 4.1 con Chrome corrente, cercando di trascinare una canvas all’interno di un div con overflow: nascosto, non ho potuto ottenere un ridisegno a meno che non ho aggiunto un elemento al div genitore (dove non avrebbe fatto alcun danno).

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

Nessuno sfarfallio dello schermo o vero aggiornamento e pulizia dopo me stesso. Nessuna variabile globale o di class, solo i locali. Sembra non danneggiare nulla su Mobile Safari / iPad o browser desktop.

Sto lavorando all’applicazione ionic html5, su alcuni schermi ho absolute elemento posizionato in absolute , quando scorri verso l’alto o il basso nei dispositivi IOS (iPhone 4,5,6, 6+) ho avuto un bug di ridisegno.

Ho provato molte soluzioni che nessuno di loro funzionava, tranne che questo risolve il mio problema.

Ho usato la class CSS .fixRepaint su quegli elementi di posizioni assolute

 .fixRepaint{ transform: translateZ(0); } 

Questo ha risolto il mio problema, potrebbe essere d’aiuto qualcuno

Questo va bene per JS

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

Ma in Jquery, e in particolare quando puoi usare solo $ (document) .ready e non puoi associare a un evento .load di un object per un motivo particolare, funzionerà il seguente.

È necessario ottenere il contenitore OUTER (MOST) degli oggetti / div e quindi rimuovere tutti i suoi contenuti in una variabile, quindi aggiungerlo di nuovo. Renderà TUTTE le modifiche fatte all’interno del contenitore esterno visibili.

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

Ho trovato questo metodo utile quando si lavora con le transizioni

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

l’hack “display / offsetHeight” non ha funzionato nel mio caso, almeno quando è stato applicato all’elemento animato.

avevo un menu a tendina aperto / chiuso sul contenuto della pagina. gli artefatti venivano lasciati sul contenuto della pagina dopo la chiusura del menu (solo nei browser Webkit). l’unico modo con cui ha funzionato “display / offsetHeight” è se l’ho applicato al corpo, il che sembra brutto.

tuttavia, ho trovato un’altra soluzione:

  1. prima che l’elemento inizi ad animare, aggiungi una class che definisca “-webkit-backface-visibility: hidden;” sull’elemento (potresti usare anche lo stile in linea, direi)
  2. quando ha finito di animare, rimuovi la class (o lo stile)

questo è ancora piuttosto hacky (usa una proprietà CSS3 per forzare il rendering hardware), ma almeno riguarda solo l’elemento in questione, e ha funzionato per me sia su Safari che su Chrome su PC e Mac.

Ciò sembra correlato a questo: lo stile jQuery non viene applicato in Safari

La soluzione suggerita nella prima risposta ha funzionato bene in questi scenari, vale a dire: applicare e rimuovere una class fittizia sul corpo dopo aver apportato le modifiche allo stile:

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

Questo costringe il safari a ridisegnare.

i suggerimenti sopra non hanno funzionato per me. ma quello sotto fa.

Vuoi cambiare il testo all’interno dell’ancora in modo dinamico. La parola “Cerca”. Creato un tag interno “font” con un attributo id. Gestito il contenuto utilizzando javascript (sotto)

 Ricerca

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

Stavo avendo un problema con un file SVG che stava scomparendo su Chrome per Android quando l’orientamento è stato modificato in determinate circostanze. Il seguente codice non lo riproduce, ma è il setup che avevamo.

 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.

Consiglierei un modo meno formale e più formale di forzare un reflow: usa forceDOMReflowJS . Nel tuo caso, il tuo codice apparirebbe come segue.

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

Una soluzione semplice con jquery:

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

o

 element.innerHTML = element.innerHTML; 

Aveva un SVG che non veniva mostrato quando è stato aggiunto all’html.

Questo può essere aggiunto dopo che gli elementi svg sono sullo schermo.

La soluzione migliore è usare:

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

e con jQuery:

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

questo verrà visualizzato correttamente su Chrome.