Easy Background Image Slideshow

Need to have a container change a background automatically?

I didn't know you can not use transitions with background-image on a single container. It will give you lots of troubles on different browsers.
What you can do is use opacity transitions with multiple containers.

Demo

View Demo

HTML

You can modify this to fit your needs. In my case I wanted the images to behave as background, under my content.

<div class="container"> <div class="content">We could have anything here</div> <div class="slide show" style="background-image: url('image-1.jpg');"></div> <div class="slide" style="background-image: url('image-2.jpg');"></div> <div class="slide" style="background-image: url('image-3.jpg');"></div> </div>

CSS

The basic CSS below. In my demo I've added extra CSS to position another container inside it. So I can have the slides as background under the content.

.container { height: 500px; /* It can be anything you need */ position: relative; width: 100%; } .container .slide { background-position: center center; background-repeat: no-repeat; background-size: cover; height: 100%; left: 0; opacity: 0; position: absolute; top: 0; transition: opacity 1s ease-in-out; width: 100%; z-index: 1; } .container .slide.show { opacity: 1; }

JavaScript (no jQuery!)

Now our function, which does the rotation magic:

/** * @param {number} interval (in milliseconds) */ function cycleBackgrounds(interval) { let index = 0 const $imageEls = document.querySelectorAll('.container .slide') // Get the images to be cycled. setInterval(() => { // Get the next index. If at end, restart to the beginning. index = index + 1 < $imageEls.length ? index + 1 : 0 // Show the next $imageEls[index].classList.add('show') // Find the previous. const previous = index - 1 < 0 ? $imageEls.length - 1 : index - 1; // Hide the previous $imageEls[previous].classList.remove('show') }, interval) }

Wait until the page has loaded to fire the function.

document.addEventListener("DOMContentLoaded", function() { cycleBackgrounds(2000); });

Performance and UX

You can tell the browser to preload the images in the carousel, so it doesn't flicker in case the next slide is shown and the image hasn't loaded yet.

Potentially this lines could improve the UX in this component for your users. Add the lines with your images in the head:

<link rel="preload" href="images/image-1.jpeg" as="image"> <link rel="preload" href="images/image-2.jpeg" as="image"> <link rel="preload" href="images/image-3.jpeg" as="image">

Other ideas:

24 comments
  • I added your code to my site exactly as you have it yet it’s not working, only the 1st image loads.

    • Unfortunately the code is not as easy as plug and play. Some tweaking might be needed.

      Impossible for me to predict every case πŸ™‚

  • Can u tell me about path in html……I mean how to set path.

  • I could get the slideshow to work but, the text also shows as part of the slideshow. Like, it has its own slide. Do you have any idea how fix this? Thanks in advance.

  • Works great, thank you.

    Only, the first slide stays longer than all other slides. I guess the JS would need some change. But I don’t know much of it.

  • This works wonderfully! Thanks! I have one question. I am trying to add Forward and Backwards buttons for clicking through the background images. I’m not too good with Jquery, but here is the updated code that I’ve come up with:

    function cycleBackgrounds() { var index = 0; $imageEls = $('.product-slide-show .slide'); // Get the images to be cycled. setInterval(function () { // Get the next index. If at end, restart to the beginning. index = index + 1 < $imageEls.length ? index + 1 : 0; // Show the next $imageEls.eq(index).addClass('show'); // Hide the previous $imageEls.eq(index - 1).removeClass('show'); }, 4000); $("#forward").click(function(){ $imageEls.eq(index + 1).addClass('show'); $imageEls.eq(index).removeClass('show'); }); $("#backwards").click(function(){ $imageEls.eq(index - 1).addClass('show'); $imageEls.eq(index).removeClass('show'); }); }; // Document Ready. $(function () { cycleBackgrounds(); });

    It somewhat works, but not quite the way it should:
    1) The timer doesn’t start over when the button is clicked.
    2) The button clicks only work one time until the next slide is displayed.
    3) If the forward button is clicked when the last image is currently displayed, a blank background will show.

    Any help would be much appreciated!

    Thanks,
    Shayne

    • Nevermind. I figured it out. It might not be the most elegant way, but it works πŸ™‚

      var index = 0; $imageEls = $('.product-slide-show .slide'); // Get the images to be cycled. var interval; function cycleBackgrounds() { interval = setInterval(function () { // Get the next index. If at end, restart to the beginning. index = index + 1 < $imageEls.length ? index + 1 : 0; // Show the next $imageEls.eq(index).addClass('show'); // Hide the previous $imageEls.eq(index - 1).removeClass('show'); }, 8000); }; //Next Button function getNext() { index = index + 1 < $imageEls.length ? index + 1 : 0; $imageEls.eq(index).addClass('show'); $imageEls.eq(index -1).removeClass('show'); clearInterval(interval); cycleBackgrounds(); } //Back Button function getPrev() { index = index - 1 < 0 ? $imageEls.length : index - 1; $imageEls.eq(index).addClass('show'); $imageEls.eq(index + 1).removeClass('show'); clearInterval(interval); cycleBackgrounds(); } // Document Ready. $(function () { cycleBackgrounds(); $('#prod-forward').on('click', getNext); $('#prod-backwards').on('click', getPrev); });
      • It’s not bad, perhaps you could move into variables the class. In case it ever changes. Also move from ID to CLASS for the forward and backwards selectors.

        Best regards

  • Unfortunately if you have links in your slide show, this solution will not work. It alwAys points to link in the last slide in the list.

  • Thanks for sharing this.. can I use two instances of this script on a page?
    Kindly provide a hint how to.. thanks again.

    • Hello,

      Sure, with a little change. Basically to iterate on the containers.

      HTML

      <div class="container"> <div class="content">We could have anything here</div> <div class="slide show" style="background-image: url('https://placeimg.com/640/480/animals');"></div> <div class="slide" style="background-image: url('https://placeimg.com/640/480/people');"></div> <div class="slide" style="background-image: url('https://placeimg.com/640/480/nature');"></div> </div> <div class="container"> <div class="content">We could have anything here</div> <div class="slide show" style="background-image: url('https://placeimg.com/640/480/animals');"></div> <div class="slide" style="background-image: url('https://placeimg.com/640/480/people');"></div> <div class="slide" style="background-image: url('https://placeimg.com/640/480/nature');"></div> </div>

      JavaScript

      function cycleBackgrounds() { $containers = $('.container'); $containers.each(function() { let $imageEls = $(this).find('.slide'); // Get the images to be cycled. let index = 0; setInterval(function () { // Get the next index. If at end, restart to the beginning. index = index + 1 < $imageEls.length ? index + 1 : 0; // Show the next $imageEls.eq(index).addClass('show'); // Hide the previous $imageEls.eq(index - 1).removeClass('show'); }, 2000); }); }; // Document Ready. $(function () { cycleBackgrounds(); });
  • I’m getting an from the JS

    TypeError: $ is not a function. (In '$(function () { cycleBackgrounds(); })', '$' is undefined)
    • Hello Brian,

      You need to include jQuery like so:

      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

      Best regards

  • Is there an easy way to randomise the image order?

  • Is there a simple or not so simple way to add a link to one of the images so if its clicked on it will go to another site or page? I have tried many options I have found online but none of them seem to work…. I thought it might be a z-index issue but I cant seem to resolve it… any thoughts?

    • You could add a link inside the slide:

      <div class="slide" style="background-image: url('image-1.jpeg');"> <a href="https://google.com" rel="nofollow ugc">Italia</a> </div>

      And then make those links take the full space of the image with CSS:

      .slide a { position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 2; }

      Hope this helps.

  • Brilliantly simple little piece of code, Ricard. Thanks. Just one question: is there a way to load the images asynchronously? I have seven or eight big images in my slideshow and they are slowing down the loading of the page.

  • Ricard
    Thanks for that quick reply. I thought the loading attribute might be the key, but unfortunately it defers loading of off-screen images, presumably meaning those outside the viewport, and the slideshow is at the top of the page and therefore within the viewport when the page opens.
    For the moment I’ve sort-of taken on your first suggestion. Although in an ideal world I really do need plenty of images in the slideshow, I’m going to select four images at random from an array and use those. This means that each time a person comes back to the page they will see some different images. Not ideal in some ways, but it does allow me to put even more images into the array.

    • The random slides it’s a nice compromise!

      I guess you already considered optimizing the files themselves? Agressive JPG lossless compression? Here’s a tool for you: https://tinypng.com/

      What about serving in modern formats such as “webp” for the supported browsers? If you know your way around a webserver you could even play with mod_pagespeed https://www.modpagespeed.com/ that does the image optimization on the fly for you.

      If you use WordPress or similar there are also tools that generate next generation image formats optimized images such as https://es.wordpress.org/plugins/webp-express/

      Thank you for the discussion. Web performance is fascinating πŸ™‚

  • I’m not sure it’s a nice compromise, but it’s a compromise. πŸ˜‰
    Yes, I do already optimise jpg files, though maybe I could push the compression a little further. I currently use 50 as a matter of course, which gives me 1000-1400px wide images around 80k-160k. I’ll experiment with more aggressive compression to see if there are any more gains to be made.
    I looked at tinypng and tried a few files. It came back with gains of 0-5% so I’m unlikely to pursue that further.
    I also looked at webp, but it seems that the software for creating webp images won’t run on my Mac OSX 10.12.
    Messing with a webserver is not for me (!!!) but I have written a set of PHP functions for creating thumbnails on my site.
    Thanks for all the help.

Leave a Reply

Add <code> Some Code </code> by using this tags.

*
*