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.

left right

Simple CSS 3D Carousel Gallery

css / galleries

Estimated reading time: 3 minutes, 30 seconds

This article is a variant of a tutorial in my book (Pro CSS3 Animation), promoted by a reader bringing my attention that there was a tiny but vital piece of code missing from the printed text. I’ve also wanted to upgrade the code ever since I wrote it, so this entry is a chance to address both issues.


The construction of this gallery is fairly straightforward: eight images, absolutely stacked inside a relatively positioned figure element, which in turn is placed inside a containing div.

<div id="gallery">
<figure id="spinner">
<img src="wanaka-tree.jpg" alt="">
<img src="still-lake.jpg" alt="">
<img src="pink-milford-sound.jpg" alt="">
<img src="paradise.jpg" alt="">
<img src="morekai.jpg" alt="">
<img src="milky-blue-lagoon.jpg" alt="">
<img src="lake-tekapo.jpg" alt="">
<img src="milford-sound.jpg" alt="">

(I’ve left the alt attribute values of the images blank for the sake of brevity).


The initial is also fairly simple: the z of the origin for the images and figure (the axis around which the elements will be transformed) is pushed “back” into the screen by 500 pixels, with the figure provided a transition speed of one second. The images are 40% wide, with a left of 30% positioning them in the center of the figure, making the gallery perfectly .

body {  background: #100000; font-size: 1.5rem;  }
div#gallery { perspective: 1200px; }
figure#spinner { transform-style: preserve-3d; min-height: 122px; transform-origin: 50% 50% -500px; transition: 1s; }
figure#spinner img { width: 40%; position: absolute; left: 30%;  transform-origin-z: 50% 50% -500px; outline: 1px solid transparent; }

(The min-height on the figure and outline on the images are provided to avoid the issues I discussed in my recent article on CSS 3D tips and tricks, while the min-width on the images ensures that the photographs do not grow so large as to overlap).

The images are then evenly distributed around the central axis, using nth-child selectors:

figure#spinner img:nth-child(1) { transform: rotateY(0deg); }
figure#spinner img:nth-child(2) { transform: rotateY(-45deg); }
figure#spinner img:nth-child(3) { transform: rotateY(-90deg); }
figure#spinner img:nth-child(4) { transform: rotateY(-135deg); }
figure#spinner img:nth-child(5) { transform: rotateY(-180deg); }
figure#spinner img:nth-child(6) { transform: rotateY(-225deg); }
figure#spinner img:nth-child(7) { transform: rotateY(-270deg); }
figure#spinner img:nth-child(8) { transform: rotateY(-315deg); }

At this stage, you’ll see that the 3D carousel is naturally responsive: as you narrow the browser window, the images get smaller, while the separation between them increases.

I have not used vendor prefixes in the code thus far, as I’d rely on Lea Verou’s prefix-free to take care of that. However, prefixes will need to be addressed in the code that controls the rotation of the gallery.

JavaScript-driven controls

Finally, we want to add two controls for the gallery: a left and right arrow to control the spin. Adding the linked elements below the page, we’ll use them to call on a JavaScript function that carries a variable.

<a href="#" style="float: left" onclick="galleryspin('-')">◀</a>
<a href="#" style="float: right" onclick="galleryspin('')">▶</a>

As you can see, the left-hand arrow carries a negative sign as a variable to a galleryspin function:

var angle = 0;
function galleryspin(sign) {
spinner = document.querySelector("#spinner");
if (!sign) { angle = angle + 45; } else { angle = angle - 45; }
spinner.setAttribute("style","-webkit-transform: rotateY("+ angle +"deg); transform: rotateY("+ angle +"deg);");

The function looks at the sign variable, and, based on its absence or presence, adds or removes 45 degrees from the orientation of the gallery, producing the result you see at the top of this article.


The code presented here works well in all modern browsers, with issues in just two:

  • Safari (and mobile Safari) still retains a bug that moves the figure element over the z-axis, rather than the transform-origin, making the result appear larger on screen, while throwing off the center of rotation. While there are ways around this (applying more transforms, rather than moving the origin) I have not shown them here to keep the code simple… and I expect the issue to be resolved in the next Safari update.

  • IE 10 may also have issues with the gallery, as the browser can have problems supporting CSS 3D when it is applied to child elements.


Outside of wider browser support, there many possible improvements that we could make to the 3D carousel gallery, including:

  • fading any images that are not front and center.
  • abstracting the JavaScript to allow for any number of images to be added to the gallery.
  • captions on the images.
  • gesture support.

Many of these advances are in the Advaned CSS 3D Carousel article, which comes next. Play with the code for this carousel 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.