Developing for IE8: inline-block resize bug


At Caplin we don’t need to support the ancient Internet Explorer 6 & 7 browsers, which makes development a lot easier, but IE8 still has some bugs to make life difficult. On a recent project we found an annoying one affecting inline-block elements, where IE8 refuses to repaint the layout and update the size of the element when it’s changed.

My div’s not resizing!

One of the motivations for writing this post was that when I was trying to figure out why we were seeing the problem, I read a lot of posts from people complaining that elements weren’t resizing properly, but nobody seemed to know why. There was also some misinformation out there; some people thought that IE8 didn’t support inline-block. While this was certainly true of IE6/7, I’ve found that IE8 generally supports it quite well; you just have to know how to handle these odd bugs.

The problem is that if the size of any element more than one level deep inside an inline-block element changes size IE8 will change the size of the inline-block element to contain the resized element, but it wont affect any of the elements around it! This is better shown with a few examples (of course, you should open the JSFiddle links below in IE8 to see the bug in action).

The basic setup is that we have rows of squares on the screen, all laid out using inline-block. When you click a square it will expand an “expandable” child element of the square to double height, increasing the size of the square and pushing the squares in the row below out of the way:

HTML

<div>
    <div class="square">
        <div class="expandable"></div>
    </div>
    <div class="square">
        <div class="expandable"></div>
    </div>
    ...
</div>

JavaScript

function expandElement(e) {
    $(this).toggleClass("expanded");
}

$(".expandable").click(expandElement);

CSS

.square {
    display: inline-block;
    vertical-align: top;
    background: green;
    border: 1px solid black;
    margin: 5px;
}
.expandable {
    height: 50px;
    width: 50px;
}
.expandable.expanded {
    height: 100px;
}

In this situation it works fine, as the child element we’re expanding is the direct child of the inline-block element. But what if we move the expanding element further down the tree?

<div>
    <div class="square">
        <!-- New div to push the expandable element down the DOM -->
        <div>
            <div class="expandable"></div>
        </div>
    </div>
    <div class="square">
        <!-- New div to push the expandable element down the DOM -->
        <div>
            <div class="expandable"></div>
        </div>
    </div>
    ...
</div>

Capture

Now we start to see a problem. IE8 adjusts the size of the square correctly, but it doesn’t push the squares in the row below out of the way like before. For some reason it doesn’t process that the size of the square element has changed and that it needs to repaint. If you resize the window while it’s in this broken state, IE8 will realise that something’s changed and will repaint everything correctly.

Avoiding the issue

This seems to be a genuine IE8 rendering bug so I don’t think there’s a proper “fix”, but there are some things we can do to work around it. The simplest thing would be to avoid using inline-block in the first place, or to remove the extra layers of elements between the inline-block and your expanding element (like the first example on the page), but these aren’t always possible.

One suggestion I’ve seen is to write some JavaScript that toggles a class on/off on the inline-block element; this will force IE8 to repaint everything to account for the class change. However we weren’t happy with this; what we really wanted was something that didn’t rely on some more JavaScript running every time our elements changed size.

We came up with our solution when we noticed that this bug only occurs when you’re dealing with block level elements; if you change the extra divs we added in the second example to spans the issue disappears! If you don’t want to use spans you can achieve the same result by setting the divs to use display: inline or inline-block. Only the elements on the way down the chain to the element changing size need to be changed – the actual expandable element is fine as a block.

This might not be appropriate for everyone – sometimes you’re using display: block for a reason – but in our situation it didn’t matter which we used and it moved the fix entirely into the CSS, making use of IE8′s native rendering engine rather than requiring additional JavaScript processing.

Related Posts with Thumbnails

5 Comments

  • Dan says:

    Thank you so much for posting this. I thought I was going crazy :)

  • Olivier BOISSIN says:

    Dude I spent hours & hours on such an issue.
    Thank you for your blog post that helps me to find a solution

  • Randy Fyfe says:

    I just came across this issue and fixed it by toggling a class to force a repaint. It seems like it does not need to be the div that is set to inline-block that needs the class to be toggled on; it seems to work when I go to a higher up parent, so I am toggling a dummy class on body using javascript.

  • Casper says:

    Thanks for the post. Help me solve this annoying bug.

    Similar to Randy’s I solved it by just setting and removing a css property on body. I using height, but it seems that any property will do the trick.

    $(‘body’).css(‘height’, ‘auto’).css(‘height’, ”);

    http://jsfiddle.net/casperskovgaard/3AD8w/10/

  • bydgoszcz says:

    Itts like youu rezd my mind! You appear tto now sso much abot this,
    like you wrote tthe book in it oor something. I think that you can do with sme
    pics to drive the message home a llittle bit, but other thqn that, this is fantastic blog.
    A fantastic read. I’ll certainly be back.

Leave a Comment

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Anti-spam image