Skip to content

Instantly share code, notes, and snippets.

@madrobby
Created November 13, 2011 13:04
Show Gist options
  • Save madrobby/1362093 to your computer and use it in GitHub Desktop.
Save madrobby/1362093 to your computer and use it in GitHub Desktop.
Force rendering a DOM element when Webkit is acting up
forceRerenderOnWebkit: ->
@el.parentNode.style.cssText += ';-webkit-transform:rotateZ(0deg)'
@el.parentNode.offsetHeight
@el.parentNode.style.cssText += ';-webkit-transform:none'
@madrobby
Copy link
Author

The concat works on any browser, not just Webkit, it just silently fails. I need to repaint because I've stumbled upon some rendering glitches with Webkit (the repaint forces the element to be correctly rendered).

@helgri
Copy link

helgri commented Nov 13, 2011

isn't any 3d transform forcing a re-rendering 'cause the element is transmitted to the gpu?

@madrobby
Copy link
Author

@helgri yeah, but it need to be flipped on, rendered once (the offsetHeight forces a recalculation/repaint) and then switched off again so you can use it more than once on a given element. you can even use "normal" CSS properties, like "height" for example, or you could toggle "display". I choose this because I know that I won't use it for this particular element, and so I don't need to store the old value, etc.

I was wondering more if there's an approach where I don't need to mess with CSS at all.

@WebReflection
Copy link

Node.prototype.repaint = function () {
    var
        offsetHeight = "offsetHeight",
        parentNode = this.parentNode
    ;
    return parentNode && (offsetHeight in parentNode) ?
        parentNode[offsetHeight] :
        this[offsetHeight]
    ;
};

@helgri
Copy link

helgri commented Nov 13, 2011

I see... and the rotation value works for you, because you know, that you don't use it. in other sites this may break...

you could also add/remove a .repaint class (with your rule), than it's also not necessary to store old values.

so best solution would be to avoid dom operations at all... what about adding/removing a css rule for the element to the stylesheet doc via javascript? won't touch the dom.

@KrofDrakula
Copy link

Have you tried modifying the class name and/or id? It worked for me on several occasions, eg. forcing iOS 5 to render position:fixed iframes whine scrolling. Any change triggered a rerender, so appending a bogus class or assigning to the id worked.

@bundyo
Copy link

bundyo commented Nov 14, 2011

Should be enough to get the computed style of the element to force a repaint.

@gr2m
Copy link

gr2m commented Nov 15, 2011

I don't have a better solution, but your suggestion just fixed a bug I had in Opera. Thanks :-)

@gr2m
Copy link

gr2m commented Nov 15, 2011

I also found this plugin:
http://plugins.jquery.com/files/jquery.forceredraw-1.0.3.js_.txt

It confirms @KrofDrakula's suggestion for most cases but also has a "brutal" fallback where it changes CSS as you do in your suggestion, just using a 1ms timeout before it changes it back

@KrofDrakula
Copy link

@gr2m: It would seem the "brutal" version here changing the padding seems a bit overkill; I use the following code for a rock solid repaint:

function forceRedraw(el) {
  var t = el.ownerDocument.createTextNode(' ');
  el.appendChild(t);
  setTimeout(function() { el.removeChild(t); }, 0);
}

@helgri
Copy link

helgri commented Nov 15, 2011

@gr2m damn, i just suggested a class named "repaint", not "redraw" ;)

but i still favor a solution which doesn't need to touch the dom at all

@nuragic
Copy link

nuragic commented Jun 10, 2014

Hi guys! Thanks to all for the suggestions... So, anyone know what is the most optimal way to force a reflow? Any jsPerf there? :)

@digitalicarus
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment