Introduction

So far in this tutorial, we've seen a fairly decent number of features being added to our simple slider, including navigation buttons, pagination, autoplay and progress bars. Now is the time to consider some stunning CSS skills at work!

In this unit, we shall discover how to get the slides of our slider to navigate with smooth and elegant transitional effects.

Particularly, we'll be looking over the following set of effects:

  • Fade-out-fade-in — the current slide fades out and then the new slide fades in.
  • Fade-out — the current slide fades out revealing the new slide.
  • Fade-out-slide-in — the current slide fades out and at the same time, the new one slides in.
  • Slide — the most basic sliding effect.

In practice, there are literally tons of effects that can be given to a slider such as squeeze, 3D box, flip, rotate and so on.

We consider only a few of them, because either the rest are difficult to code and not worth the grunt work, or simply because they require the most latest and experimental technologies on the browser, that will otherwise fail on older bundles.

Even effects such as fade, slide, etc. may seem easy from the outside, but programatically implementing them in the most compatible way is indeed a task which requires a decent amount of coding and designing experience.

Anyways, it has been a lot of talking, so without wasting any more time, let's dive right into constructing our first effect — fade-out-fade-in.

AJAX course at CodeGuage

How the effect works

Before we can write the code to power the fade-out-fade-in effect, we first need to understand exactly how it works.

Once we understand its idea, only then can we go on and convert that to a real implementation.

So, here's how the effect works:

The current slide is faded out and once it disappears completely, then the new slide is faded in.

Hence the name, 'fade-out fade-in'.

Now with this description in mind, we would like to get you to think about how to implement it in code, using a bunch of questions...

Which of the following CSS properties would we need for fading out a slide?

  • opacity
  • color
  • transform

Which of the following CSS properties would we need for fading out a slide?

  • transition
  • visibility
  • Both A) and B)

We'll be needing only three things at the basic level, to power a fade effect:

  1. The opacity property to control the transparency of the slide.
  2. The visibility property to hide/show the slide.
  3. The transition property to change both the properties above in a smooth manner.

Technically, visibility is not needed for the fade effect — the effect will work the same with just opacity and transition.

The visibility property is simply given to hide/show the element being faded. Without visibility, if the element is faded out, it won't be visible, but still there. Any buttons or other interactive elements in it would be clickable.

Anyways, now that we know what tools to use to construct the fade effect, let's get to the real work.

Basic approach

Let's review what happens in the fade-out-fade-in effect, when we navigate our slider, by calling navigateSlider().

The current slide is faded out and once it disappears completely the new slide is faded in.

Let's first tackle with the first part of the effect — fading out the current slide.

In order to fade out the current slide, we simply need to set the following properties on it: opacity: 0, visibility: hidden and finally transition.

You can go with any parameters for transition as you like. We go with a transition duration of 0.5s and the timing function linear.

The order in which you apply these properties doesn't matter — at the end, they are all applied together after which the next browser repaint is made.

Now to set these properties on the current slide, we can go with the straightforward approach — add them using the JavaScript style property.

Below we have the code, in the navigateSlider() function, that fades out the current slide:

function navigateSlider() {
    /* ... */

    // fade out the current slide
    slides[currentIndex].style.opacity = '0';
    slides[currentIndex].style.visibility = 'hidden';
    slides[currentIndex].style.transition = '0.5s linear';

    currentIndex = newIndex;
}
In the code above, /* ... */ denotes the rest of the code of the navigateSlider() function we created in the previous chapters.

Let's now deal with the second part of the effect — fading in the new slide.

The properties to be added to the new slide are exactly the same as with the current one, except for their values.

Recall that the current slide has to be faded out while the new one has to be faded in; likewise the values of the respective properties on both these slides ought to be different.

Apart from this, there is one more thing different in the case of the new slide. It has be faded in only once the current slide has been faded out. In other words, there is a delay in its appearance.

How can we give this delay? Any ideas?

There are two options: use the setTimeout() function or use the CSS transition-delay feature.

What do you think is easier than the other one?

Well clearly it's the latter option i.e using the transition-delay property of CSS.

With setTimeout() we have to create a new function, write the fade in logic within it, and then pass the transition duration of the first slide as an argument to it. Comparing this to the CSS way, we see that CSS surely outruns JavaScript in terms of simplicity.

Since the transition duration of the current slide was 0.5s in our case, we'll need a transition delay of 0.5s on the new slide. After this delay, the new slide will witness the fade-in effect.

Altogether, we get to the following addition in the navigateSlider() function:

function navigateSlider() {
    /* ... */

    // fade out the current slide
    slides[currentIndex].style.opacity = '0';
    slides[currentIndex].style.visibility = 'hidden';
    slides[currentIndex].style.transition = '0.5s linear';

    // fade in the new slide
    slides[newIndex].style.opacity = '1';
    slides[newIndex].style.visibility = 'visible';
    slides[newIndex].style.transition = '0.5s linear 0.5s';

    currentIndex = newIndex;
}

And this completes our effect! Check it out in the link below.

Live Example

Separation of concerns

Despite the fact that the effect we created above is working perfectly, it is usually recommended to keep CSS away from JavaScript. This is formally known as separation of concerns.

Its hard to maintain CSS in two places — stylesheets and scripts — and is therefore recommended that developers keep CSS limited to stylesheets.

In the code above, we change the styles of the current and new slides manually using the style property. This is an example of CSS in JavaScript, and should be avoided.

But how?

How to change the styles of the current and new slides without writing any CSS in our script?

Well, we can use HTML classes to our advantage.

Define the styles in the classes and then add those classes to the slides in order to apply them. The classes will be defined in the document's stylesheet along with the other CSS rules.

On the other hand, the logic to add/remove the classes will be put in JavaScript.

And this separates both the concerns — the styles are defined in the stylesheet while the logic of the slider is defined in the script.

So, let's think on what class names should we come up with that clearly indicate the purpose of their underlying styles.

The current slide is faded out; so we'll call the class to be given to it 'slider_slide--faded-out' (following the BEM naming convention we've been using throughout our slider's markup).

Here is the definition of .slider_slide--faded-out

.slider_slide--faded-out {
    opacity: 0;
    visibility: hidden;
    transition: 0.5s linear
}

We've gathered all three of the styles here that we previously set on the current slide in navigateSlider() function above (lines 5 - 7).

Over to dealing with the new slide.

The new slide is faded in; thereby, we'll call the class to be given to it 'slider_slide--faded-in'.

Below shown is the definition for .slider_slide--faded-in:

.slider_slide--faded-in {
    opacity: 1;
    visibility: visible;
    transition: 0.5s linear 0.5s
}

With these classes in place, the last thing we have to do is to get them added to the respective slides. And this would obviously be done in our same old navigateSlider() function.

The current slide gets the class .slider_slide--faded-out while the new one gets the class .slider_slide--faded-in:

function navigateSlider() {
    /* ... */

    slides[currentIndex].classList.add("slider_slide--faded-out");
    slides[newIndex].classList.add("slider_slide--faded-in");

    currentIndex = newIndex;
}

Let's try out the slider made by this class toggle logic.

Live Example

Notice any issues?

The fade-out-fade-in effect has just gone — we only get fade-out on the first two navigations, after which even that goes out!

There is definitely something wrong in this slider. Think on it...

Let's break down each step that happens when we navigate for the first time to the right, to understand where the problem lies.

Initially, when the page is loaded, the first slide gets the classes .slider_slide--faded-out and .slider_slide--faded-in added due to the call to navigateSlider(), at the end of the script.

Now when we navigate forward, the first slide (which is the current slide) gets the class .slider_slide--faded-out added, while the second slide (the new slide) gets the class .slider_slide--faded-in added.

Since .slider_slide--faded-out is already there on the first slide, its addition has no effect, and we witness no fade-out effect. It's only the fade in effect that's witnessed.

Going forward once again, the second slide (current one) gets the class .slider_slide--faded-out while the third slide (new one) gets the class .slider_slide--faded-in.

Since the second slide already has the class .slider_slide--faded-in on it, its transition is delayed for 0.5s. As a result, no fade-out effect is seen until 0.5s; at which point the third slide simultaneously fades in as well.

Now from this point onwards, the navigations have no effect — we witness no effect at all.

This happens simply because now all the slides have both the classes .slider_slide--faded-out and .slider_slide--faded-in already on them, and so adding them don't cause any effect.

Reading this long block of text, we can clearly see that the problem is coming from adding the two classes. Or better to say, the problem is coming from the way we are adding the two classes.

The solution is pretty straightforward — when a class is added to a slide, the other class is removed from it. In this way, we can be rest assured that at any point, each slide has exactly one class on it.

In the following code, we accomplish this idea:

function navigateSlider() {
    /* ... */

    slides[currentIndex].classList.add("slider_slide--faded-out");
    slides[currentIndex].classList.remove("slider_slide--faded-in");
    slides[newIndex].classList.add("slider_slide--faded-in");
    slides[newIndex].classList.remove("slider_slide--faded-out");

    currentIndex = newIndex;
}

The current slide gets the class .slider_slide--faded-out, so we remove the other one from it i.e .slider_slide--faded-in. Similarly, the new slide gets the class .slider_slide--faded-in, so we remove the other one from it i.e .slider_slide--faded-out.

Let's now see the slider.

Live Example

Voila! Our efforts paid back.