I have some trivial JavaScript to effect a style change:
sel = document.getElementById('my_id');
sel.className = sel.className.replace(/item-[1-9]-selected/,'item-1-selected');
return false;
This works fine with the latest versions of FF, Opera and IE, but fails on the latest versions of Chrome and Safari.
It affects two descendants, which happen to be siblings. The first sibling updates, but the second doesn’t. A child of the second element also has focus and contains the <a> tag that contains the above code in an onclick attribute.
In the Chrome “Developer Tools” window if I nudge (e.g. uncheck & check) any attribute of any element, the second sibling updates to the correct style.
Is there a workaround to easily and programmatically “nudge” WebKit into doing the right thing?
I cannot believe this is still a problem in 2014. I just had this issue when refreshing a fixed position caption box on the lower-left hand of the page while scrolling, the caption would 'ghost' its way up the screen. After trying everything above without success, I noticed a lot of things were either slow/causing issues due to creating very short DOM relayouts etc causing somewhat unnatural feeling scrolling etc...
I ended up making a fixed position, full-size div with
pointer-events: none
and applying danorton's answer to that element, which seems to force a redraw on the whole screen without interfering with the DOM.HTML:
CSS:
JS:
We recently encountered this and discovered that promoting the affected element to a composite layer with translateZ in CSS fixed the issue without needing extra JavaScript.
As these painting issues show up mostly in Webkit/Blink, and this fix mostly targets Webkit/Blink, it's preferable in some cases. Especially since the accepted answer almost certainly causes a reflow and repaint, not just a repaint.
Webkit and Blink have been working hard on rendering performance, and these kinds of glitches are the unfortunate side effect of optimizations that aim to reduce unnecessary flows and paints. CSS will-change or another succeeding specification will be the future solution, most likely.
There are other ways to achieve a composite layer, but this is the most common.
Since the display + offset trigger didn't work for me, I found a solution here:
http://mir.aculo.us/2009/09/25/force-redraw-dom-technique-for-webkit-based-browsers/
i.e.
I stumbled upon this today: Element.redraw() for prototype.js
Using:
However, I've noticed sometimes that you must call redraw() on the problematic element directly. Sometimes redrawing the parent element won't solve the problem the child is experiencing.
Good article about the way browsers render elements: Rendering: repaint, reflow/relayout, restyle
I found some complicated suggestions and many simple ones that didn’t work, but a comment to one of them by Vasil Dinkov provided a simple solution to force a redraw/repaint that works just fine:
I’ll let someone else comment if it works for styles other than “block”.
Thanks, Vasil!
For some reason I couldn't get danorton's answer to work, I could see what it was supposed to do so I tweaked it a little bit to this:
and it worked for me.