DEV Community

Bilkeesu Babangida
Bilkeesu Babangida

Posted on • Updated on

create a menu fade animation with JavaScript

Introduction

Have you ever hovered over a navigation link on a website and noticed that all the other links fade out, leaving only the one you're hovering over? In this tutorial, you will create that effect using just a few lines of JavaScript.

Here's a demo of the effect we're going to create:

Demo

The HTML

To create a basic navigation, we have a div with the class nav, containing a ul element with the class nav-list. Within the ul, there are five li elements, each with the class nav-link.

<div class="nav">
      <ul class="nav-list">
        <li class="nav-link">Home</li>
        <li class="nav-link">Features</li>
        <li class="nav-link">Operations</li>
        <li class="nav-link">Testimonials</li>
        <li class="nav-link">Contact</li>
      </ul>
    </div>

Enter fullscreen mode Exit fullscreen mode

Styling the navigation

We’ll add some visual styles to the nav

.nav {
        height: 7rem;
        background-color: pink;
        padding: 2rem;
      }
      .nav-list {
        display: flex;
        gap: 3rem;
        justify-content: center;
        align-items: center;
        list-style: none;
      }
      .nav-link {
        transition: all 0.3s;
        font-size: 2.5rem;
        cursor: pointer;
      }

Enter fullscreen mode Exit fullscreen mode

Output:

An image of the navigation bar

The JavaScript

The main properties we need to implement this menu fade effect are:

  • The mouseover event: this event is triggered when a mouse cursor hovers over an element.
  • The mouseout event: this is the opposite of the mouseover event. It happens when a mouse cursor moves away from an element.
  • Opacity: this property will give us the fade-in/fade-out effect.

We’ll start by attaching an event Listener to the common parent of the li, instead of attaching it to each element separately. This method is called event delegation. In case you’re unfamiliar with event delegation, read my article on it here.

let’s select all the elements we’ll use and save them into variables. We’ll use these variables throughout this tutorial.

const nav = document.querySelector(".nav");
const navList = document.querySelector(".nav-list");
const navLink = document.querySelectorAll(".nav-link");
Enter fullscreen mode Exit fullscreen mode

Next step is to add the event listener:

nav.addEventListener("mouseover", function (e) {
  console.log(e.target);
});
Enter fullscreen mode Exit fullscreen mode

You may need clarification here. In the HTML, the li has 2 parents; the ul and the div. You can add the event listener to either of them. I chose to use the div as our parent element. Hence, the event listener was attached to it.

We’re only interested in the event that happens on the li, not on the ul or div. The event object (e) has a target property that helps us identify where an event originated from. This event.target (e.target) is the element where an event happened. In this case, e.target is the element you’re hovering over.
So now If you hover over any of the parent elements, the console will log information about the parent. If you hover over the li, the console will log information about the li. We’ll use this information to isolate only the event coming from the li. Since the li has the class nav-link, we’ll first check if any element we’re hovering over contains this class before adding any functionality.

nav.addEventListener("mouseover", function (e) {
  if (e.target.classList.contains('nav-link')){
    console.log(e.target);
  }
});
Enter fullscreen mode Exit fullscreen mode

Now if you hover over the ul or the div, nothing will appear in the console because they do not contain the nav-link class. If you hover over the li, it will appear in the console because it contains the class.
The next step is to find the sibling elements of the e.target. We’ll do this by selecting the parent nav and then we’ll select all the li children of the nav.

if (e.target.classList.contains("nav-link")) {
  const siblings = e.target.closest(".nav").querySelectorAll(".nav-link");
  }
Enter fullscreen mode Exit fullscreen mode

We used the closest() method to find the nearest parent of the e.target that has the class nav. Then we chained querySelectorAll() to select all its child elements that have the class nav-link. This will give us a node list containing all the li elements. That is the e.target and all its siblings. We’re going to loop over this node list to reduce the opacity of all the sibling elements of the e.target.

nav.addEventListener("mouseover", function (e) {
  if (e.target.classList.contains("nav-link")) {
    const siblings = e.target.closest(".nav").querySelectorAll(".nav-link");

    siblings.forEach((el) => {
      if (el !== e.target) {
        el.style.opacity = "0.5";
 }
    });
  }
});


Enter fullscreen mode Exit fullscreen mode

This code checks if the current element is not e.target (i.e., the element you're hovering over). If it's not, it reduces the element's opacity to 0.5. As a result, when you hover over any navigation link, all other links will fade out, leaving only the hovered link fully visible.

Fadeout

Notice that the links didn’t return to normal when the cursor moved away. This is where the mouseout event comes in handy. Remember, the mouseout event fires off when the cursor moves away from an element. So we’ll attach the mouseout event listener to the nav. The code will be the same as the mouseover event listener except for the opacity. The opacity here will be set to 1 so that the elements will return to their normal state when the cursor moves away.

We’ve successfully implemented the menu fade animation. When you hover over any of the links, the others fade out and if you move the cursor away, they go back to normal (opacity goes back to 1).

Refactoring the code

I’m sure you’ve noticed that we have duplicate code. The code in both the event listeners is the same except for the opacity values. This goes against the D.R.Y (don't repeat yourself) principle. Let’s refactor the code into a function. We’ll call the function inside each event listener and then pass in the event (e) and the opacity as arguments.

How do we call this function in the event listeners? Usually, when we have a function like this, it is passed into the event listener as a callback function.

nav.addEventListener("mouseout", navHover);

Enter fullscreen mode Exit fullscreen mode

The issue here is we want to pass in the event (e) and opacity into this function. Ideally, arguments cannot be passed directly to event listeners. This will always return an error. How do we tell this function to use an opacity of 0.5 in the mouseover event and an opacity of 1 in the mouseout event? The solution would be to still have a regular callback function in the event listener, which JavaScript will call whenever the event happens. Inside this callback, we can then call the navHover function manually and pass in the arguments.

nav.addEventListener("mouseover", function (e) {
  navHover(e, 0.5);
});
nav.addEventListener("mouseout", function (e) {
  navHover(e, 1);
});

Enter fullscreen mode Exit fullscreen mode

This function will be executed as soon as JavaScript executes the callback function.

Conclusion

In addition to learning how to make the cool menu fade animation with a few lines of JavaScript; we’ve also learned how to pass in a function with arguments into an event Listener.

Top comments (2)

Collapse
 
dreama profile image
Dream

Great tutorial! Love how simple and effective this method is for creating a sleek fade effect. Thanks for sharing!

Collapse
 
bilkeesu96 profile image
Bilkeesu Babangida

Thank you for the feedback