Friday, August 14, 2009

Using CSS3 box-shadow with IE

At YayArt, we show a lot of images. An important part of the presentation is subtle drop shadows.

My original solution to that problem was a Javascript hack that inserts a couple of 1 pixel wide divs at the edge of any element with a shadow class. However, although I have tweaked it several times, it has always been a bit slow. For instance, for the shop front page we're currently rendering more than 60 elements with shadows which takes a couple of seconds with Firefox and Firebug on my old trusty PIII 950 MHz laptop. I'll note that this is actually an order of magnitude faster than the (more general) code I based it on from somewhere else. The really tricky part was decent-speed IE 6 support because that actually required measuring the DOM elements.

However, Firefox 3.5 was released about a month ago, and one of the good news was support for the box-shadow CSS3 property. It's a relatively simple property for adding drop shadows. So given that Safari has it, and has had for some time, and most Firefox users will soon have it, it starts getting interesting. For reference, about half of our visitors are Firefox + Safari (+ Chrome which uses the same rendering engine as Safari).

If you search for box-shadow, some are already using it to add a bit of extra embellishment. However, on YayArt, it's an integrated part of the design. So I had to figure out how to make it work on all browsers.

I ended up with a three-way solution. For recent Firefox/Safari/... I use box-shadow. For non-box-shadow supporting browsers, I fallback to the old hack. And for Internet Explorer, I'm using a new hack based on the proprietary filter stuff in IE.

Here's a quick sketch. I put this in the general stylesheet:
.shadowed {
-moz-box-shadow: 2px 2px 3px #969696;
-webkit-box-shadow: 2px 2px 3px #969696;
}
This makes it work with browsers based on the Gecko and Webkit engines. Some people recommend adding a plain box-shadow line, but I need full control over which browsers are responding, and besides it seems to defeat the purpose of the browsers using the -engine- prefix. Here's a demo:

If your browser is recent enough, you can see a shadow here.

Now for the fallback, I need to discover in Javascript whether the browser is using the CSS:
function supportsBoxShadow() {
var s = document.body.style;
return s.WebkitBoxShadow !== undefined || s.MozBoxShadow !== undefined;
}
The assumption is that the symbols will be defined only if the browser actually draws the shadow. This seems to be about right, the only exception I've found so far is the Webkit port to GTK (there's a bug report open).

Final point is Internet Explorer. As it turns out, there is a DropShadow filter. It's not terrible useful for this purpose, however. There are no soft edges, and it shadows the content rather than the containing box (it simply redraws the content with an offset in another color). So for my purpose I need to set a background color to ensure it's drawing a rectangle and not a text shadow. You could probably hack the lack of blurring with another filter, but in the end I went with a simple three-one-pixel-wide-lines approach that looks like my old hack but is much faster (updated, replaced the filter with a more appropriate one as suggested in the comments):
.shadowed {
background-color: #fff;
zoom: 1;
filter: progid:DXImageTransform.Microsoft.Shadow(color='#969696', Direction=135, Strength=3);
}
This is served for IE only. The zoom: 1 is a hack to ensure that the element gets a layout (to work around the usual IE 6 bug).

So there you have it. Practical drop shadows. I will have to adjust the code a little bit as the other browsers get support, but I can live with that.

55 comments:

  1. Man, this is amazing!!! Realy amazing!!! This is the best solution and work´s fine!!!

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. I like to use this in my website
      www.visitorbazaar.com
      May I use?

      Delete
  3. Good, but Opera 10.10 (current 21/01/2010) fails

    Only Opera 10.50 alpha wins

    thanks a lot

    ReplyDelete
  4. pixelzero: You still need another hack for old browsers. I didn't document that hack here, I only explained how to discover that you need it. :)

    I have one in action on YayArt.com, but it's a little bit complicated and has some caveats.

    ReplyDelete
  5. i have found the scripts for Opera from 9.5 (to the 10.50 version at this time) in your code (the common js).

    now i'm trying to apply to mupeditore.it

    thanks a lot

    ReplyDelete

  6. filter: progid:DXImageTransform.Microsoft.Shadow(color='#777777', Direction= 135, Strength=8);

    yes, cool, only one line make the same of eights

    ReplyDelete
  7. Yeah, switching

    filter:
    progid:DXImageTransform.Microsoft.DropShadow(color=#969696, offx=1, offy=1)
    progid:DXImageTransform.Microsoft.DropShadow(color=#C2C2C2, offx=1, offy=1)
    progid:DXImageTransform.Microsoft.DropShadow(color=#EFEFEF, offx=1, offy=1);

    out with

    filter: progid:DXImageTransform.Microsoft.Shadow(color='#969696', Direction=135, Strength=3);

    I'll update the blog post. Thanks!

    ReplyDelete
  8. Hmmm, oddly enough your example doesn't work in IE 7 or IE 8 on my xp or vista installs. Just shows a grey box with no shadow.

    ReplyDelete
  9. works for me,
    XP sp3 ie8 and ie 7 & 6 with IETester

    ReplyDelete
  10. You could also do this to generate a rounded box-shadow ;)

    http://blog.citycrawler.com/?p=103

    - Daniel

    ReplyDelete
  11. Lovely trick indeed. Unfortunately does not work well with elements positioned absolutely that has :hover applied to it... Any thoughts to a fix guys?

    ReplyDelete
  12. to other not working try to put "!important" in css

    filter: progid:DXImageTransform.Microsoft.Shadow(color='#969696', Direction=135, Strength=3) !important;

    ReplyDelete
  13. Hi,

    I'd recommend checking out http://www.modernizr.com/ . This is a great tool to determine not just the browser but specific browser functions like if it supports box-shadow. Than you have access to a class: .no-boxshadow to apply rules for browsers that don't support box-shadow.

    :Sam

    ReplyDelete
  14. Thanks Ole!
    It doesn't work in ie8 compat mode - but better than nothing. Looks good in ie6 too... Yes some of my target audience may still be using this...

    ReplyDelete
  15. Awesome fix! Thx a lot!

    ReplyDelete
  16. WOW! It's realy best solution that i saw.
    Thx u!

    ReplyDelete
  17. Thanks.. working fine....

    ReplyDelete
  18. oh! just i was trying drop shadow to my input box, but i did not get solution for IE browser, my luckily i found solution in your website. Thanks for posting.
    Can i post same article to my blog. see this my blog: http://www.addcolours.com/blog

    ReplyDelete
  19. This solution is not working on IE 8

    ReplyDelete
  20. IE 8: it seems to work for me, when I visit YayArt with my IE 8 on Windows XP, I definitely get shadows.

    As one of the above comments mention, it may not work in IE 8 compatibility mode, I think this may be fixable, but really, you should get out of that mode as soon as possible because it means you're stuck with the old non-standard compliant renderer.

    ReplyDelete
  21. I still can't get this to work in IE9, I will try creating a sector just for IE.

    ReplyDelete
  22. Don't use the IE hack for IE9, it has native support for box-shadow: http://msdn.microsoft.com/en-us/library/cc351024(v=vs.85).aspx

    ReplyDelete
  23. Check out css3pie.com. It uses methods similar to this for many css3 styles in IE, and works really well, all things considered.

    ReplyDelete
    Replies
    1. css3pie is not work correct find curvecorner script and put ur site.and should must -moz-border-radius:10px;

      Delete
  24. You should still put the standard box shadow call below the -moz & -webkit so that when a browser fully adds the box shadow capability you are overriding the workaround (-moz and -webkit)

    ReplyDelete
  25. its work friend. tq, i like this

    ReplyDelete
  26. Had to switch it off on the shadowed content as the contained link hover states became unresponsive:

    .shadowed * {filter:none}

    ReplyDelete
  27. hre provide all ie solution.like box shadow,corner,text shadow.

    ReplyDelete
  28. and here also provide jquery script for box shadow,text shadow because it solution is not work in IE. so plz provide.

    ReplyDelete
  29. no shadow or round corner in ie9..... but css3 worked good at mozila, chrome, safari, opera, firefox.....

    fuck ie9.

    ReplyDelete
  30. Thank for share this great trick

    ReplyDelete
  31. IE9 supports box-shadow so you can stop moaning about that.

    ReplyDelete
  32. For IE6,IE7,IE8
    filter: progid:DXImageTransform.Microsoft.Shadow(color='#777777', Direction= 135, Strength=8);
    zoom: 1;

    But there is a problem cursor in area input box to apply with css filter.
    The cursor will display wrong position in input box when you key press them.
    Anybody know how to fixed ? Thanks....

    ReplyDelete