Sliding Image Panels with CSS3

Today we'll show you how to create some neat sliding image panels with CSS only. The idea is to use background images for the panels and animate them when clicking on a label. We'll use radio buttons with labels and target the respective panels with the general sibling selector.


SlidingImagePanelsCss3_2

View demo Download source

Today we’ll show you how to create some neat sliding image panels with CSS only. The idea is to use background images for the panels and animate them when clicking on a label. We’ll use radio buttons with labels and target the respective panels with the general sibling selector.

The beautiful images are by Joanna Kustra and they are licensed under the Attribution-NonCommercial 3.0 Unported Creative Commons License.

You might as well be interested in Filter Functionality with CSS3 where we have used a similar technique for filtering elements based on their type.

Please note: the result of this tutorial will only work as intended in browsers that support CSS transitions and animations.

The Markup

The HTML will consist of three major parts: the radio buttons and the labels, the container with the panels and their “slices” for each image, and the titles. The container with the class cr-bgimg part will have a division for each of the panels and inside we’ll place spans for every image with the right background position. So, the first panel will have four slices, each having the one of the images as background with the left-most position. The second panel will have again four slices but now the background position will be moved to be showing the next part of the respective image:

<section class="cr-container">			

	<!-- radio buttons and labels -->
	<input id="select-img-1" name="radio-set-1" type="radio" class="cr-selector-img-1" checked/>
	<label for="select-img-1" class="cr-label-img-1">1</label>

	<input id="select-img-2" name="radio-set-1" type="radio" class="cr-selector-img-2" />
	<label for="select-img-2" class="cr-label-img-2">2</label>

	<input id="select-img-3" name="radio-set-1" type="radio" class="cr-selector-img-3" />
	<label for="select-img-3" class="cr-label-img-3">3</label>

	<input id="select-img-4" name="radio-set-1" type="radio" class="cr-selector-img-4" />
	<label for="select-img-4" class="cr-label-img-4">4</label>

	<div class="clr"></div>	

	<!-- panels -->
	<div class="cr-bgimg">
		<div>
			<span>Slice 1 - Image 1</span>
			<span>Slice 1 - Image 2</span>
			<span>Slice 1 - Image 3</span>
			<span>Slice 1 - Image 4</span>
		</div>
		<div>
			<span>Slice 2 - Image 1</span>
			<span>Slice 2 - Image 2</span>
			<span>Slice 2 - Image 3</span>
			<span>Slice 2 - Image 4</span>
		</div>
		<div>
			<span>Slice 3 - Image 1</span>
			<span>Slice 3 - Image 2</span>
			<span>Slice 3 - Image 3</span>
			<span>Slice 3 - Image 4</span>
		</div>
		<div>
			<span>Slice 4 - Image 1</span>
			<span>Slice 4 - Image 2</span>
			<span>Slice 4 - Image 3</span>
			<span>Slice 4 - Image 4</span>
		</div>
	</div>

	<!-- titles -->
	<div class="cr-titles">
		<h3>
			<span>Serendipity</span>
			<span>What you've been dreaming of</span>
		</h3>
		<h3>
			<span>Adventure</span>
			<span>Where the fun begins</span>
		</h3>
		<h3>
			<span>Nature</span>
			<span>Unforgettable eperiences</span>
		</h3>
		<h3>
			<span>Serenity</span>
			<span>When silence touches nature</span>
		</h3>
	</div>

</section>

The h3 elements for the titles will have two spans, one for the main headline and one for the sub-headline.

Let’s style this baby.

The CSS

I will omit all the vendor prefixes, but you will, of course, find them in the files.
We’ll be going through the style of demo 1.

Our aim is to first hide those radio buttons by covering them up with labels. In web browsers, clicking on a label will make the respective checkbox or radio button selected. Giving an ID to the input, we can use the for = idref attribute of the label to reference the respective input.

Second, we want to place all the background images correctly and third, we want to show the respective image slices and titles when clicking on a label.

So, lets first syle the section and give it a white border with some subtle box box shadow:

.cr-container{
	width: 600px;
	height: 400px;
	position: relative;
	margin: 0 auto;
	border: 20px solid #fff;
	box-shadow: 1px 1px 3px rgba(0,0,0,0.1);
}

Since we want to use the general sibling selector in order to “reach” the right image slices and titles, we need to place the labels before those containers. Let’s make sure that they are on top as a layer (z-index) and push its position down by adding a top margin of 350px;

.cr-container label{
	font-style: italic;
	width: 150px;
	height: 30px;
	cursor: pointer;
	color: #fff;
	line-height: 32px;
	font-size: 24px;
	float:left;
	position: relative;
	margin-top: 350px;
	z-index: 1000;
}

Let’s prettify the label by adding a little circle. We’ll create a pseudo element and place it centered behind the label text:

.cr-container label:before{
	content:'';
	width: 34px;
	height: 34px;
	background: rgba(130,195,217,0.9);
	position: absolute;
	left: 50%;
	margin-left: -17px;
	border-radius: 50%;
	box-shadow: 0px 0px 0px 4px rgba(255,255,255,0.3);
	z-index:-1;
}

In order to create a separation between the panels we’ll use a little trick. We’ll create another pseudo-element for the label and extend it to stretch over the panel. Using a gradient, we’ll make the line “fade out” at the top:

.cr-container label:after{
	width: 1px;
	height: 400px;
	content: '';
	background: linear-gradient(top, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 100%);
	position: absolute;
	bottom: -20px;
	right: 0px;
}

The last panel should not have that line so we simply give it 0 width:

.cr-container label.cr-label-img-4:after{
	width: 0px;
}

Now, that we’ve taken care of the label look, we can hide the inputs:

.cr-container input{
	display: none;
}

Whenever we click on a label, the respective input gets checked. Now we can target the respective label using the general sibling selector. So, we will change the color the “selected” label:

.cr-container input.cr-selector-img-1:checked ~ label.cr-label-img-1,
.cr-container input.cr-selector-img-2:checked ~ label.cr-label-img-2,
.cr-container input.cr-selector-img-3:checked ~ label.cr-label-img-3,
.cr-container input.cr-selector-img-4:checked ~ label.cr-label-img-4{
	color: #68abc2;
}

And we’ll also change the background color and box shadow of its cicle pseudo-element:

.cr-container input.cr-selector-img-1:checked ~ label.cr-label-img-1:before,
.cr-container input.cr-selector-img-2:checked ~ label.cr-label-img-2:before,
.cr-container input.cr-selector-img-3:checked ~ label.cr-label-img-3:before,
.cr-container input.cr-selector-img-4:checked ~ label.cr-label-img-4:before{
	background: #fff;
	box-shadow: 0px 0px 0px 4px rgba(104,171,194,0.6);
}

The container for the image panels will occupy all the width and it will be positioned absolutely. This container will be used later in order to set the background image to the currently selected image. We need to do this in order to have an image visible by default. So we’ll also add some background properties already:

.cr-bgimg{
	width: 600px;
	height: 400px;
	position: absolute;
	left: 0px;
	top: 0px;
	z-index: 1;
	background-repeat: no-repeat;
	background-position: 0 0;
}

Since we have four panels/images, one panel will have the width of 150 pixels (600 divided by 4). The panels will be floating left and we’ll hide their overflow since we don’t want to see the slices coming out when we slide them:

.cr-bgimg div{
	width: 150px;
	height: 100%;
	position: relative;
	float: left;
	overflow: hidden;
	background-repeat: no-repeat;
}

Each slice span will be positioned absolutely and initially, they will be hidden by placing them out of the panel with a left of -150px:

.cr-bgimg div span{
	position: absolute;
	width: 100%;
	height: 100%;
	top: 0px;
	left: -150px;
	z-index: 2;
	text-indent: -9000px;
}

Now, let’s take care of the background of the image container and the respective image slices:

.cr-container input.cr-selector-img-1:checked ~ .cr-bgimg,
.cr-bgimg div span:nth-child(1){
	background-image: url(../images/1.jpg);
}
.cr-container input.cr-selector-img-2:checked ~ .cr-bgimg,
.cr-bgimg div span:nth-child(2){
	background-image: url(../images/2.jpg);
}
.cr-container input.cr-selector-img-3:checked ~ .cr-bgimg,
.cr-bgimg div span:nth-child(3){
	background-image: url(../images/3.jpg);
}
.cr-container input.cr-selector-img-4:checked ~ .cr-bgimg,
.cr-bgimg div span:nth-child(4){
	background-image: url(../images/4.jpg);
}

We also need to give the right background position to the slices depending on the panel:

.cr-bgimg div:nth-child(1) span{
	background-position: 0px 0px;
}
.cr-bgimg div:nth-child(2) span{
	background-position: -150px 0px;
}
.cr-bgimg div:nth-child(3) span{
	background-position: -300px 0px;
}
.cr-bgimg div:nth-child(4) span{
	background-position: -450px 0px;
}

When we click on a label we will simply slide all the slices out to the right:

.cr-container input:checked ~ .cr-bgimg div span{
	animation: slideOut 0.6s ease-in-out;
}
@keyframes slideOut{
	0%{
		left: 0px;
	}
	100%{
		left: 150px;
	}
}

…all except the slices with the respective background image. Those will slide in from -150px to 0px:

.cr-container input.cr-selector-img-1:checked ~ .cr-bgimg div span:nth-child(1),
.cr-container input.cr-selector-img-2:checked ~ .cr-bgimg div span:nth-child(2),
.cr-container input.cr-selector-img-3:checked ~ .cr-bgimg div span:nth-child(3),
.cr-container input.cr-selector-img-4:checked ~ .cr-bgimg div span:nth-child(4)
{
	transition: left 0.5s ease-in-out;
	animation: none;
	left: 0px;
	z-index: 10;
}

Last, but not least, we want to style the h3 title elements and their spans. The h3 will have a opacity transition and once we select the respective label/input the opacity will increase from 0 to 1:

.cr-titles h3{
	position: absolute;
	width: 100%;
	text-align: center;
	top: 50%;
	z-index: 10000;
	opacity: 0;
	color: #fff;
	text-shadow: 1px 1px 1px rgba(0,0,0,0.1);
	transition: opacity 0.8s ease-in-out;
}
.cr-titles h3 span:nth-child(1){
	font-family: 'BebasNeueRegular', 'Arial Narrow', Arial, sans-serif;
	font-size: 70px;
	display: block;
	letter-spacing: 7px;
}
.cr-titles h3 span:nth-child(2){
	letter-spacing: 0px;
	display: block;
	background: rgba(104,171,194,0.9);
	font-size: 14px;
	padding: 10px;
	font-style: italic;
	font-family: Cambria, Palatino, "Palatino Linotype", "Palatino LT STD", Georgia, serif;
}
.cr-container input.cr-selector-img-1:checked ~ .cr-titles h3:nth-child(1),
.cr-container input.cr-selector-img-2:checked ~ .cr-titles h3:nth-child(2),
.cr-container input.cr-selector-img-3:checked ~ .cr-titles h3:nth-child(3),
.cr-container input.cr-selector-img-4:checked ~ .cr-titles h3:nth-child(4){
	opacity: 1;
}

If you don’t want to use the label trick on mobile devices you could, for example, use a media query:

@media screen and (max-width: 768px) {
	.cr-container input{
		display: inline;
		width: 24%;
		margin-top: 350px;
		z-index: 1000;
		position: relative;
	}
	.cr-container label{
		display: none;
	}
}

This is just a quick solution and it might be better to check, if the label trick is supported.

And that’s it! There are many possibilities of animations that can be done here. Check out the demos to see more.

Demos

  1. Demo 1: Slide to right
  2. Demo 2: Odd/even slide to left/right
  3. Demo 3: Odd/even slide up/down
  4. Demo 4: Scale up/down

And that’s it! I hope you enjoyed this tutorial and find it inspiring!

View demo Download source

Previous:
Next:

Tagged with:

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

View all contributions by

Website: http://www.codrops.com

Related Articles

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.

Feedback 69

Comments are closed.
  1. 1

    Hi

    Is there a script to scroll immediately to (for instance) the 4th page? I’ve tried but without success…

  2. 3

    I’ve followed the tutorial, but something has gone askew. I believe I’ve got my animate wrong, the images changes on click, but the panels won’t slide, instead they slide on initial page-load, which seems to be what the CSS is telling it to do… My test here: bit.ly/y0rtdW Anyone care to enlighten me? Thanks.

    • 4

      Solved the problem. I’d left a trailing comma between the last selector and the opening bracket on the animation rule set.

  3. 6

    Hello and thank you for this fabulous tutorial.
    I wanted to know if there was a solution to make it work with IE8?
    Thank you for your response

  4. 7

    Hi Mary Lou, thanks for sharing your nice works.
    But a big problem : doesn’t work on iPad. On computer, all is fine…..
    Can you help me, please….

  5. 8

    Hi ML, awesome work! Doesn’t seem to work on iPad for me either though, is there anyway around this? iPad displays radio buttons but I can’t click on them. Thanks for your help! Emily

    • 11

      Call these 2 scripts (in your )

      and add this (in your )

      var $j = jQuery.noConflict();
      var i = 2; // premier switch vers image 2

      function switchImage()
      {
      $j(“.current”).removeAttr(‘checked’);
      $j(“.current”).removeClass(‘current’);

      $j(“#select-img-“+i).addClass(‘current’);
      $j(“#select-img-“+i).attr(‘checked’, true);

      if (i==4)
      {
      i=1; // retour au debut sur image 1
      }
      else
      {
      i++; // image suivante
      }
      }

      $j(document).ready(function(){ //on lance l’annimation en boucle toute les 5 secondes (5000 miliseconde)
      setInterval(‘switchImage();’, 6000);
      });

  6. 14

    For the panel to work on iPhone/iPad, insert this javascript at the end of your page (just before ):

    /* IPHONE CLICK */

    if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/iPad/i)) {
    $(‘label[for]’).click(function () {
    var el = $(this).attr(‘for’);
    if ($(‘#’ + el + ‘[type=radio], #’ + el + ‘[type=checkbox]’).attr(‘selected’, !$(‘#’ + el).attr(‘selected’))) {
    return;
    } else {
    $(‘#’ + el)[0].focus();
    }
    });
    }

    Hope it helps. It worked for me.

  7. 18

    Very beautiful indeed, only problem is that it doens’t work well in IE and doesn’t work AT ALL in Safari (at least the Win7 version).

    • 19

      Hi Benny, sure, the CSS properties that IE does not support, will of course not work in IE, you just have a simple “changing of the image”.
      I just tested it again in Safari (latest version) on Win7 and also Vista and it works fine. What do you mean with not “at all”, give me some more details on what it looks like. Thanks, cheers, ML

  8. 21

    Great tutorial, thanks.
    Having 2 goofy issues – but it does work. Using dw cs4 and firefox(latest)
    No matter what I try, I cannot get the label number text inside the circle – my text is always to the left – circle is dead center – changes color and all on checked, but cannot get text into button. I even copied and pasted both your css pages and html core, trying to isolate – all of your css and html – works fine except text is not in circle. Yet your demos clearly show it in the circle.
    DW cs4 – does not color code the @keyframes -‘correctly’ – does not seem to recognize the brace structure (brace after 0% not highlighting – final brace shown as error – extra brace). It does work, and may only be a visual thing, but just curious – I could not find info out about why this occurs- except typical dreamweaver confusion maybe.
    Thanks for the tut,
    Mike

    • 22

      Never mind on the Dreamweaver question. I kinda figured it out.
      some css3 shows but it doesn’t show correctly for pseudo elements and deeper things – @keyframe in particular. This is dw cs4 – they are on like 6 now, so I think it is just old.
      …I downloaded another of your tutorial files (Animated Web Banners) and took a look at the css – it is marked up as invalid(by colors – not by any other rule or test) – but the pages work great – So no issue.
      And by the way … another great tutorial, thanks again

  9. 23

    Is there a way to make this full screen and auto adjust to screen size? Please do help me out.

Comments are closed.