Grow your CSS skills. Land your dream job.

Photo Swivel

Published by Guest Author

The following is a guest post by Alex Young (@the_alexyoung). Alex has created a simple technique to "rotate" the subject of a photo simply by hiding and showing multiple stacked photographs taken at different angles. Enjoy!

Web designers and developers have always fascinated us with fun and engaging ways we interact with their websites. I love discovering new techniques that these designers/developers have come up with. One technique in particular that sparked my interest is something that I saw on Warby Parker’s website. They were able to create a cool effect where model follows the user’s mouse, showing off the different angles of the frames.

I’ve seen this technique mainly used for showing off sunglasses, but I’m interested to see what you guys can come up with for other real-world applications.

Before we begin, you will need a few things. Well, seven things to be exact. You are going to need seven photos of something taken at seven different angles.

HTML Setup

What we are setting up is a container called “faces”, then have created an area that we are going to use to display the photos – “face-area”. We also have a div to hold each of the seven individual images.

<div id="faces">

  <div id="face-area">

    <div id="image-1" style="display: none;">
      <img src="/images/look-left-3.jpg">

    <div id="image-2" style="display: none;">
      <img src="/images/look-left-2.jpg">

    <div id="image-3" style="display: none;">
      <img src="/images/look-left-1.jpg">

    <div id="image-4" style="display: none;">
      <img src="/images/look-center.jpg">

    <div id="image-5" style="display: none;">
      <img src="/images/look-right-1.jpg">

    <div id="image-6" style="display: none;">
      <img src="/images/look-right-2.jpg">

    <div id="image-7" style="display: none;">
      <img src="/images/look-right-3.jpg">

Now we'll create a div that is going to do exactly what the name implies. It is going to lay on top of the other div. We can divide this div into 7 small columns and divide them equally across it. These 7 columns will be used to listen for when the mouse is hovering over that specific one. Adding “data-number” to each div will allow us to refer to each in jQuery later on.

    <div id="the_faces_overlay">
      <div class="the_faces" data-number="1"></div>
      <div class="the_faces" data-number="2"> </div>
      <div class="the_faces" data-number="3"></div>
      <div class="the_faces" data-number="4"></div>
      <div class="the_faces" data-number="5"></div>
      <div class="the_faces" data-number="6"></div>
      <div class="the_faces" data-number="7"></div>

  </div><!-- END #face-area -->

</div> <!-- END #faces --> 

CSS Setup

Most of the CSS is pretty self-explanatory. There is one thing I need to mention that is important, make sure that the 7 columns fit perfectly together across the span of the div.

body {
  background: #333 

#faces {
  height: 333px;
  width: 500px;
  margin: 0 auto;
  border: 8px solid white;

#face-area {
  height: 500px;
  width: 333px;
  position: relative;

#the_faces_overlay {
  position: absolute;
  width: 500px;
  top: 0;
  left: 0;

#faces .the_faces {
  height: 333px;
  width: 14.2857143%;
  float: left;
  margin: 0;
  padding: 0;

jQuery Setup

We need to listen for when each of the columns are hovered over. This is where those “data-numbers” come in handy. If we wanted to add more columns down the road we wouldn't have to add any more JavaScript.

// Reveal the "center" image
var centerImage = $("#image-4").show();

// Bind hovers to each column
$(".the_faces").each(function() {

  $(this).on("mouseover", function() {
    $("#image-" + $(this).attr("data-number")).show();
  }).on("mouseout",function() {
    $("#image-" + $(this).attr("data-number")).hide();


// Reset center image
$("#face-area").on("mouseleave", function() {;
}).on("mouseenter", function() {


Check out this Pen!

There you have it! Now you have your very own, head turning model. Use it to show off your very own products. There are tons of uses for this out there. Let me know what you come up with.

Editor's note: this would be a fun demo to work on adding touch support, wouldn't it? Follows a swipe or something.


  1. Very nice Chris, loving the simple javascript to make everything work.

    It would be cool if we could add some code to detect the center image.

  2. Dave

    Nice effect.

    To simplify the HTML, the ID’s and inline styles could be applied to the images themselves rather than needing a div around each one. Those divs, I think, are unnecessary markup here.

    I wonder if you could also do something clever like track the cursor position over the parent div, and work out which image to show based on which fraction of the image the mouse is over. Same principal as is on display here, but may again allow the removal of more empty divs that are really only there to aid the visual effect.

    • Dave

      I knocked up my suggestion (sorry Chris, I use JSFiddle >.<)

      Effectively removes all the markup used for hover events, and works out the segment of the image the cursor is over and loads the corresponding image. My variable names are a little dubious, and part of me wonders whether there is a more succinct way of doing the maths, but it works nonetheless!

    • Anthony Ryan Delorie

      @Eduardo: CSS only pretty cool

      cached jquery objects.., id attributes not needed if just sequential.. leveraged .eq()

  3. Josh Parrett

    I thought I would give this a go with a slightly different method:

  4. ahoiii

    i solved a similar problem some time ago.
    would be great to hear your opinions (i’m no pro)

  5. Crispen Smith

    The Touchswipe plugin ( should very happily provide for a touch centric interface.

    I might just play with this.

  6. Neat effect. I haven’t spent much time on it, but it looks like it could probably be cleaned up a bit to use less markup. Also, the JavaScript can be a little more efficient and easier to read, and should use $.data to get the data attributes:

    // Reveal the "center" image
    var centerImage = $("#image-4").show();
    // Bind hovers to each column
    $(".the_faces").each(function() {
      var $this = $(this),
          dataNumber = $"number"),
          $imgEl = $("#image-" + dataNumber);
      $this.on("mouseover", function() {
      }).on("mouseout",function() {
    // Reset center image
    $("#face-area").on("mouseleave", function() {;
    }).on("mouseenter", function() {
  7. An alternative method to help prevent the “flickering” issue in some browsers is to use absolute positioning and z-index to show/hide the images:

    Trade-off: This method would be best suited when using small light-weight images, as you need to wait for the images to load.

    • Josh Parrett

      That’s awesome man!

    • Like! Very nice. Semantic markup too. Of course, it probably won’t work in IE8 or below, or Opera, or Android browsers… but still, it’s a nice solution.

    • Nicely done.

    • cp

      Eduardo, yours is about 100 times better. The code in this demo teaches people to write non-reusable js with hardcoded IDs everywhere, while your approach is adaptable and more versatile, nice job.

    • Wow! thank you guys! that was my first comment here!

    • MaxArt

      That’s a well deserved approval.

    • Mike

      I was wondering while reading the post if this could be done with HTML & CSS only and sure enough Eduardo proves it can. Awesome Job!

    • This is awesome!, I would love to avoid JS where ever I can.

      Thanks for Sharing.

    • Patrick

      Nice work Eduardo. Keep commenting! ;)

  8. Brad Dalton

    Flickers in Chrome but this works

  9. Loving this feedback! What are some other uses for this are there?

    • Also, thanks for all the improvements to this. Always looking for new and better ways to do things.

    • Crispen Smith

      Not sure if this is a different use as such (it is a radical change), but the first thing that came to mind for me was replacing carousels with user guided swaps. In that case though I’d recommend making the “selection” divs obvious; labelled, and not obscuring the image. The advantage being it would remove carousel autoload frustrations.

  10. Ernest

    Amazing effect…if we used a tranparent gif or png with the subject well placed and CSS3 transitions, we cud achieve a 3D like effect…neat trick!

  11. As already discussed on Twitter, this can be vastly improved by using more semantic HTML and allow JS to do what it does best – calculate things for us – in this case the mouse position and see what image to show accordingly. I am working on a screencast explaining the main issues, but here is a plain vanilla demo that works with keyboard, mouse and on touch devices (tested on Android in Firefox and Chrome) . The flickering issue is also gone, this was not only a preload problem but also far too many event handlers and DOM interaction whilst moving the mouse.

  12. Thanks , but I can this would be implemented with pure html & css and no jquery needed.

  13. Cool effect! Would be a great app for jewelry or sculpture gallery. Thanks!

  14. Eduardo=Genius
    props to you +1

  15. Rachel Reveley

    I wonder if this could be made to work with CSS transitions to make it look smoother.

  16. As promised to Alex, here is a long post and a 25 minute screencast explaining the performance and maintenance issues with the demo code and how to re-write this without any library dependency and having keyboard and touch support whilst being fully maintainable by changing the HTML:

  17. Clever stuff. I’ve seen similar things done before without jquery, using ordinary javascript functions that fire on the onmouseover event. I wonder how it’d look with double the number of images, for a smoother effect. Perhaps this could be better achieved using video footage rather than still-shots, from which individual jpeg frames could be extracted.

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".