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
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>
Code language: HTML, XML (xml)
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;
}
Code language: CSS (css)
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)
}
Code language: PHP (php)
Wait until the page has loaded to fire the function.
document.addEventListener("DOMContentLoaded", function() {
cycleBackgrounds(2000);
});
Code language: JavaScript (javascript)
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">
Code language: HTML, XML (xml)
Other ideas:
- Using the picture element to conditionally load smaller images on mobile and bigger images on desktop.
- Using the native lazy loading attribute (does not have full browser support).
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’m not sure what to you mean. Path depends on where you have your images.
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.
Super hard to say without seeing the code.
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(); });
Code language: PHP (php)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); });
Code language: PHP (php)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>
Code language: HTML, XML (xml)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(); });
Code language: JavaScript (javascript)I’m getting an from the JS
TypeError: $ is not a function. (In '$(function () { cycleBackgrounds(); })', '$' is undefined)
Code language: PHP (php)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>
Code language: HTML, XML (xml)Best regards
Is there an easy way to randomise the image order?
I guess it is possible.
Or you could shuffle the index.
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>
Code language: HTML, XML (xml)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; }
Code language: CSS (css)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.
Thank you Paul!
Ok here are some ideas:
<img src="image.jpg" loading="lazy" alt="..." />
Code language: HTML, XML (xml)More on that here: https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading
Lazy Loading via attribute on images has decent, but not great, support: https://caniuse.com/#feat=loading-lazy-attr
If you still want lazyloading more complex solutions have to be put in place (loading a single pixel image and then detecting if the user has scrolled within the part of the viewport to load the actual image)
I hope this helps!
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.
hi
Thanks for this great article.
You’re welcome !
Hi, I’ve had your code in my pages, thanks for the example !
However, how can I add title on the background and is it possible to create three dot on the background to navigate in pictures ?
Thank you !
(Sorry for my English I’m French.)
Hey Olivier,
Thanks for the feedback.
What you’re asking is not super straightforward to do. You would need custom CSS to position the dots over the images. Then the JavaScript event listeners on the dots to move the index. I’m afraid I can’t code it for you. Perhaps you should look for a code that already has this features built in. Check out this one https://kenwheeler.github.io/slick/ is quite complete.
Good luck!