Code

Make a Background Image Slider With CSS Keyframes

A silky smooth, pure css approach to animating background-images

Written by Pete Wright

Ya like sliders? Lame. Because guess what little buddy? No one cares or clicks.

Let me lay some science on you – 90% of sliders on the web are pointless fluff. Google it. But, on a purely presentational level, a nice little background image animation certainly has merit. Plus, considering the wide-ranging support for css animations (keyframes, transforms, transitions), it’s easy to accomplish this UX pattern with a purely css approach (no javascript).

A Pure CSS Keyframes Slider

So, today, let’s use css keyframes to create a full height slider that fades between images all sexy like. Additionally, we’ll deliver smaller images for mobile to keep them load times fast. For the sake of scalability (and non retardery), we’ll be using SCSS and Bourbon.

1. Create Images for Mobile and Desktop

First, create a series of images for our slider, at both desktop and mobile sizes. For desktop, I like to use images around 2000×1350. For mobile, images around 800×1200 will work great.

The demo uses images from a great free stock site: Pexels

2. Set Up a Banner Section

With images ready to rock, time to create a banner section to house our content and assign the background-images. For this demo, we’ll be fading between 3 images, so let’s set up an unordered list with 3 empty list items. Essentially, we’ll apply our images to each list item via the :nth-child() selector, then use a simple opacity keyframe animation.

<!-- Sect: Banner
======================================= -->	
<section class="sect-banner">
 <!--List items for bg images -->
 <ul class="kf-slider">
  <li></li>
  <li></li>
  <li></li>
 </ul>
 <!-- Vertically Center Content -->
 <div class="v-center">
  <h1>Stupid Simple Slider</h1>
  <p>Silky smooth background image animations with css keyframes</p>	
 </div>
</section>

3. Style It Up

As you can see, we have a pretty straight forward banner/hero section going. Now it’s time to style stuff up. Here’s a breakdown of our requirements:

  • Make everything full width & height, using vh units (viewport height)
  • Vertically center the content with table-cell display
  • Apply a tinted overlay to bg images via a pseudo-element
  • Absolutely position the list items for our background-images and ensure they fill available space via background-size: cover
  • Apply smaller images to mobile and larger to desktop with a min-width media query
  • Create a simple opacity keyframe animation and apply it to our list of background images sequentially via animation-delay and the :nth-child() selector
First the Banner Section and Content
/*----------------------------------------------   
--Banner
-----------------------------------------------  */
.sect-banner{
 display: table;
 width: 100%;
 margin: 0 auto;
 text-align: center;

 /*-- Full Height --*/
 height: 100vh;
 color:	rgba(255,255,255,0.9);

 /*-- Create an Overlay --*/
 &:after{
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background-color: rgba(118, 144, 164, 0.4);
  z-index: 0;
 }

 /*-- Vertically center --*/
 .v-center{
  display: table-cell;
  vertical-align: middle;
  position: relative;
  z-index: 4;
  padding: 0 5%;
 }
}
Now our simple opacity keyframes animation
/*----------------------------------------------   
--Keyframes
-----------------------------------------------  */
@include keyframes(fade-out) {
 33%{
  opacity: 1
 }
 66%{
 opacity: 0
 }
}
Finally, our list to apply background images and declare animations
/*----------------------------------------------   
--List for images, sm and large
-----------------------------------------------  */
ul.kf-slider{
 li{ 	
  height: 100%;
  width: 100%;
  position: absolute;
  top: 0;
  background-size: cover;
  background-repeat: no-repeat;
  background-position:	50%;
  z-index: 0;
  opacity: 0;
  /*-- Add animation --*/ 
  @include animation(fade-out 9s infinite both);
  /*-- Image 1: small --*/ 
  background-image: url(../images/banner-1-sm.jpg);
  @media (min-width: 32ems){
   /*-- Image 1: large --*/ 
   background-image: url(../images/banner-1.jpg);
  }
 }
 /*-- Image 2 --*/ 
 li:nth-child(2){
  background-image: url(../images/banner-2-sm.jpg);
  /*-- Animation delay: 3s --*/ 
  @include animation-delay(3s);
  @media (min-width: 32ems){
   background-image: url(../images/banner-2.jpg);
  }
 }
 /*-- Image 3 --*/ 
 li:nth-child(3){
  background-image: url(../images/banner-3-sm.jpg);
  /* Animation delay: 6s */  
  @include animation-delay(6s);
  @media (min-width: 32ems){
   background-image: url(../images/banner-3.jpg);
  }
 }
}

uiblog-kfslider-ex

Our page with styles

What’s Going On Here?

The list items of .kf-slider are each assigned a background-image and absolutely positioned atop one another. We then reveal each layer sequentially by animating its opacity via our fade-out keyframe animation.

Since the total animation-time is set to 9 seconds, we target each image with the :nth-child() selector and apply a 3 second animation-delay. So, image 1 is shown for 3 secs, then fades to reveal image 2 for 3 secs, then image 3 for 3 secs. A continual loop is achieved by setting the animation-iteration-count to infinite.

Of course, we’re using Bourbon to eliminate prefixing and keep the authorship of our animations and keyframes super tidy. If you prefer Compass, here’s an animation plugin by Eric Suzanne that adopts an identical syntax.

Gimme A Demo

You got it. Here’s a Demo

Approach 2: Tweening Background Images

There’s an even easier method to achieve this effect by tweening the background images – which actually creates a way more silky smooth experience. Unfortunately, background-image can only be animated in webkit currently, but since this effect is presentational, a static fallback is fine if you ask me. Look at it like a little reward nugget for using a better browser.

Set Up

Our markup is essentially the same, but instead of a unordered list, we’ll just use a single div called banner-bg to house our images and new keyframe animations.

<section class="sect-banner">

 <!--Div to house the background-->
<div class="banner-bg"></div>
	
<div class="v-center">
 <h1>Stupid Simple Slider</h1>
 <p>Silky smooth background image animations with css keyframes</p>	
 </div>
</section>

Animations

Create 2 keyframe animations for small and large images/sizes. Here, instead of animating opacity, we’re actually changing the background-image as the animation progresses. To prevent a jerky jump at the end of the animation cycle, apply the image from the beginning of the animation (0%) at 100%.

/*----------------------------------------------   
--Keyframes Slider - Sm
-----------------------------------------------  */
@include keyframes(slider-sm) {
 0%{
   background-image: url(../images/banner-1-sm.jpg);
 }
 33%{
   background-image: url(../images/banner-2-sm.jpg);
 }
 66%{
   background-image: url(../images/banner-3-sm.jpg);
 }
 100%{
   background-image: url(../images/banner-1-sm.jpg);
 }
}

/*----------------------------------------------   
--Keyframes Slider - Lg
-----------------------------------------------  */
@include keyframes(slider-lg) {
 0%{
   background-image: url(../images/banner-1.jpg);
 }
 33%{
   background-image: url(../images/banner-2.jpg);
 }
 66%{
   background-image: url(../images/banner-3.jpg);
 }
 100%{
   background-image: url(../images/banner-1.jpg);
 }
}

Style It

Now just style your div to position it absolutely inside our parent section (like the list items from demo 1), applying fallbacks and our new keyframe animations at large and small sizes with a min-width media query.

/*----------------------------------------------   
-Banner Bg
-----------------------------------------------  */	
.banner-bg{
 height: 100%;
 width: 100%;
 position: absolute;
 top: 0;
 background-size: cover;
 background-repeat: no-repeat;
 background-position:50%;
 z-index:0;

 /*-- Fallback image for mobile --*/
 background-image:	url(../images/banner-1-sm.jpg);

 /*-- Add mobile keyframe animation --*/
 @include animation(slider-sm ease-in-out 30s both infinite);
	
 @media (min-width: 32ems) {
  /*-- Fallback image for desktop --*/
  background-image:url(../images/banner-1.jpg);

  /*-- Add desktop keyframe animation via bourbon mixin --*/
  @include animation(slider-lg ease-in-out 30s both infinite);
 }
}

Got a Demo?

You know it. Here’s a Demo

How About a Download?

Oh, for sure. Grab the files on Github