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

SlidingImagePanelsCss3_2

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!

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.