create a menu fade animation with JavaScript
Tags: webdev, javascript, beginners, tutorial
Published: 2024-05-19 17:36:41

## Introduction

Have you ever hovered over a navigation link on a site, and all the other navigation links fade out except the link you’re hovering over? Well, you’ll learn how to create this effect with a few lines of JavaScript. Here's a demo of the effect we're going to create:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tem40v75qmiknpu0vynn.gif)

## The HTML
To build a simple navigation, we have a `div` with the class `nav`, which contains a `ul` with the class `nav-list`. Inside the `ul`, we have five `li` 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>

```

## 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;
      }

```
 
Output:

![An image of the navigation bar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6iw6ufl66u2uf14i3ofe.png)

## 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/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](https://dev.to/bilkeesu96/understanding-event-delegation-in-javascript-11em). 
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");

```
Next step is to add the event listener:

```
nav.addEventListener("mouseover", function (e) {
  console.log(e.target);
});

```
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 the `ul` or the `div`. The `event object (e)` has a `target` property, which we can use to know 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);
  }
});

```
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");
  }

```
We used the `closest()` method to find the closest parent of the `e.target` that has the class `nav`. Then we attached `querySelectorAll()` to select all its child elements that have the class `nav-link`. This will give us a node list containing all the `li`. 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";
 }
    });
  }
});


```
This code says that if the current element is not `e.target` ( if it is not the element you’re currently hovering over), reduce its opacity to `0.5`. Now if you hover over any of the navigation links, they all fade out except except the link you’re hovering over. 

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/16ee4p5cxmvzxkp72d6e.png)
Notice that the links didn’t go back 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 add 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 go back to normal when the cursor moves away.
Yay! 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);

```
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);
});

```
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.