Space on web pages is growing tighter as mobile development 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 PhotoShop*. The next step is to set up the container element for responsive CSS 3D 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:
Motion | Delay before movement | Duration |
---|---|---|
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.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/Hnfrd