20

In ie8 if elements don't 'repaint' with the associated css when you change the classname, how can you force the browser to refresh and not kill ie8 performance?

This post (How can I force WebKit to redraw/repaint to propagate style changes?) suggested calling offsetHeight which forces a repaint.

This post (http://www.tek-tips.com/viewthread.cfm?qid=1688809) had a comment that suggested adding and removing a class from body element.

Both of these approaches killed ie8 performance and the first had side-effects on my layout.

What's the best approach?

Community
  • 1
  • 1
Doug
  • 2,242
  • 2
  • 20
  • 16

6 Answers6

24

The solution I came up with for my ie8 issue was to add/remove a class on a near parent of the element i'm changing. Since I'm using modernizer, I check for ie8 and then do this add/remove dance to get the new css to paint.

        $uicontext.addClass('new-ui-look');
        if ($('html').is('.ie8')) {
            // IE8: ui does not repaint when css class changes
            $uicontext.parents('li').addClass('z').removeClass('z');
        }
Doug
  • 2,242
  • 2
  • 20
  • 16
  • I've observed that IE8 seems to slow down based on the number of elements and the number of attached events you have in the DOM. Also, discovered that attribute selector is faster in event handlers, e.g. `[some-attr]` is better than `.some-class`. – Doug Dec 10 '12 at 21:34
  • 2
    I'd say `$(el).parent().addClass('forceiepaint').removeClass('forceiepaint')` – abernier Apr 22 '14 at 15:18
  • 1
    After banging my head against IE8, and trying various hacks I found online, this one finally fixed my layout weirdness! – Elbin Oct 09 '14 at 12:11
  • I cannot get anything to work, including this. Very frustrating. – Michael Giovanni Pumo Mar 11 '15 at 11:38
  • @MichaelGiovanniPumo have you tried the other solutions in this post. If that does not work, make sure to jslint/hint your code. I had an infuriating ie8 bug that magically went away after making my code lint free. Just a thought. – Doug Mar 12 '15 at 12:41
  • @Doug - I fixed my issue. I was setting opacity and visibility properties. Adding a class to toggle these. However, IE8 wasn't setting these properly when the class was added or removed. After removing the 'visibility' property and only using opacity with an offset 'top' (to hide the element) instead, it worked. In short; IE8 seems to have an issue with the visibility property in CSS when adding a class. After this, I didn't need to use the script above, as it just worked. No forced repaint needed. – Michael Giovanni Pumo Mar 12 '15 at 13:30
9

The correct answer to this question is that you need to actually change the content rule.

.black-element:before { content:"Hey!"; color: #000;}
.red-element:before { content:"Hey! "; color: #f00;}

Notice the extra space I added after Hey! on .red-element

Adam Jenkins
  • 51,445
  • 11
  • 72
  • 100
6

Ridiculously, this works:

function ie8Repaint(element) {
    element.html(element.html().replace('>', '>'));
}

Nothing actually changes in the DOM so it won't affect any other browsers.

user489998
  • 4,473
  • 2
  • 29
  • 35
2

Fire a move or resize event on it.

var ie8 = whateverYouUseToDetectIE();
var element = document.getElementById("my-element");
element.className += " new-class";
if (ie8) {
    element.fireEvent("resize");
}
webaware
  • 2,795
  • 2
  • 30
  • 37
  • I just tried that and behavior is not as eloquent as the add/remove class on near parent. Not all events got the repaint. The add/remove class seems to repaint all events no matter how fast I invoke them. In my case, mouseenter/leave events. – Doug Dec 09 '12 at 20:49
1

This expands on the other answers here. You need to both add a new class (Doug's answer) and ensure the class has a different content value (Adam's answer). Changing the class alone may not be enough. The content change is needed to force IE8 to repaint. Here is a related blog post.

Here is the JQuery to change add the new class:

$(".my-css-class").addClass("my-css-class2");

Here is CSS with the 2nd class having a slightly different content value:

.my-css-class:before {content: "\e014";}
.my-css-class2:before {content: "\e014 ";}
James Lawruk
  • 30,112
  • 19
  • 130
  • 137
0

I had a lot of difficulty and tried everything to no avail...until I tried this for IE8

function toggleCheck(name) {
  el = document.getElementById(name);
  if( hasClass(el, 'checked') ) {
    el.className = el.className.replace(/checked/,'unchecked');
  } else if( hasClass(el, 'unchecked') ) {
    el.className = el.className.replace(/unchecked/,'checked');
  }
  document.body.className = document.body.className;
}
function hasClass(element, cls) {
  return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}

And now my CSS changes for my checkboxes work beautifully for IE8, Chrome, and Firefox!

Urchin
  • 395
  • 3
  • 9