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