New week! New Challenge! 😄
The theme for the second week of the Weekly Coding Challenge is:
Create a Slider
A slider is used mostly to showcase content like: images, projects in your portfolio or even testimonials from clients. It is useful because you have this content focused in a screen which changes at a certain time, like every 5 seconds, and highlights the next item from your showcase.
In this article we’re going to build the following Full Page Slider:
https://codepen.io/FlorinPop17/pen/LvOroe/
As you can see it has a fun little animation which erases the current item and highlights the next one. The next slide comes in automatically (after a few seconds) but you could also change the slide by clicking on the navigation buttons, which is pretty neat if you ask me! 😃
Let’s see how we can build this!
Gathering the resources
First thing that we need to do is to get the images which will be used in the slider. For this, Unsplash is the perfect place! It has beautiful, free photos which could be used in any project!
Next, we need the icons for the navigation buttons. As always I choose to use FontAwesome.
The HTML
We’ll add everything in a main .slider
div, and by everthing I mean the following:
- a
.slider-container
div which will hold all the.slide
’s with the images (the class will be used in JavaScript to get all the.slide
children of this div) - an
.eraser
div which will be used in the erasing animation. Basically this will slowly hide the current item in the slider, and when it reaches the end, we quickly swap it out with the next.slide
- the
.buttons-container
which holds the two navigation buttons and it has two FontAwesome icons
<div class="slider">
<div class="slider-container">
<!-- See bellow for the content of this div -->
</div>
<div class="eraser"></div>
<div class="buttons-container">
<button id="previous"><i class="fa fa-arrow-left"></i></button>
<button id="next"><i class="fa fa-arrow-right"></i></button>
</div>
</div>
Now, for the .slide
s…
We put the image directly in the style
prop of the <div>
. This is because I don’t want to have in the CSS multiple declarations for each .slide
separately just to add a background-image
property. It’s also useful if in the future we want to convert this slider and have the .slide
s added dynamically using React or Vue or anything else. 🙂
Also, we add a div (.info
) within it that will have some additional text we want to display on top of the image. This is optional, you can remove it if you want.
<div class="slider">
<div class="slider-container">
<div
class="slide active"
style="background-image: url('add_image_url_here');"
>
<div class="info">
<h1>Ocean View</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Voluptatum.
</p>
</div>
</div>
<div class="slide" style="background-image: url('add_image_url_here');">
<div class="info">
<h1>Forest View</h1>
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit.
Amet, vero earum perspiciatis officia
</p>
</div>
</div>
<div class="slide" style="background-image: url('add_image_url_here');">
<div class="info">
<h1>Ocean View</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
Incidunt recusandae unde autem
</p>
</div>
</div>
<!-- The rest of the slides -->
</div>
<!-- The rest of the content -->
</div>
Important
The first .slide
has an .active
class set on it. We’ll use this later to track in the JavaScript which .slide
is visible/active at a certain time.
Note that the script will fail if
- you have multiple
.slide
s with an.active
class or - you don’t have a
.slide
with an.active
class
The CSS
As we want the Slider to be Full Width, we need to either use Normalize CSS or to have some simple resets in the CSS.
@import url('https://fonts.googleapis.com/css?family=Lato');
* {
box-sizing: border-box;
}
body {
font-family: 'Lato', sans-serif;
margin: 0;
}
(I also added the Lato font as I decided to have some text in the Slider. You can remove the import if you don’t have any text or you can add your own font to the body
tag).
The .slide
s will need to be positioned absolute
if we want to move them around and that means that we’ll have to have a relative
positioned parent, that would be the .slider
div.
.slider {
position: relative;
overflow: hidden;
height: 100vh;
width: 100vw;
}
.slide {
background-position: center center;
background-size: cover;
position: absolute;
top: 0;
left: 100%;
height: 100%;
width: 100%;
}
.slide.active {
transform: translateX(-100%);
}
Few things to note here:
- 100vh and 100vw means that the
.slider
should be as wide as the screen (vh - viewport height, vw - viewport width) - initially we have the
.slide
positioned outside the viewport with theleft
property set to100%
, and we’lltranslate
it back to0
when the.active
class is set on it (left: 100%
+translateX(-100%)
=left: 0
)
The next piece of code is optional. Only use it if you want to have the text over the .slide
:
.slide .info {
background-color: rgba(255, 255, 255, 0.7);
color: #333;
padding: 20px 15px;
position: absolute;
opacity: 0;
top: 70px;
left: 30px;
text-align: center;
width: 300px;
max-width: 100%;
}
.slide.active .info {
opacity: 1;
transform: translateY(-40px);
transition: all 0.5s ease-in-out 0.6s;
}
.slide .info h1 {
margin: 10px 0;
}
.slide .info p {
letter-spacing: 1px;
}
There’s a transition
which will add the moving up effect to the .info
div and also will change the opacity
, just a little touch I wanted to add. 🙂 Also there is a delay
to the transition
of 0.6s
- this is enough to wait until the .eraser
is moving out of the way so the text transition is visible.
Speaking of which… The .eraser
CSS:
.eraser {
background: #fff;
position: absolute;
transition: transform 0.7s ease-in-out;
top: 0;
left: 100%;
height: 100%;
width: 100%;
z-index: 100;
}
.eraser.active {
transform: translateX(-100%);
}
The .eraser
is another full height/width div
which has it’s own .active
class (do not confuse this with the .slide
’s active class). This class with be added in JavaScript when we want to change the slide. More about this a little bit later. 😉
Note: the 0.7s
value is important as this will have to be exactly the same with the eraserActiveTime
value used in the JavaScript.
And the last part of the CSS, the .buttons-container
:
.buttons-container {
position: absolute;
bottom: 60px;
right: 20px;
}
.buttons-container button {
border: 2px solid #fff;
background-color: transparent;
color: #fff;
cursor: pointer;
padding: 8px 20px;
}
.buttons-container button:hover {
background-color: #fff;
color: #333;
}
Simple CSS, nothing fancy here. We just position this div absolute
too so we can place it wherever we want in the .slider
.
The JavaScript
This part is where the magic happens. First, we need to set all the variables that we’re going to use (I added comments for all the lines, it should be pretty clear):
const slides = document.querySelectorAll('.slider-container .slide'); // get all the slides
const eraser = document.querySelector('.eraser'); // the eraser
const prev = document.getElementById('previous'); // previous button
const next = document.getElementById('next'); // next button
const intervalTime = 5000; // time until nextSlide triggers in miliseconds
const eraserActiveTime = 700; // time to wait until the .eraser goes all the way
let sliderInterval; // variable used to save the setInterval and clear it when needed
Next, we need to create a function .nextSlide
which will be called every 5 seconds - the intervalTime
. Let’s break this function into steps:
- Add the
.active
class to theeraser
- this will trigger theeraser
to move to the left. - Set a timeout that will allow the
eraser
to move all the way to the left. This is where we’ll use theeraserActiveTime
- it has to be the same as the CSS value we mentioned above. - Get the active
.slide
and toggle the.active
class on it (in this case, remove it). - Check to see if the
.slide
has a next element sibling available. If it has, add the.active
class to it. - If it’s the last element in the list, add the
.active
class to the first slide (the one with index 0). - Remove the
.active
class from theeraser
- this will trigger theeraser
to move back to the right. It also waits 200 ms before doing this (just to give enough time for the next.slide
to move in place).
const nextSlide = () => {
// Step 1.
eraser.classList.add('active');
// Step 2.
setTimeout(() => {
// Step 3.
const active = document.querySelector('.slide.active');
active.classList.toggle('active');
// Step 4.
if (active.nextElementSibling) {
active.nextElementSibling.classList.toggle('active');
} else {
// Step 5.
slides[0].classList.toggle('active');
}
// Step 6.
setTimeout(() => {
eraser.classList.remove('active');
}, 200);
}, eraserActiveTime);
};
sliderInterval = setInterval(nextSlide, intervalTime);
At the end, we set an interval which will run every intervalTime
miliseconds and it will change the slide to the next one, over and over.
The buttons functionality
As of now we have a slider
which will automatically change slides every intervalTime
miliseconds, but we also want to be able to change the .slide
’s manually by pressing the buttons. Before that though, let’s quickly add the prevSlide
function. This is very similar to the nextSlide
function, but instead of going to the next sibling, we go to the previous sibling and when we reset, we set the last slide to be active
:
const prevSlide = () => {
eraser.classList.add('active');
setTimeout(() => {
const active = document.querySelector('.slide.active');
active.classList.toggle('active');
// The *changed* part from the nextSlide code
if (active.previousElementSibling) {
active.previousElementSibling.classList.toggle('active');
} else {
slides[slides.length - 1].classList.toggle('active');
}
// End of the changed part
setTimeout(() => {
eraser.classList.remove('active');
}, 200);
}, eraserActiveTime);
};
Good, we have the functions in place. All we have to do now is to add the eventListeners
to the buttons:
next.addEventListener('click', () => {
nextSlide();
clearInterval(sliderInterval);
sliderInterval = setInterval(nextSlide, intervalTime);
});
prev.addEventListener('click', () => {
prevSlide();
clearInterval(sliderInterval);
sliderInterval = setInterval(nextSlide, intervalTime);
});
This is where we also need to reset the interval as we don’t want it to run while we are pressing the buttons. For this we clear the “old” interval and create a new one.
Aaaand… we’re done! 😃
Conclusion
Congratulations for making it this far! 👏 I hope you liked this slider example and I can’t wait to see what you’re going to build next! 😄
Remember to check out the Weekly Coding Challenge “rules” if you want to participate! It’s a great way to learn by practicing!
Have fun! I surely did! 👍