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 leanirng CSS now.

Feedback 69

Comments are closed.
  1. 3

    Thank you all for your feedback!
    @Akamaxbuz, what exactly doesn’t work for you on the iPad? Demo 4 seems to have some issue with the scale but apart from that they work fine. Thanks again, cheers, ML

    • 4

      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….

  2. 8

    Not working for me on an iPad1. Some fooling around showed me this:

    – on a desktop clicking a label is the same as clicking the radio button itself
    – on my iPad clicking a label does nothing; the actual radio button has to be visible to be checked

    I don’t know off-hand how much styling can be done to keep radio buttons pretty, but for my iPad it seems they have to be visible to remain functional.

  3. 10

    You are absolutely amazing Mary Lou! Really grateful to you for sharing. Am learning a LOT

  4. 11

    wow nice slider design, i check this css code, its works really great.

    Thanks for sharing.

  5. 14

    @ Mary, your tutorial’s are just fantastic, from where you get these ideas and the way you execute them is fabulous.. :)

  6. 15

    Thanks for this amazing tutorial. I was wondering about one thing: how can I position the big H3 element, for example 15px down. I tried the .cr-titles h3 span:nth-child(1), but then the whole thing goes down.

  7. 17

    This is broken in Opera 11.6 (in OS X 10.6), otherwise it looks pretty stunning (if your browser supports it).

    Demo 4 also glitches in Safari 5.1.2.

  8. 19

    This is a great tutorial, thank you so much for the sharing!! Anyway, is that possible to make it Autoplay? I wanted to know how is it and looking forward from your reply to know this answer… thanks! :-)

  9. 20

    Awesome work. I really appreciate the developer of this very much.
    Can you please make a jQuery version of this, so that this can be used widely for every device, everywhere.
    Please provide a jQuery version of this. this will rock the world.
    thanks to codrops team!!

  10. 21

    Dear, Thank you for sharing this! I love it, but I found it doesn’t work on ipad/iphone and had troubles on various browser too.
    Is there an update that can allow this effect on all browsers and on Ipad/Iphone too?

    Please let me know!

Comments are closed.