demosthenes.info

I’m Dudley Storey, the author of Pro CSS3 Animation. This is my blog, where I talk about web design and development with , and . To receive more information, including news, updates, and tips, you should follow me on Twitter or add me on Google+.

web developer guide

my books

Book cover of Pro CSS3 AnimationPro CSS3 Animation, Apress, 2013

my projects

CSSslidy: an auto-generated #RWD image slider. 3.8K of JS, no JQuery. Drop in images, add a line of CSS. Done.

tipster.ioAutomatically provides local tipping customs and percentages for services anywhere.

Origami: A CSS 3D Foldout Image Gallery

css / galleries

Estimated reading time: 4 minutes, 48 seconds

Space on web pages is growing tighter as gains in popularity. In response, designers are being pushed to create interfaces that work in extremely restricted areas. Carousels and slider galleries are a possible solution for responsive images, but lately I’ve been interested in more elegant designs that flower open from a small footprint to expose more content. Thus, the first version of this interface, Origami.

The HTML Code

<div id="emma">
<img src="emma-center.jpg" alt>
<img id="top" src="emma-top.jpg" alt>
<img id="left" src="emma-left.jpg" alt>
<img id="bottom" src="emma-bottom.jpg" alt>
<img id="right" src="emma-right.jpg" alt>
</div>

The source order of the bitmap images corresponds to their level in the folded origami structure, and thus the order in which they are unfolded: the last image will fold out first, followed by the second to last, and so on. The first child image inside the div, emma-center.jpg, will not move at all.

The Setup CSS

The bitmap images are all the same size, but for the sake of simplicity #top and #bottom have been inverted in *. The next step is to set up the container element for responsive effects. (Note that I’ve dropped browser vendor prefixes where possible to keep the code simple and clear).

div#emma { width: 25%; position: relative;  perspective: 1500px; margin: 0 auto; }

The centred container will scale in response to the size of its parent element; perspective has been set to a moderate amount. Now for the images themselves:

div#emma img {
position: absolute;
max-width: 100%;
-webkit-filter: drop-shadow(3px 3px 5px rgba(0,0,0,0.6));
filter: url(shadow.svg#drop-shadow);
filter: drop-shadow(3px 3px 5px rgba(0,0,0,0.6));
transform: rotate3d(0, 0, 0, 0deg);
transition-duration: 1s;
}

The images use the standard “absolutely positioned elements inside a relative container” trick for controlling layout. Any image transition will last for exactly one second. The images also have a dynamic drop-shadow applied for Chrome, Safari and Firefox: unlike a standard box-shadow, these will accurately reflect any 3D manipulation of our images, casting dynamic shadows on the surface of the page.

The rotate3D Matrix Shortcut

The rotate3d  property is a useful shortcut for 3d manipulation: the value at the end of the declaration will be shared by the X, Y and Z axes during rotation of the element, depending on the value of their multiplier. A value of 1 for an axis means that the full value of the rotation will be used; 0.5 will be half the rotation amount, and so on.

Avoiding WebKit’s Predilection For Premature Transitions

One of the issues found in crafting CSS animations for Webkit is that it has a tendency to immediately transition elements from an assumed default state to the initial transition point on page load, especially if the transition property is set to all. By using position: absolute and zeroing out all values of rotate3d, we’ve avoided this particular behaviour in Chrome and Safari.

Creating An Unfolding Effect

The images unfold whenever the user hovers over the div container. Taking a close look at the first image reveals the key to the technique:

div#emma img#right { transform-origin: top right; transition-delay: 3s; }
div#emma:hover img#right { transform: rotate3d(0, 1, 0, 180deg); transition-delay: 0s; }

Any transformation of the first image will originate in the top right corner of the image, where the paper logically “folds”. The image will unfold over 180 degrees in the Y axis the moment that the user interacts with the element.

So far, that’s standard behaviour for simple 3D transforms. However if we leave the code as-is, the images will fold back in the exact same order that they opened, which we don’t want: in order to make sense, the image that unfolded first should transition back last when the user leaves the div.

To create that behaviour, I’ve added a delay to the default state of the image. Remember that a transition-delay is always tothe next state. That can be a little confusing at first:

MotionDelay before movementDuration
Unfolding (default state → hover state) None (derived from the value on the :hover state) 1 sec
Refolding (hover state → default state) 3 seconds (derived from the value on the default state) 1 sec

The rest of the CSS follows suit, with transition-delay increasing for the hover state of images higher in the stack (so they unfold in sequence) and decreasing for their default states (so that they return in reverse order).

div#emma img#bottom { transform-origin: center bottom; transition-delay: 2.5s; }
div#emma:hover img#bottom { transform: rotate3d(1, 0, 0, -178deg); transition-delay: .5s; }
div#emma img#left { transform-origin: left top; transition-delay: 2s; }
div#emma:hover img#left { transform: rotate3d(0, 1, 0, -178deg); transition-delay: 1s; }
div#emma img#top { transform-origin: top center; transition-delay: 1.5s; }
div#emma:hover img#top { transform: rotate3d(1, 0, 0, 179deg); transition-delay: 1.5s; }

I’ve used values less than ±180° for some of the transforms due to the fact that browsers will sometimes become confused as to whether elements should rotate clockwise or counter-clockwise from 0 to 180 degrees; by providing values slightly less than 180 we can “lead” the browser in the correct direction, while keeping the complete unfolded interface less than perfectly “flat”.

Conclusions & Future Improvements

CSS 3D transforms allow us to use perspective to get around the limits of shrinking screen sizes on web pages, revealing more content in depth.

The code shown here is still less than perfect; mobile devices will read the first tap on the div as a hover event and unfold the images, but not return them into place: that code will be saved for a future article. I’ve also not added a fallback for browsers that do not yet support CSS transforms.

Ideally, the Origami effect would be double-sided: one might expect to see a paper texture behind each image, with unfolding revealing the photograph on the other side. That rather more complex proposition I will also leave for a future article.

Photographs by Paul Cox, licensed under Creative Commons

* While we could force an image inversion with CSS, it would make the code rather more complicated.

Play with this code on CodePen.
comments powered by Disqus

This site helps millions of visitors while remaining ad-free. For less than the price of a cup of coffee, you can help pay for bandwidth and server costs while encouraging further articles.