Recreate the 3D slider effect from the Android home page

December 28th, 2011

I think I’ve mentioned on here before that once in a while I’ll see an effect on a web page and I’ll become obsessed with how it was down. The latest thing to catch my attention is the 3D slide effect that’s on the home page of the Android site. It’s a great effect and makes use of CSS3 3D transforms. But it does continue a trend I’ve been seeing from Google lately, it only works in Webkit browsers like Chrome and Safari although it could be set to work in Firefox 10, which is in beta right now. This might be because Google wanted it to work a certain way and Firefox’s implementation doesn’t work quite the same as Webkit’s.

The trick to how the effect works is that it’s powered by CSS but it uses JavaScript to trigger the effect. And the CSS it uses are translateX, transitions and animations. The animations are used to create a fade effect when the slider moves more than one “slide”. I’m not going to go step by step on how to build this, I’ll just go over the key parts and then if you really want to build your own version, you can go through the demo I’ve created. Here’s our basic HTML:

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="box-wrapper">
 <div id="box-container">
   <div id="home" class="box">
   </div>
   <div id="about" class="box">
   </div>
   <div id="work" class="box">
   <div class="image-left">
   </div>
   <div id="contact" class="box">
   </div>
 </div>
</div>

First off, anytime you use 3D with CSS, then you need to set the perspective:

1
2
3
4
.box-wrapper {
 -webkit-perspective: 600px;
 -webkit-perspective-origin: 2000px -200px;
}

A div with the class box-wrapper is the wrapper div for everything. The perspective property is set to 600 pixels, which essentially means the content is 600 pixels away on the z index. Next, the perspective-origin property is set to 2000px on the x axis and -200px on the y axis. This sets up the view that the user has. Next, we need to set up our transform-style:

1
2
3
4
#box-container {
 -webkit-transform-style: preserve-3d;
 -webkit-transition: -webkit-transform .6s ease-in-out;
}

Inside box-wrapper is a div with the id of box-container. I’ve set the transform-style to perserve-3d. There’s only two options, perserve-3d or flat, the first says everything should be positioned in 3D space, the other positions everything on the same plane as the container element.

Now it needs some JavaScript to set up the translateZ property of all the divs. The reason I decided to use to set all the z axis positioning on the divs is mainly because it allows you to add or remove divs without worrying about setting anything for them manually.

1
2
3
4
5
6
var startDist = 0;
boxContainer.style[transform] = 'translateZ(' + startDist + 'px)';
for (var i = 0; i < boxes.length; i++) {
 boxes[i].style[transform] = 'translateZ(' + startDist + 'px)';
 startDist -= 400;
}

First thing this does is set the translateZ property of the box-container div to 0. Next, the boxes array contains all the divs with a class of box and in the loop they are all given a translateZ value that’s 400 less than the previous one.

The basics to how this works is this, there’s four divs, the first one is 0, the next -400, then -800 and finally -1200. To get the moving through 3D space effect, the box-container div’s translateX value is changed to be the same as the one we want to see, so if the 3rd one is selected, it will be set to -800 and that div is the one in the view port. To trigger this effect, the translateX of the box-container will be set depending on what link is clicked:

There’s one other effect that really helps flesh this out and that’s when the user clicks on a div that not the next div, say they click on div 3 when they’re currently on div 1, there’s a nice fading animation to make it look like the user is moving through the other divs. First the animation:

1
2
3
4
5
6
7
8
9
10
11
@-webkit-keyframes half-fade {
 0% {
   opacity: 0;
 }
 50% {
   opacity: .4;
 }
 100% {
   opacity: 0;
 }
}

So this just fades the div in to 40% opacity and then back to zero to add to the transition effect. To add this effect, there’s a class called transition:

1
2
3
.transition {
 -webkit-animation: half-fade .6s ease;
}

What happens is that if the user is going from say, div 1 to div 3, then div 2 would have the transition class added to it and you’d get that fade effect. But there’s one problem, once a CSS animation is fired, there’s no way to restart it. This was the part that caused me the most problems but a quick search lead me to CSS-Tricks, where of course Chris Coyier had the answer. The solution is that you have remove the element and then add a new version of it. Luckily, that only takes 5 lines of JS:

1
2
3
4
5
function clone(i) {
 var el = boxes[i];
 var nel = el.cloneNode(true);
 el.parentNode.replaceChild(nel, el);
}

This code gets the element, clones the element and then replaces the element with the new element. This allows use to reset the animations.

Poke around the code in my demo. I didn’t use jQuery because A) Google didn’t on their site and B) because I want to make sure that I don’t rely on jQuery for everything. I made my demo to work in Firefox and also future proofed it to work in the other major browsers for the one day when they include 3D transforms.

One other thing, in at least my version of Chrome, the dev channel on Windows 7, you can’t click on either of the back two divs, in my version or on android.com. The same goes for Firefox. It does let you click on them in Safari, so I’m guessing this is a temporary bug but one that really make using this on real sites impossible, hopefully it gets fixed soon.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>