Activate CSS Animation with a Click using JavaScript

I'm trying to create a simple hamburger icon that triggers a CSS animation on click using pure Javascript (no jQuery). Currently, I have the animation working when adding a class to the hamburger icon, but when I remove the class, the animation abruptly resets without animating. How can I make the animation reverse and smoothly return to its original position?

Here's the code snippet:

var hamburgerMenu = document.querySelector('.hamburger-menu');
hamburgerMenu.addEventListener('click', function() {
  var hamburgerMenuSpan2 = document.querySelector('.hamburger-second');

  hamburgerMenuSpan2.classList.toggle('hamburger-line-2');
});
.hamburger-menu {
  position: absolute;
  top: 20px;
  right: 20px;
}

.hamburger-line-2 {
  animation-name: animate;
  animation-duration: 3s;
  animation-timing-function: ease-in-out;
  animation-fill-mode: forwards;
  animation-direction: alternate;
}

@keyframes animate {
  0% {
    width: 40px;
  }
  100% {
    width: 0px;
  }
}

.hamburger-menu span {
  display: block;
  width: 40px;
  height: 2px;
  background: black;
  margin: 10px 0px;
}
<div class="hamburger-menu">
  <span class="hamburger-line-1"></span>
  <span class="hamburger-second"></span>
  <span class="hamburger-line-3"></span>
</div>

Essentially, I want the hamburger icon line to shrink to 0px width on click with a defined duration, and then expand back to its original width smoothly when clicked again.

Answer №1

It may not be the prettiest solution, but it gets the job done:

var hamburgerMenu = document.querySelector('.hamburger-menu');
hamburgerMenu.addEventListener('click', function() {
  var hamburgerMenuSpan2 = document.querySelector('.hamburger-second');

  if (hamburgerMenuSpan2.classList.contains("animate-out")) {
    hamburgerMenuSpan2.classList.remove("animate-out");
    hamburgerMenuSpan2.classList.add("animate-in");
  } else {
    hamburgerMenuSpan2.classList.add("animate-out');
    hamburgerMenuSpan2.classList.remove("animate-in');
  }

});
.hamburger-menu {
  position: absolute;
  top: 20px;
  right: 20px;
}

.hamburger-line-2 {
  animation-duration: 3s;
  animation-timing-function: ease-in-out;
  animation-fill-mode: forwards;
  animation-direction: alternate;
}

.animate-out {
  animation-name: animate-out;
}

.animate-in {
  animation-name: animate-in;
}

@keyframes animate-out {
  0% {
    width: 40px;
  }
  100% {
    width: 0px;
  }
}

@keyframes animate-in {
  0% {
    width: 0px;
  }
  100% {
    width: 40px;
  }
}

.hamburger-menu span {
  display: block;
  width: 40px;
  height: 2px;
  background: black;
  margin: 10px 0px;
}
<div class="hamburger-menu">
  <span class="hamburger-line-1"></span>
  <span class="hamburger-second hamburger-line-2"></span>
  <span class="hamburger-line-3"></span>
</div>

Answer №2

If you have the freedom to utilize CSS transition, then this method could serve as an effective solution.

var hamburgerMenu = document.querySelector('.hamburger-menu');
hamburgerMenu.addEventListener('click', function() {
  var hamburgerMenuSpan2 = document.querySelector('.hamburger-second');

  if (hamburgerMenuSpan2.classList.contains('low-width')) {
    hamburgerMenuSpan2.classList.remove('low-width');
  } else {
    hamburgerMenuSpan2.classList.add('low-width');
  }
});
.hamburger-menu {
  position: absolute;
  top: 20px;
  right: 20px;
}

.hamburger-second {
  transition: width 3s ease-in-out;
}

.low-width {
  width: 0px !important;
}

.hamburger-menu span {
  display: block;
  width: 40px;
  height: 2px;
  background: black;
  margin: 10px 0px;
}
<div class="hamburger-menu">
  <span class="hamburger-line-1"></span>
  <span class="hamburger-second"></span>
  <span class="hamburger-line-3"></span>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Delete the rows in a table's column

I used Bootstrap to create a table. The goal was to have a table with rows that have different background colors for each row. However, I'm facing an issue where there is spacing between the columns when separating the rows. How can I remove this sp ...

Are there restrictions on the amount of Client-Side requests allowed for the Google Custom Search API?

My Google Developers account states that the limit is set at 1,000 requests per day for a specific API key. My question is whether this limit applies to the server or the client side. I am currently using the deprecated API for making AJAX requests on the ...

What is the best way to send multiple data values (such as radio button selections and selections from two drop-down boxes) in a single anchor tag using jQuery?

Using jQuery to Pass Multiple Values in Anchor Tag Href country name state name quetion_id(radio button) Include an anchor tag (options) By clicking the anchor tag, you can pass the country name, state name, and question id to the href link using jQuer ...

Tips for sharing data between React components without causing re-renders or relying on JSX, such as through a function within functional components

As a beginner in react, I have been struggling to find answers to this issue. I am trying to figure out how to pass data from one functional component to another in react without actually rendering the child component. Does anyone know a solution for this ...

Navigate to a precise point in a video using react hooks in videojs

I am currently working on adding a feature that allows users to skip forward or backward by 15 seconds in a video. However, I am encountering difficulties when it comes to updating and setting the current time accordingly. const videoNode = useRef(null); ...

Why does the name not appear when I first click the button, only 'emit'?

I am attempting to utilize eventemiter in order to send a name when clicking a button, but it doesn't seem to be working as expected. The issue I am facing is that the name is not displayed the first time I click the button, however, if I click it aga ...

Guide on showing Laravel variables as JSON in Laravel view with Charts.js

I am currently working on a project using Laravel 7 with MySQL and Charts.js. I'm facing an issue in echoing/displaying the data of two columns ("player_name" and "kills") from my MySQL database in JSON format. Typically, Laravel provides a @foreach l ...

Using a variety of objects in TypeScript arrays

How to effectively implement a superior class in TypeScript for an array containing diverse objects that inherit from the same class, without triggering errors? This is my attempt: interface IVehicle{ modelName: string } interface ICar extends IVehi ...

Ways to resolve the issue of my sidebar displaying at the bottom of the page on smaller screens

Below is the code snippet that generates a Bootstrap page with lorem text and a sidebar. The issue I am facing is that when the browser window size gets smaller, the sidebar appears at the bottom instead of the side. On very small resolutions, it becomes h ...

What causes the NodeJS* event loop to persist even after my Promise has been resolved?

Question Is there a way to make NodeJS pause the event loop until all arguments have been parsed? Info I recently discovered a solution using this and this answer, involving the use of Promise. Now, when the app encounters --password, it waits for user ...

Searching for and substituting text in HTML

I am using basic HTML without any Javascript, XML, CSS, etc. I am trying to locate instances of "--" and replace them with an 'em dash'. Below is the code I have written: <!DOCTYPE html> <html> <center> <head> <tit ...

What is the best way to understand and decipher this CSS code?

As I delve into customizing the CSS of an Internet theme, I am faced with a syntax that is unfamiliar and puzzling to me. One example from the theme is as follows: @media screen and(max-width: 768 px) { .wy-tray-container { bottom: auto;top: 0; ...

showing chosen preferences in a multi-select drop-down menu through ajax and codeigniter

I have a requirement to showcase specific options (which are already stored in the database) in a multi-select dropdown list using ajax. The response obtained from ajax is structured as follows {"skill":[{"skill":"css"},{"skill":"Laravel"}]} It is neces ...

Showing a gallery of images in React

I have a unique situation where I am working on setting a variable to match the import statement that calls for images. Once I have this variable assigned, I want to use it to display the corresponding image. For instance, if my code generates the name &ap ...

What is the best way to show "no results found" message in a jQuery search list?

Everything is working smoothly. Does anyone have any suggestions on how to display a message saying "No results found"? This is the code I'm using: http://jsfiddle.net/UI_Designer/8p426fog/4/ $(".my-textbox").keyup(function() { var val = $( ...

Encountering an issue while attempting to fetch a value from a nested object property with VueJS Interpolation

I'm struggling to properly display nested arrays in Vue JS. Below is a snippet of my JSON data: { "id": 1, "slug": "test-page", "banner": { "title": "banner title", "subTitle": "my sub title", "hasSubTitle": false, "hasClass": " ...

What is the process for converting an <input type="file> into a base64 string?

Currently, I'm attempting to send an image to my express backend by including the image directly in the post request body. var imgValue = document.getElementById("image").value; Within my post request: body : JSON.stringify({ image:imgValue ...

Transforming the NavBar in React: A guide to dynamically updating values

I am facing an issue with my NavBar that changes based on certain events. The current setup works fine, but I don't want to render it in every class that loads a new page. Initially, I had the NavBar rendering inside App.js so it could appear on all p ...

Executing php class method through ajax with jQuery without requiring a php handler file

How can I trigger a PHP class method using AJAX with jQuery without the need for a separate PHP handler file? Here is my PHP Class animal.php:- <?php class animal { function getName() { return "lion"; } } ?> jQuery code snippet:- ...

Image Blob increases over 50 times its original size when uploaded

I'm completely baffled by the situation unfolding here. Using Preprocess.js, I am resizing/compressing an image on the front-end. During the processfile() function on the image.onload (line 32), I convert the toDataURL() string to a Blob, in order to ...