IE alpha / overflow hidden bug

By

I ran into an interesting bug in Internet Explorer 8 and lower recently. If an element has a Microsoft CSS filter, like -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=50)", then overflow: visible doesn’t work.

On the Radisson Blu design holiday site, we have a series of photos which can be filtered down using the excellent jQuery plugin Isotope. When you hover your cursor over a photo, it expands to reveal a larger picture and some information about the hotel. This effect is achieved with some simple CSS:
.hotel { overflow: hidden; z-index: 50; }
.hotel:hover { overflow: visible; z-index: 60; }

The hover state worked fine when the page was first loaded in IE, but after you applied some Isotope filters, the bug would occur and the hover state would look this this:

The reason this was happening was that IE8 doesn’t support CSS3 transitions, so Isotope falls back to plain old jQuery animations to fade the images in and out. Of course, IE8 doesn’t support the standard CSS opacity property either, so jQuery applies a Microsoft alpha filter to achieve the fade. And that’s when things go downhill. Even after the fade animation had finished, the hover state of the photos was still being cut off. The Microsoft filter does something to the elements which prevents overflow: visible from working. Fortunately, once you remove that filter, the elements behave normally again.

For the hotel site, we only needed opacity during animations, not after, so the solution was to disable filters when the hover state was applied. For IE8 we applied this CSS:
.ie8 .hotel:hover { -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(enabled=false)" !important; }

And for IE7 and older, we applied this CSS:
.lte7 .hotel:hover { filter: "progid:DXImageTransform.Microsoft.Alpha(enabled=false)" !important; }

We don’t want to remove filters from items that have been filtered out by Isotope, so we also need to apply the following CSS to undo our fix when items have a class of isotope-hidden:
.ie8 .isotope-hidden:hover { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=0)" !important; }
.lte7 .isotope-hidden:hover { filter: alpha(opacity=0) !important; }

You should normally avoid using !important statements in your CSS, and instead write a selector with a high enough specificity, but in this scenario they are required because we need to override the inline styles that are applied by the Isotope plugin.

So that’s how we got around the “alpha / overflow hidden” bug. Unfortunately I can’t offer any explanation as to why it happens, so if you have more information, please share!

Note: The .ie8 and .lte7 classes are Paul Irish’s conditional classnames idea and a part of the rock solid HTML5 boilerplate.

This entry was tagged with Web development. Bookmark the permalink.

Comments

  1. By prototypr

    I was going to say more on twitter, but kind of ran out of characters :P

    IE filters have just about driven me insane in the past and I now try to avoid them if possible. I honestly don’t know this particular problem happens, but I’ve found filter-related problems in IE<9 are usually caused by either hasLayout issues or the underlying DirectX rendering system which filters are based on.

    IE9 left the IE8,7+6 engines in for compatibility, they couldn't remove the hasLayout concept in those modes because it'd break too many websites. IE9 in IE8 compatibility mode interestingly didn't have the `overflow: visible` cutoff problem which IE8 did before though. With the new hardware accelerated Direct2D engine, IE9 rewrote the overall renderer, and I think the DirectX filter renderer has been totally rewritten.

    What I think happens in IE<9 is it "designates" a square where DirectX can render on top of a hasLayout box based on `width`+`height` properties, and if content tries to expand outside that box then it'll be cut off. I think that in block elements which have filters in them that everything in them is also rendered by DirectX. (As a side effect which you may already be aware of, text rendered by DirectX wasn't ClearType aware and so in particular bolded text rendered garbled in IE6, leading to the devs to turn off ClearType entirely in filtered elements in IE7-8.)

    As a workaround, I've found that putting the filter style into a separate absolutely-positioned DIV inside a relatively-positioned container can work. The content then goes inside the filter DIV. This makes it so that the element with a DirectX filter can expand outside the container when the container's overflow is set to `visible` I think because the drawing outside the boundary is not done by the filter's DirectX renderer where it'd get chopped off but using IE's normal GDI renderer: http://jsfiddle.net/bcAa3/8/

Leave a Reply