The Shady Hotness
So, I’m at BarCamp NYC and I finished up with the code for my presentation a bit faster than I expected, so I figured I’d fix something that’s been bothering me for awhile.
A List Apart ran a wonderful article some time ago, entitled "Onion Skinned Drop Shadows". It’s a really, really great way of putting gorgeous drop shadows on divs, images, or other block elements. Unfortunately though, the markup required involves a bunch of wrapper divs, and that kind of bothered me a little—it strikes me as somewhat less than elegant.
So, I wrote up a quick fix for the problem. In a nutshell, I used behavior.js to locate all elements with a class of “dropshadow” and add in the wrapper divs with some simple JavaScript. The rest gets handled by the CSS supplied in the ALA article.
The JavaScript:
Update: Now with IE support!
(Turns out IE needs you to call the “className” method, or it doesn’t know to update the CSS class.)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Behaviour.register({
'.dropshadow' : function(element) {
var wrap1 = document.createElement("div");
wrap1.className = "wrap1";
var wrap2 = document.createElement("div");
wrap2.className = "wrap2";
var wrap3 = document.createElement("div");
wrap3.className = "wrap3";
var outerNode = element.parentNode;
outerNode.insertBefore(wrap1, element);
wrap1.appendChild(wrap2);
wrap2.appendChild(wrap3);
outerNode.removeChild(element);
wrap3.appendChild(element);
}
});
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
.wrap1, .wrap2, .wrap3 {
display:inline-table;
/* \*/display:block;/**/
}
.wrap1 {
float: left;
background:url(/files/shadow.gif) right bottom no-repeat;
}
.wrap2 {
background:url(/files/corner_bl.gif) -4px 100% no-repeat;
}
.wrap3 {
padding:0 16px 16px 0;
background:url(/files/corner_tr.gif) 100% -4px no-repeat;
}
.wrap3 img {
display:block;
border:1px solid #ccc;
border-color:#efefef #ccc #ccc #efefef;
}
|
The Demo:
Anyhow, many thanks to Brian Williams for the original article.
Update: And for those wondering about performance, I wrote up a quick test page featuring merely 440 shady Papa Smurfs. I wrote a test page, then removed it so I don’t run out of bandwidth due to IE’s brokenness. Firefox handles the smurf mob just fine. If I manage to get IE working, I’ll put it back up.
Notice to IE users: Why aren’t you using Firefox?!? IE peeps, please don’t try to load the whole performance test page… IE’s going to try to download the same images over and over again, like a bazillion times because being stupid is all it’s good at. I’d really prefer not running out of bandwidth for the month, or worse, make TextDrive sad, because of IE being dumb. Update: IE should play nice now that I’m insisting on proper behavior with the Cache-Control header. Not verified though… Update: Nevermind, Internet Explorer is still trash.
Sweetness! I’ll have to try this sometime. Thanks!
Behaviour is teh Best!
That author of behaviour must be a handsome man.
Using jQuery, that ‘huge’ chunk of Javascript can be shortened to:
$(“img.dropshadow”) .wrap(”<div.wrap1><div.wrap2><div.wrap3></div></div></div>”);
and if you tightened up your CSS a little bit, it could be:
$(“img.dropshadow”) .wrap(”<div.wrap><div><div></div></div></div>”);
I’ve got a mini demo here.
Hehe. Sup Resig. Was just about to translate it to Prototype for the IE compatibility. The jQuery code is really quite nice though…
Actually, the point about tightening up the CSS is a really good one.
Oh… LOL, Ben! Heh, took me awhile to catch on there…
The lack of IE support has been rectified. IE apparently can’t handle it when people use setAttribute to change the class name. They’re such jokesters!
For some reason in IE (6) instead of just showing the dropshadow (which it does fine by the way) it also thinks it has to reload the all images for the dropshadow for each time the drop shadow is used.’
I noticed this on your performance test page. I’d view it, it would show all images, all drop shadows, but then sit there saying “1204 images still loading” on the status bar!
Aha! See, that’s what I wanted to know. Um, not sure how to fix that, frankly. Preloading the images perhaps? Still, that’s a gloriously retarded thing for IE to be doing…
Search for “IE Flickering .htaccess” and you’ll find some mod_expires lines to work that out.
Huh, thanks “null.” Unfortunately I’m using lighttpd, so I can’t just copy and paste. I’ll see if I can’t figure something out.
Ok, I set mod_expire up, and it’s sending Cache-Control headers now, so hopefully that will force IE to behave.
I have been looking into jQuery, but isn’t the function they use to bind events memory leak-ish? They don’t use closures and they don’t use an unload to free those events.. Could be my misunderstanding of the memory leak…
Looks pretty good! It’s nice to see someone working on workarounds for the extra markup for the onion-skin method.
I think you could further optimize the script by cloning a template node, replacing the image within the template and then replacing the original in-page image with the template, thus having two replaceChild() calls as opposed to three createElement() and an appendChild(). However, I’d bet on most modern machines and with less-complex layouts you wouldn’t notice the difference. ;)
You appear to be using setAttribute as well as .className – if the former isn’t working for IE, I’d just use .className as that works for everything rather than having both methods.
As for the IE flickering (reloading image) thing, setting an “Expires” header with a future date may fix that. From my experience it doesn’t seem to matter how the image is “created” (ie. by createNode, cloning or via .innerHTML), it appears to be a more general loading issue.
Nice! Thanks for the great tips Scott, I’ll see about putting them to good use.
About five months ago I removed all of the wrapper divs from my posts because it was becoming a hassle to remember to add them into my posts. When I get home tonight I’m going to give this a try. Great mod to a great idea!
gilles: To prevent memory leaks, I use a modified version of Dean Edward’s addEvent/removeEvent – more info about this can be found at his site.
this is great. i’m new at this, so i’m sorry if these are dumb questions.
after implementing the original script (sans jQuery), i find the text (and everything else) following the image wraps around the image too. how do i avoid that?
i noticed you used “behavior.js” in addition to the javascript you show above. is this necessary? was it for the IE issues?
appreciate your help.
The outer div wrapper is a left-floated div. You could avoid it by clearing the float with an element following it that has “clear: left” set in the CSS. In my case, that was desirable behavior. Feel free to modify to suit your needs.
Behavior.js is necessary, yes. It could have been implemented in other ways, but I was already using behavior.js for other stuff, so it was a natural fit. It does help with IE issues, but its primary purpose is to keep from having to embed javascript directly within the HTML. It allows for full separation of structure, presentation, and behavior.
got it! great solution. thanks for the help!
Two things: One recommendation I would make would be to use Pawel’s domEl function to create the wrappers?
http://pawel.saikko.com/domel-easier-dom-manipulation,20060325
Also, why do we keep using IE? Here are some reasons:
1. Speed. Right now I am using Maxthon, and I have 36 tabs open (yes 36), with no noticeable speed difference, and I can quickly scroll through the tabs quite speedily. Maxthon shows that it’s using 17 megs of RAM (though I’ve seen it go up to 60 if Im really power browsing). I have 2 tabs open in Firefox, and it’s using 34 megs of RAM. Mind you, Maxthon has session saving, group saving, drag and drop links/text searches, search bar, roboform integration, adblock integration, translation service integration, skin support, and more, all built in by default. Yes, FF’s extensibility is nice, but at what cost? To get all those same features in Firefox, you’re looking at a couple hundred megs worth of memory just opening the thing. And keeping the same snappy GUI at the same time is just darn impossible.
2. The GUI. Firefox feels like a GNOME application. Seriously, it’s kludgy, the chrome has a bloated feel to it, and it just gives off the feeling of not being integrated with Windows.
So, while I love some aspects of FF, frankly, there is nothing in it that makes it a “must use”. In fact, while I love the extensions, the whole is actually less than the sum of it’s parts, because when you start combining them all together, it can make a worse experience when it comes to memory issues.
So, IMHO, Firefox is great for some people (average folks who look at 1 page and close), Maxthon is perfect for those of us who browse around, do work, and need to keep somethings in the background until later, and like having their pages available again if something crashes (which is really rare for Maxthon).
And no, Maxthon did not support this message :)
Anyways, cool technique. It could probably also be done with behavior as well :)
Er, over 40% of my readers don’t even use Windows, and of the ones that do, almost all use Firefox. Maxthon shows up as not even 1%. And I suspect that 100% of my Maxthon hits are you.
As for FF’s memory issues, those can be fixed easily in the about:config screen.
I will agree with you on the UI though. I’d pick Camino’s UI as the nicest, though I’m highly partial to Shiira’s functionality, except the way it handles copying and pasting.
But really, I’m not sure how this turned into a browser thing, aside from my comment on how IE is trash. Which, it is, at least for version 6.0 and under. IE 7.0 (even in its beta form) is better, but it’s a long, long way from perfect. And frankly, it’s not the speed or the memory usage that makes a browser worth using. It’s how well it renders the page and how well it functions. IE functions just fine, most of the time, if you discount insecurities. But it’s piss poor at rendering, and its javascript implementation is just scary messed up in some places. And that’s what annoys me.
Also, with regard to domEl, I don’t think I would use it. It would abbreviate the code for sure, but it would also make it much more difficult to read, IMHO. That’s one of the nice things about Prototype: your code is both easier to read and shorter, in most cases.
“And frankly, it’s not the speed or the memory usage that makes a browser worth using. It’s how well it renders the page and how well it functions.” You’re a Java programmer, arent you? ;)
I agree about IE’s rendering problems, but Firefox is just as much trash as IE, just in different areas.
No doubt you think differently, but not everyone uses their computer and browser for the same reasons you do.
Nate: I’m a Java programmer by job description only. I’m a Ruby programmer by preference. Though I’d actually pick C# over Java for any desktop app that was meant for Windows only.
The reason I say speed isn’t an issue is simply that memory and processor speed keep getting cheaper and faster. Firefox does have its own quirks and foibles, but rendering doesn’t tend to be one of them.
You’ll have to forgive me, but I’m not sure I follow the logic in that statement. Others may not use their browser for development, but if IE makes development harder, I’m a heck of a lot more likely to eventually get fed up and just shrug and say “screw em.” IE users only make up 9% of my readers anyway, and about 99% of that 9% came in from Google and will never return anyways.
nice write up – here’s a technique that does a similar effect on text: http://www.scottjehl.com/jsDropShadows/
snip= (Turns out IE needs you to call the “className” method, or it doesn’t know to update the CSS class.) =snip
man i love you … i just been creating some list from the result of an ajax call and then attaching behaviour onto it with a Behaviour.apply() call … it worked on firefox but did nothing on internet explorer ….
I would never have guessed this was the problem except by pure chance I came accross your blog.
here is my code for those interested ( incidentally I’m using DWR for remoting //
—code follows --//Leave a Response