CSS3 transitions and 3D transforms make it easy to create very nice cube transition (one like you can find in Keynote presentations and few places in Mac OS X).

Demo

Basement Cat
Ceiling cat
Ceiling cat
Basement Cat

Screenshot

Code

In theory:

.front {
    transform: translateZ(-100px) rotateY(  0deg) translateZ(100px);
    background: gray;
}

.left {
    transform: translateZ(-100px) rotateY(-90deg) translateZ(100px); 
    background: black;
}

.right {
    transform: translateZ(-100px) rotateY( 90deg) translateZ(100px);
    background: white;
}

.left,.front,.right {
    position:absolute; top:0;bottom:0;left:0;right:0;

    backface-visibility: hidden;
    transition: transform 0.6s ease-in-out, background-color 0.6s ease-in-out;
}

.container {
    position:relative; width:100px; height:100px;

    perspective: 1000;
}

and then you build:

<div class=container>
    <section class=left>
        Stuff here
    </section>
    <section class=right>
        Other stuff there
    </section>    
</div>

and flip classes with script, or use favorite CSS selector trick to do it with “pure” CSS.

Transition of background color simulates light and shade, giving it much more realistic looks.

Some bad news

  1. Currently these CSS modules are Working Drafts, i.e. they’re not a standard yet, it’s still possible that they’ll change in incompatible ways or never become a standard. Some experimental implementations are buggy. Don’t put this code in production, or keep an eye on compatibility problems.

  2. Varying level of browser support and vendor prefixes turn few simple lines into a hyphenated version of coke & mentos.

  3. The cube must have a fixed size in pixels due to design limitation of 3D transforms.

So here we go:

2D fallback

Not every browser supports 3D, and 2D transforms can serve as a decent fallback:

.front {
    transform: translateX(0px);
    transform: translateZ(-100px) rotateY(  0deg) translateZ(100px);
    background: gray;
}

.left {
    transform: translateX( 100px) scaleX(0.00000001);
    transform: translateZ(-100px) rotateY(-90deg) translateZ(100px); 
    background: black;
}

.right {
    transform: translateX(-100px) scaleX(0.00000001);
    transform: translateZ(-100px) rotateY( 90deg) translateZ(100px);
    background: white;
}

Scale factor can’t be 0, because it causes division by zero in some matrix computation I’d rather not know about.

You could also add opacity transition as a fallback for transform-less browsers, but that keeps element clickable, so a proper fallback will need a good’ol script toggling display:none.

Prefixes

I've dropped experimental -vendor- prefixed code from this page. I'm waiting for vendors and CSSWG to get their act together.

Different direction

If you swap all X’s and Y’s, transition will work from top to bottom. However, transforms exhibit…

Spooky action at distance

Big thanks to Brendan Kenny for explanation

For transitions to work in a sane manner, all transform properties, everywhere, must have exactly same number and order of transform functions. Otherwise some transforms will be “flattened” to a single matrix, that doesn’t animate well.

If you want to use both horizontal and vertical rotation, the workaround is to add rotateX(0) before rotateY(…deg) and rotateY(0) after rotateX(…deg) everywhere.

Compatibility