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.

Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.

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!

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 in the loop: Get your dose of frontend twice a week

Fresh news, inspo, code demos, and UI animations—zero fluff, all quality. Make your Mondays and Thursdays creative!

Feedback 71

Comments are closed.
  1. Seriously why are you guys soo good ? what do you know that we don’t !!!

    Love this one too.

  2. Thanks Mary Lou. Another winner. This has to be one of the best tutorial sites around right now. Great to be able to do this without jquery.

    Tim

  3. lovely Mary, what a wonderful effects !
    I’ve been enjoying Demo3 for a minute !
    to fav, nice to add this to some “sliding featured panel” at homepage.

    thanks for share, have a nice week !

  4. Great job, Mary. Would you please show us how to make the slide automatically switch pages?

  5. OMG! thats awesome… I was looking for something like this, specially loved the effects of demo 2.

    Thanks for sharing … God Bless you!

  6. Hi ML,

    I want to make the background image fullscreen (100% width and 100% height)
    Could you please hint what I need to change.

  7. Excellent work! Thank you! Good slide show is a powerful tool in web design. CSS3 – a great thing.

  8. Real Nice nice work as always!! But… I just want to say… don’t test on IE, it’s never work, cause IE will always be the prehistory of the Web… IE should be prohibited!!

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

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

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

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

    Thanks for sharing.

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

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

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

  15. 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! 🙂

  16. 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!!

  17. 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!

  18. Hi

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

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

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

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

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

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

    • 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);
      });