Using CSS3 Transitions and Transforms to mimic Mac OS X Stacks behavior
The other day when I wrote Using CSS3 Transitions To Create Rich Effects I was thinking of nice ways to apply this. One of the things that came up was creating the Mac OS X Stacks behavior entirely in CSS!
The working example
In the page CSS3 Transitions – Mac OS X Stacks, which is part of my new CSS3 – Information and samples playground, it displays the stacks in action. Just hover over the bottom image and you will see the effect in action.
Web browser support
This effect runs nice with animation in:
- Firefox 3.7+ (once CSS Transitions for CSS Transform bug is fixed)
- Google Chrome 4.0+
- Safari 4.0+
- Opera 10.5+
However, and here’s the kicker, I wanted it to work back in Firefox 3.5 and, hold on to something now, Internet Explorer (IE 6+ – now works thanks to great CSS input from Zoltan Hawryluk and Paul Irish)! Since I wanted it to be CSS only, there was no way I could tend to the animation part, but at least get the proper rotation and position when hovering. For Firefox 3.5+ it works automatically since that’s when they implemented support for CSS Transforms.
For Internet Explorer, however, I needed to resort to filters (more specifically, the DXImageTransform.Microsoft.Matrix
one), served via a conditional comment. And thankfully, through the help of CSS3 Please! I could generate the degrees value, and that helped me from going insane.
Breaking down the code
The code isn’t particularly advanced, there’s just a fair amount of it, so I won’t show you it in its entirety. However, the basics are:
Container element
All the images are contained within a box with the size of the image initially visible at the button:
.stack-container-bottom { position: absolute; left: 200px; bottom: 0; width: 148px; height: 130px; z-index: 1000; }
Base setup for images with CSS Transitions
All the images within that box has a CSS Transition applied to them:
.stack-container img { position: absolute; left: 0px; bottom: 0; padding-bottom: 5px; /* Firefox */ -moz-transition: -moz-transform 0.3s ease; /* WebKit */ -webkit-transition: -webkit-transform 0.3s ease; /* Opera */ -o-transition: -o-transform 0.3s ease; /* Standard */ transition: all 0.3s ease; }
This transition sets that it will do a transition for the specified property, the transform
one, during 0.3 seconds and it will use easing for the effect.
Hovering the box
When the user hovers the box, it sets a new state for all images via their transform
property and will execute the above transition:
.stack-container-bottom:hover img:nth-child(1) { /* Firefox */ -moz-transform: rotate(12deg) translate(-4px, -600px); /* WebKit */ -webkit-transform: rotate(12deg) translate(-4px, -600px); /* Opera */ -o-transform: rotate(12deg) translate(-4px, -600px); /* Standard */ transform: rotate(12deg) translate(-4px, -600px); }
Each image has a different rotation degree and offset (set through translate), so I used the :nth-child
pseudo class to assign each of them their values (using this means I need no classes on the images, and makes it more dynamic). The effect is that the images break out of the surrounding box’s square, but since they are still children element of it, when you hover them, the box is considered to still be hovered too.
However, if you hover the white background between the images, it considered the background being hovered instead, effectively hiding the images – so, the images are now actually aligned to each other but use padding-bottom: 5px
to create the visual effect that there is actually a gap there.
And that’s all there is to it! π
Making it work in Internet Explorer
In styles within a conditional comment for Internet Explorer, I use styles applied via a class for each image, then reposition the images through their left
and top
position and ultimately use the progid:DXImageTransform.Microsoft.Matrix
for the rotation. Example:
.stack-container-bottom:hover img.ie-1st { left: 115px; top: -550px; filter: progid:DXImageTransform.Microsoft.Matrix( M11=0.9781476007338057, M12=-0.20791169081775931, M21=0.20791169081775931, M22=0.9781476007338057, sizingMethod='auto expand'); /* IE6,IE7 */ -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=0.9781476007338057, M12=-0.20791169081775931, M21=0.20791169081775931, M22=0.9781476007338057, sizingMethod='auto expand')"; /* IE8 */ zoom: 1; }
All code and sample
As mentioned above, in the Transitions – Mac OS X Stacks you can run the example and also see all the code needed to create this effect.
You forgot the fade-in effect π
Very nice demo Robert!
Soon you'll be getting your MS CSS filter diploma π
Fantastic tutorial
Adrian,
Actually, from what I can see, there's no fade-in for Stacks in Mac OS X. However, just add the <code>opacity</code> property to the mix if you want it. π
Morgan,
Thanks! And yes, I do deserve that diploma, right? π
Michael,
Thank you!
So, does this or does this not work in IE6?
There is currently a discussion within the CSS WG about the syntax for transitions and animations. It *might* change…
Mathias,
Well, currently it doesn't, since the Matrix filter only seems to apply to the last element. It should work, though, and hopefully a workaround can be found.
Lars,
Yes, but isn't it sort of dangerous grounds to change it if all major web browser vendors (excluding IE) already have implemented it?
Great post! Really exciting to test all the possibilities with CSS3.
Adam,
Thanks, glad you like it!