In this tutorial you’ll learn how to create a responsive full-screen slideshow with plain JavaScript. To build it, we’ll go through several different front-end tricks. As a bonus, we’ll go a step further and customize the cursor’s appearance as we hover over the slideshow.
As usual, to get an initial idea of what we’ll be building, take a look at the related CodePen demo (check out the larger version for a better experience):
Note: This tutorial won’t discuss how to make the slideshow more accessible (e.g. the buttons). We’ll mainly focus on the CSS and JavaScript.
1. Begin With the Page Markup
To create the slideshow, we’ll need an element with the slideshow
class. Within it, we’ll place a list of slides along with the navigation arrows.
Each slide will contain a background image. Of course, if you like, feel free to add additional content,
By default, the first slide will appear. But, we can configure that behavior by attaching the is-active
class to the desired slide.
Here’s the required markup:
<div class="slideshow"> <ul class="slides"> <li class="slide is-active"> <div class="cover" style="background-image: url(IMG_SRC);"></div> </li> <li class="slide"> <div class="cover" style="background-image: url(IMG_SRC);"></div> </li> <li class="slide"> <div class="cover" style="background-image: url(IMG_SRC);"></div> </li> </ul> <div class="arrows"> <button class="arrow arrow-prev"> <span></span> </button> <button class="arrow arrow-next"> <span></span> </button> </div> </div> <main>...</main>
2. Define the Styles
With the markup ready, we’ll continue with the main styles of our slideshow.
Stacking Slides
By default, all slides will be stacked on top of another. They will all be hidden, apart from the active slide.
To stack the images, we’ll take advantage of CSS Grid. In fact, I’ve already covered this technique and its advantages compared to the traditional positioning in a recent tutorial.
Here are the associated styles:
.slideshow .slides { display: grid; } .slideshow .slide { grid-column: 1; grid-row: 1; opacity: 0; transition: opacity 0.4s; } .slideshow .slide.is-active { opacity: 1; }
Each div
inside a slide will receive the cover
class. This will convert its background image into a full-screen background image:
.cover { background-size: cover; background-repeat: no-repeat; background-position: center; height: 100vh; }
Navigation
The navigation buttons will be absolutely positioned inside the slideshow. Each of the buttons should cover half of the slideshow width, and their height should be equal to the slideshow height.
Initially, all buttons will be hidden. But, as we start moving the cursor within the slideshow, the corresponding button will appear depending on the mouse position.
Each span
inside a button will have an arrow (left or right) as a background image.
By default, the color of these arrows will be black. However, as we move the cursor inside the slideshow, their color should change and create a contrast against the slide images. The trick for creating this effect is to add mix-blend-mode: difference
(or exclusion
) and filter: invert(1)
to the span
s.
To learn more about how various blend modes work in CSS (and what alternatives are available to you) take a look at this guide to blend modes by Jonathan Cutrell:
Moving on, the styles for the navigation are below:
.slideshow { cursor: none; } .slideshow .arrows { position: absolute; top: 0; left: 0; display: flex; width: 100%; height: 100%; overflow: hidden; } .slideshow .arrows .arrow { position: relative; width: 50%; cursor: inherit; visibility: hidden; overflow: inherit; } .slideshow .arrows .is-visible { visibility: visible; } .slideshow .arrows span { position: absolute; width: 72px; height: 72px; background-size: 72px 72px; mix-blend-mode: difference; filter: invert(1); } .slideshow .arrow-prev span { background-image: url(slider-prev-arrow.svg); } .slideshow .arrow-next span { background-image: url(slider-next-arrow.svg); }
3. Add the JavaScript
Let’s now add interactivity to our slideshow!
For this example, the slideshow will come with three default options which we can customize by specifying the associated custom attributes:
Option | Default Value | Description |
---|---|---|
autoplay |
false | Make slideshow autoplay. |
autoplay-interval |
4000 | The interval time between switching slides in milliseconds. |
stop-autoplay-on-hover |
false | Stop autoplay mode on hover. |
Variables
Before digging into these options, as a first step, we’ll define a bunch of variables which we’ll use later:
const slideshow = document.querySelector(".slideshow"); const list = document.querySelector(".slideshow .slides"); const btns = document.querySelectorAll(".slideshow .arrows .arrow"); const prevBtn = document.querySelector(".slideshow .arrow-prev"); const prevBtnChild = document.querySelector(".slideshow .arrow-prev span"); const nextBtn = document.querySelector(".slideshow .arrow-next"); const nextBtnChild = document.querySelector(".slideshow .arrow-next span"); const main = document.querySelector("main"); const autoplayInterval = parseInt(slideshow.dataset.autoplayInterval) || 4000; const isActive = "is-active"; const isVisible = "is-visible"; let intervalID;
Initializing Things
When all page assets are ready, we’ll call the init
function.
window.addEventListener("load", init);
This function will fire four sub-functions:
function init() { changeSlide(); autoPlay(); stopAutoPlayOnHover(); customizeArrows(); }
As we’ll see in a moment, each of these functions will accomplish a certain task.
Loop Through Slides
The changeSlide
function will be responsible for looping through slides.
Each time a button is clicked, we’ll perform the following actions:
- Grab a copy of the currently active slide.
- Remove the
is-active
class from the active slide. - Check to see which button is clicked. If that’s the next button, we’ll add the
is-active
class to the slide which immediately follows the active slide. If there isn’t such a slide, the first slide will receive this class. - On the other hand, if the previous button is clicked, we’ll add the
is-active
class to the previous slide of the active slide. If there isn’t such a slide, the last slide will receive this class.
Here’s the signature of this function:
// variables here function changeSlide() { for (const btn of btns) { btn.addEventListener("click", e => { // 1 const activeSlide = document.querySelector(".slide.is-active"); // 2 activeSlide.classList.remove(isActive); // 3 if (e.currentTarget === nextBtn) { activeSlide.nextElementSibling ? activeSlide.nextElementSibling.classList.add(isActive) : list.firstElementChild.classList.add(isActive); } else { // 4 activeSlide.previousElementSibling ? activeSlide.previousElementSibling.classList.add(isActive) : list.lastElementChild.classList.add(isActive); } }); } }
Autoplay
The autoplay
function will be responsible for activating the autoplay mode.
By default, we have to manually cycle through the slides.
To activate autoplay, we’ll add the data-autoplay="true"
attribute to the slideshow.
We can also adjust the interval time between switching slides by defining the data-autoplay-interval="number"
(default is 4000ms) as a second attribute, like this:
<div class="slideshow" data-autoplay="true" data-autoplay-interval="6000"> ... </div>
Here’s the signature of this function:
// variables here function autoPlay() { if (slideshow.dataset.autoplay === "true") { intervalID = setInterval(() => { nextBtn.click(); }, autoplayInterval); } }
Stop Autoplay
The stopAutoplayOnHover
function will be responsible for disabling the autoplay mode when hovering the slideshow.
To enable this functionality, we’ll pass the data-stop-autoplay-on-hover="true"
attribute to the slideshow, like this:
<div class="slideshow" data-stop-autoplay-on-hover="true"> ... </div>
Here’s the signature of this function:
// variables here function stopAutoPlayOnHover() { if ( slideshow.dataset.autoplay === "true" && slideshow.dataset.stopAutoplayOnHover === "true" ) { slideshow.addEventListener("mouseenter", () => { clearInterval(intervalID); }); // touch devices slideshow.addEventListener("touchstart", () => { clearInterval(intervalID); }); } }
Customizing Arrows
The customizeArrows
function will be responsible for manipulating the visibility of the navigation buttons and the position of their spans.
As we’ve discussed before, the navigation buttons will initially be hidden.
As we move the mouse inside the slideshow, only one of them will appear at a time depending on the mouse position. The position of its span element will also depend on the coordinates of the mouse pointer.
As soon as we leave the slideshow, the buttons will become hidden again.
To accomplish these requirements in various screens/devices, we’ll use two mouse events along with two touch events.
Here’s the code that implements this functionality:
// variables here function customizeArrows() { slideshow.addEventListener("mousemove", mousemoveHandler); slideshow.addEventListener("touchmove", mousemoveHandler); slideshow.addEventListener("mouseleave", mouseleaveHandler); main.addEventListener("touchstart", mouseleaveHandler); } function mousemoveHandler(e) { const width = this.offsetWidth; const xPos = e.pageX; const yPos = e.pageY; const xPos2 = e.pageX - nextBtn.offsetLeft - nextBtnChild.offsetWidth; if (xPos > width / 2) { prevBtn.classList.remove(isVisible); nextBtn.classList.add(isVisible); nextBtnChild.style.left = `${xPos2}px`; nextBtnChild.style.top = `${yPos}px`; } else { nextBtn.classList.remove(isVisible); prevBtn.classList.add(isVisible); prevBtnChild.style.left = `${xPos}px`; prevBtnChild.style.top = `${yPos}px`; } } function mouseleaveHandler() { prevBtn.classList.remove(isVisible); nextBtn.classList.remove(isVisible); }
Conclusion
That’s it, folks! In this tutorial, we managed to implement a flexible full-screen slideshow by writing pure JavaScript code. Hopefully, you enjoyed this journey and gained some new knowledge!
Here’s a reminder of what we built:
Next Steps
There are so many things that you can do to enhance the functionality of this slideshow. Here are some thoughts:
- Add swipe support and keyboard navigation. As a starting point, you can have a look at this tutorial.
- So far, the slides appear with a fade animation. Build other animation modes like slide and scale.
- Make the slideshow emit custom events when a new slide comes into view.
- Make the code more reusable and solid. You might want to use Prototypal inheritance, ES6 classes, or another JavaScript design pattern.
- Implement a fallback scenario for browsers that don’t support CSS filter effects (e.g. some versions of Microsoft Edge) for the navigation arrows.
As always, thanks a lot for reading!
Learn More About JavaScript Slideshows
Check out these tutorials to learn more about how to create powerful JavaScript slideshows:
-
CSS SelectorsHow to Build a Simple Slideshow With the CSS Checkbox Hack
-
jQueryHow to Build a Full-Screen Responsive Carousel Slider With Owl.js
-
jQueryHow to Build an Attractive Responsive Image Gallery With slick.js
No comments:
Post a Comment