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.

Friday, August 7, 2009

Emacs 23...

... is out and has been so for over a week. Why didn't somebody tell me?

In any case, I upgraded to Emacs 23 on my Debian unstable laptop. This means a new font. I put Emacs.font: Bitstream Vera Sans Mono 9 in my .Xresources file and am enjoying it so far. It's a bit muddy so I wasn't sure at first, but after having stared at it for a while the old font is just too skinny. Note that configuring the font in .emacs is still broken (sigh), in that it causes the window to jerk when you start Emacs.

I've been lobbying for changing the defaults over to make copy-paste between Emacs and other X applications (from this century) work properly. Apparently, (setq x-select-enable-clipboard t) is now better, but still not according to the spec. And it's not default yet.

I noticed some Tramp updates (for accessing remote files) in the NEWS and decided to give it a spin for the first time. Try C-x C-f someserver:myfile.txt and with a little patience, you're editing a remote file locally! Very neat.

Feeling adventurous I also tried IDO, an update of iswitchb that works with file find (so overrides C-x C-f). I'm turning it on with
(ido-mode 1)
(setq ido-enable-flex-matching t)
(setq ido-use-filename-at-point t)
replacing iswitchb and ffap settings. We'll see how it goes.

Finally, Anders mentioned a new Javascript mode, js2-mode, which I'm definitely going to try out.