Trigger CSS Animation on Click via javascript - javascript

I have a simple hamburger icon and I want to trigger CSS animation on click via pure javascript(no jquery please). I am doing this by adding and removing a class on hamburger icon when I add the class the CSS animation is happening however when I remove the class the animation is not happening, the hamburger line is coming back abruptly without animating. Basically I want the animation to reverse and come back to original position.
Here is the code:
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>
Basically I want the hamburger icon line to become 0px width on click with duration and then whenever user clicks again I want the hamburger icon line to become original width starting from 0.

A bit ugly, because of the extra class needed, but it works:
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>

If you are free to use CSS transition, then this could be a great 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>

Related

How can I get a CSS animation to work in reverse?

I am trying to animate my menu. The menu open animation works fine, but I can't get the menu close animation to work.
The menu opens fine, but I don't know how to make it close with the MenuClose settings.
function showMenu() {
const el = document.getElementById("MenuContainer");
el.classList.toggle('MenuOpen');
}
#MenuContainer {
height: 0px;
left: 10px;
overflow: hidden;
padding: 5px 0px 0px 0px;
position: relative;
top: 20px;
width: 0px;
}
.MenuOpen {
animation-direction: normal;
animation-duration: 4s;
animation-fill-mode: forwards;
animation-name: Menu;
}
.MenuClose {
animation-direction: reverse;
animation-duration: 2s;
animation-fill-mode: forwards;
animation-name: Menu;
}
#keyframes Menu {
from {
height: 0px;
width: 0px;
}
to {
height: 100px;
width: 300px;
}
}
<input id="MenuButton" type="button" value="Menu" onclick="showMenu();" title="Menu" />
<div id="MenuContainer"></div>
2 main points:
you toggle MenuOpen with... nothing, it puts menuopen and remove it
better to have open animation and close animation, eas
function showMenu() {
const el = document.getElementById("MenuContainer");
if (el.classList.contains('MenuOpen')) {
el.classList.add('MenuClose');
el.classList.remove('MenuOpen');
} else {
el.classList.add('MenuOpen');
el.classList.remove('MenuClose');
}
}
#MenuContainer {
height: 0px;
left: 10px;
overflow: hidden;
padding: 5px 0px 0px 0px;
position: relative;
top: 20px;
width: 0px;
background-color: #3388ff;
}
.MenuOpen {
animation-duration: 4s;
animation-fill-mode: forwards;
animation-name: MenuOpen;
}
.MenuClose {
animation-duration: 2s;
animation-fill-mode: forwards;
animation-name: MenuClose;
}
#keyframes MenuOpen {
from {
height: 0px;
width: 0px;
}
to {
height: 100px;
width: 300px;
}
}
#keyframes MenuClose {
from {
height: 100px;
width: 300px;
}
to {
height: 0px;
width: 0px;
}
}
<input id="MenuButton" type="button" value="Menu" onclick="showMenu();" title="Menu" />
<div id="MenuContainer"></div>
ier to control
You can use if else statement and replace function to toggle the open close animation.
//Get the menu container
const el = document.getElementById("MenuContainer");
// Function to toggle the menu open/close animation
function showMenu() {
// Check if the menu container has the 'MenuOpen' class
if (el.classList.contains('MenuOpen')) {
// Replace the 'MenuOpen' class with 'MenuClose'
el.classList.replace('MenuOpen', 'MenuClose');
} else {
// Add the 'MenuOpen' class to the menu container
el.classList.add('MenuOpen');
}
}
Hope this will help. This is just one solution of many ways.

Unable to make a smooth transition in background color when scroll event is triggered

I am trying to to create a fixed header for one of my projects using react. The background color of the Header should be transparent when the web page is opened but on scrolling it down, it should change its color to black. I have managed to make the transition smooth while changing the background color from transparent to black (when I scroll down) however, I am unable to make the transition smooth when the background color changes from black to transparent (when I scroll back up).
Here is my Code :
import React from 'react';
import Navbar from '../Navbar/Navbar.js';
import logo from '../images/nsut_logo.png';
class Header extends React.Component {
constructor() {
super();
this.state = {
header: false
};
this.handleScroll = this.handleScroll.bind(this);
}
componentDidMount(){
window.addEventListener("scroll", this.handleScroll);
}
handleScroll(event) {
if (window.pageYOffset > 0) {
this.setState({ header: true });
}
else{
this.setState({ header: false });
}
}
render() {
return (
<header onScroll={this.handleScroll}>
<div className={this.state.header ? "Header-Site-Title-Active" : "Header-Site-Title"}>
<img className = "Header-logo" src={logo} />
<div className="Department-Name">
<h1 >
<b>Department Of Computer Science And Engineering</b>
<br/>
</h1>
<h3>
Netaji Subhas University of Technology
</h3>
</div>
<Navbar />
</div>
</header>
);
}
}
export default Header;
Here is my CSS File:
header{
top: 0;
padding-bottom: 1%;
position: fixed;
z-index: 5;
height: 17vh;
}
#keyframes bgChangeDown {
0% {background-color: none;}
100% {background-color: black;}
}
#keyframes bgChangeUp {
0% {background-color: inherit;}
100% {background-color: none;}
}
.Handle-Site-Title {
height: 100px;
width: 100vw;
top: 0;
animation-name: bgChangeUp;
animation-duration: 2s;
animation-iteration-count: 1;
transition: ease-in 1.5s;
animation-fill-mode: forwards;
}
.Header-Site-Title-Active {
height: 100px;
width: 100vw;
top: 0;
animation-name: bgChangeDown;
animation-duration: 2s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
transition: ease-in 1.5s;
}
.Header-logo{
height:100px;
padding: 5px 10px 0 5px;
margin: 0;
display: inline;
float: left;
}
.Department-Name{
margin: 0;
margin-bottom: 5px;
height: 100px;
float: left;
display: inline;
color: white;
}
.Department-Name h3{
margin-bottom: 15px;
margin-top: -17px
}
.hamburger{
position: fixed;
cursor: pointer;
margin: 5px;
right: 5%;
top: 5%;
}
.line{
width: 30px;
height: 3px;
background: white;
margin: 5px;
}
.sidenav {
height: 100%; /* 100% Full-height */
width: 0; /* 0 width - change this with JavaScript */
position: fixed; /* Stay in place */
z-index: 1; /* Stay on top */
top: 0; /* Stay at the top */
right: 0;
background-color: black; /* Black*/
overflow-x: hidden; /* Disable horizontal scroll */
padding-top: 60px; /* Place content 60px from the top */
transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */
}
.sidenav-active {
height: 100%; /* 100% Full-height */
width: 250px; /* 0 width - change this with JavaScript */
position: fixed; /* Stay in place */
z-index: 1; /* Stay on top */
top: 0; /* Stay at the top */
right: 0;
background-color: black; /* Black*/
overflow-x: hidden; /* Disable horizontal scroll */
padding-top: 60px; /* Place content 60px from the top */
transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */
}
/* The navigation menu links */
.sidenav a, .sidenav-active a {
padding: 8px 8px 8px 32px;
text-decoration: none;
font-size: 25px;
color: white;
display: block;
transition: 0.3s;
}
/* When you mouse over the navigation links, change their color */
.sidenav a:hover, .sidenav-active a:hover {
color: #f1f1f1;
}
/* Position and style the close button (top right corner) */
.sidenav .closebtn, .sidenav-active .closebtn {
position: absolute;
top: 0;
right: 25px;
font-size: 36px;
margin-left: 50px;
}
#media screen and (max-height: 450px) {
.sidenav {padding-top: 15px;}
.sidenav a {font-size: 18px;}
}
I am still learning React so feel free to suggest a new approach as well.
The classes that you're applying in your React component are Header-Site-Title-Active and Header-Site-Title but in your CSS your bgChangeUp animation is assigned to the Handle-Site-Title class, not Header-Site-Title:
.Handle-Site-Title {
height: 100px;
width: 100vw;
top: 0;
animation-name: bgChangeUp;
animation-duration: 2s;
animation-iteration-count: 1;
transition: ease-in 1.5s;
animation-fill-mode: forwards;
}
.Header-Site-Title-Active {
height: 100px;
width: 100vw;
top: 0;
animation-name: bgChangeDown;
animation-duration: 2s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
transition: ease-in 1.5s;
}
Further to this, this effect may be more easily achieved using CSS transitions:
.Header-Site-Title {
...
background-color: transparent;
transition: background-color ease-in 1.5s;
...
}
.Header-Site-Title-Active {
...
background-color: rgba(0,0,0,black);
...
}

Reverse a CSS animation without jquery

I'm making a dropdown menu that should slide into view on click. I want to make it slide back up on a second click, but have been struggling to figure out how to do so. Most of the answers I've found online involve jQuery, but I am hoping to accomplish this with vanilla js.
My CSS:
.post-more-dropdown {
background-color: #f8f9fa;
display: block;
position: absolute;
right: 0px;
top: 60px;
min-width: 80px;
animation-name: dropdown;
animation-play-state: paused;
animation-fill-mode: backwards;
animation-duration: 0.7s;
a {
display: block;
padding-left: 10px;
padding-top: 10px;
}
a:hover {
background-color: #555555;
color: white;
cursor: pointer;
}
}
#keyframes dropdown {
0% {
max-height: 0px;
opacity: 0;
}
100% {
max-height: 200px;
opacity: 1;
}
}
My javascript:
function post_more_dropdown(post_id) {
dropdown = document.querySelector(`#post-more-dropdown-${post_id}`);
dropdown.style.animationPlayState = "running";
}
This works perfectly to get the dropdown to run on click, but I'm struggling to figure out how to reverse it on the second click. I was thinking I could create a new #keyframes dropdown-reverse animation and add it to the class, but then I realized I can't control two animations under one class with JS. I was thinking I could also create two different classes and add/remove those classes with JS along with controlling two different animations, but I feel like there's got to be a more elegant solution that I'm missing.
I have a feeling that animation-direction is going to be part of the answer, but I haven't quite figured out how that will work for this.
Use the following CSS, change class using JavaScript.
function post_more_dropdown(post_id) {
dropdown = document.querySelector(`#post-more-dropdown-${post_id}`);
if (dropdown.classList.contains('dropdown-animate-forward')) {
dropdown.classList.add('dropdown-animate-backward');
dropdown.classList.remove('dropdown-animate-forward');
} else {
dropdown.classList.add('dropdown-animate-forward');
dropdown.classList.remove('dropdown-animate-backward');
}
}
setInterval(function() {
post_more_dropdown(1)
}, 1000);
.post-more-dropdown {
background-color: #f8f9fa;
display: block;
position: absolute;
right: 0px;
top: 60px;
min-width: 80px;
a {
display: block;
padding-left: 10px;
padding-top: 10px;
}
a:hover {
background-color: #555555;
color: white;
cursor: pointer;
}
}
/* forward animation */
.dropdown-animate-forward {
animation-name: dropdownForward;
animation-fill-mode: backwards;
animation-duration: 0.7s;
}
#keyframes dropdownForward {
0% {
max-height: 0px;
opacity: 0;
}
100% {
max-height: 200px;
opacity: 1;
}
}
/* backward animation */
.dropdown-animate-backward {
animation-name: dropdownBackward;
animation-fill-mode: forward;
animation-duration: 0.7s;
}
#keyframes dropdownBackward {
0% {
max-height: 200px;
opacity: 1;
}
100% {
max-height: 0px;
opacity: 0;
}
}
<div id="post-more-dropdown-1" class="post-more-dropdown">Post more</div>

Multiple CSS animations: How to avoid re-triggering one of them?

I am trying to build an animated menu for mobile apps similar to Pinterest's radial menu. I have managed to get the behaviour to where I want it except for one minor detail: when the menu opens, the items shoot out as I want them to, and when you hover on them, they transform as I want them to. problem is, after the cursor leaves the items, they re-trigger their original animation, instead of just returning to their previous state. I realise this is a problem to do with the class being used for the animation and I have tried a number of solutions, including deleting the class and adding a new one .onmouseover() and changing animation running state on hover/mousover. I am probably missing something simple and idiotic, but I just cannot see it. can anybody help?
The following code is just the way I had it before trying to implement solutions.
HTML:
<!--Footer-->
<div class="footer">
<!--RADIAL NAV MENU-->
<div id="navContainer">
<!--Buttons-->
<div id="workouts" class="sml smlOne">Go there</div>
<div id="home" class="sml smlTwo">Go here</div>
<div id="profile" class="sml smlThree">Go somewhere</div>
<!--Burger-->
<div class="burger-menu">
<div id="top" class="bar barTop"></div>
<div id="middle" class="bar barMid"></div>
<div id="bottom" class="bar barBot"></div>
</div>
</div>
</div>
CSS:
.footer
{
position: fixed;
bottom: 0%;
width: 100%;
height: 50px;
background-color: #d36363;
box-shadow: 0px -6px 6px #888888;
z-index: +2;
}
/* Burger menu section */
#navContainer
{
text-align: center;
font-size: 10px;
}
.burger-menu
{
position: relative;
margin: auto;
height: 100%;
width: 50px;
}
.bar
{
height: 6px;
width: 100%;
background-color: white;
}
#top
{
position: relative;
top: 5px;
}
#middle
{
position: relative;
top: 15px;
}
#bottom
{
position: relative;
top: 25px;
}
.barTop, .barMid, .barBot
{
-webkit-transition: all 0.1s ease;
-moz-transition: all 0.1s ease;
-o-transition: all 0.1s ease;
-ms-transition: all 0.1s ease;
transition: all 0.1s ease;
}
.barTopOn
{
transform: rotate(45deg) translateY(12px) translateX(11px);
}
.barMidOn
{
opacity: 0;
}
.barBotOn
{
transform: rotate(-45deg) translateY(-12px) translateX(11px);
}
/* Navigation buttons section */
#navContainer
{
position: relative;
margin: auto;
width: 50px;
}
.sml
{
border: 2px solid #58a7dd;
height: 50px;
width: 50px;
border-radius: 50%;
background-color: white;
box-shadow: 6px 6px 6px #888888;
transform: scale(0);
}
#workouts
{
position: absolute;
bottom: 10px;
left: -60px;
}
#home
{
position: absolute;
bottom: 50px;
}
#profile
{
position: absolute;
bottom: 10px;
left: 60px;
}
.smlOnOne
{
animation: pop, slideOne 0.1s ease-in;
animation-fill-mode: forwards;
}
.smlOnTwo
{
animation: pop, slideTwo 0.1s ease-in;
animation-fill-mode: forwards;
}
.smlOnThree
{
animation: pop, slideThree 0.1s ease-in;
animation-fill-mode: forwards;
}
.smlOnOne:hover
{
background-color: red;
border: none;
box-shadow: 6px 10px 18px #686868;
animation: whopL 0.2s;
animation-fill-mode: forwards;
}
.smlOnTwo:hover
{
background-color: red;
border: none;
box-shadow: 6px 10px 18px #686868;
animation: whopC 0.2s;
animation-fill-mode: forwards;
}
.smlOnThree:hover
{
background-color: red;
border: none;
box-shadow: 6px 10px 18px #686868;
animation: whopR 0.2s;
animation-fill-mode: forwards;
}
#keyframes pop
{
100%
{
transform: scale(1,1);
}
}
#keyframes slideOne
{
0%
{
bottom: -20px;
left: 0px;
}
100%
{
bottom: 10px;
left: -60px;
}
}
#keyframes slideTwo
{
0%
{
bottom: -20px;
}
100%
{
bottom: 50px;
}
}
#keyframes slideThree
{
0%
{
bottom: -20px;
left: 0px;
}
100%
{
bottom: 10px;
left: 60px;
}
}
#keyframes whopL
{
0%
{
transform: scale(1,1) translateY(0px) translateX(0px);
}
100%
{
transform: scale(1.5) translateY(-10px) translateX(-10px);
}
}
#keyframes whopC
{
0%
{
transform: scale(1,1) translateY(0px) translateX(0px);
}
100%
{
transform: scale(1.5) translateY(-10px);
}
}
#keyframes whopR
{
0%
{
transform: scale(1,1) translateY(0px) translateX(0px);
}
100%
{
transform: scale(1.5) translateY(-10px) translateX(10px);
}
}
JS/jQuery:
$(".burger-menu").click(function()
{
$(".barTop").toggleClass("barTopOn");
$(".barMid").toggleClass("barMidOn");
$(".barBot").toggleClass("barBotOn");
$(".smlOne").toggleClass("smlOnOne");
$(".smlTwo").toggleClass("smlOnTwo");
$(".smlThree").toggleClass("smlOnThree");
});
Here is a working demo:
https://codepen.io/BGGrieco/pen/NgjxXq
You have an element that is a set of #-webkit-keyframes to animate in. On hamburger-menu click, these keyframes run, and that works well.
Next, you have a second set of #-webkit-keyframes on hover, so on hover works well too.
However, the instant the mouse is away from the element, the first (intro) set of keyframes gets run again. You don't want it to run after it first runs.
Here is what I was able to accomplish:
https://codepen.io/CapySloth/pen/RgxKEb
<div id="workouts" class="sml smlOne">
<div class="test1">
Go there
</div>
</div>
Instead of stacking classes which contain keyframe animations onto the one ".sml" class, I have split the task between two elements. ".sml" now acts as a wrapper which takes care of the "hamburger-menu open" animation and "test1 a" takes care of the "whop" animation.
If you can find a way to hide/show parents of the "test1 a/test2 a/test3 a" then you will have what you want.
You can use .stop() before your .toggleClass.
$("#example").stop().toggleClass("class");

Animation didn't work properly when click the button in menu [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Here is my jsfiddle: https://jsfiddle.net/n1ssf5up/5/
I took the source code from this link: http://codepen.io/MrBambule/pen/jIseg
I need to change the code for getting small size button.
It works fine, when i increase the font-size, as 0.7em to 1.7em for the list.
css:
.button {
position: relative;
width: 50px;
height: 50px;
border: 1px solid;
border-radius: 50%;
background: #2E3F47;
z-index: 10;
}
.line {
background: #ccc;
width: 15px;
height: 5px;
margin: 2px auto;
}
.line__first {
margin-top: 15px;
}
.menu {
z-index: 1;
float: left;
width: 100%;
}
/* for the list to be horizontaly centered */
.table {
display: table;
margin: 0 auto;
}
.menu__list {
width: 100%;
margin-left:-110px;
margin-top:-10px;
}
/* Animation keyframes for the drop down */
#keyframes drop {
from {
top: 0px;
}
70% {
top: 85px;
animation-timing-function: ease-in;
}
to {
top: 70px;
animation-timing-function: ease-out;
}
}
#-webkit-keyframes drop {
from {
top: 0px;
}
70% {
top: 85px;
-webkit-animation-timing-function: ease-in;
}
to {
top: 70px;
-webkit-animation-timing-function: ease-out;
}
}
li {
position: relative;
list-style: none;
padding-bottom: 0px;
top: 0px;
}
li a {
text-decoration: none;
color: grey;
text-align: center;
font-size: 0.7em;
font-family: 'Open Sans', sans-serif;
}
.menu__list__item {
opacity: 0;
}
/*Animation classes to add to list-items that should be animated*/
.list--animation, .list--animation--delay1, .list--animation--delay2 {
animation: drop 0.9s;
-webkit-animation: drop 0.9s;
animation-fill-mode: forwards;
opacity: 1;
-webkit-animation-fill-mode: forwards;
opacity: 1;
}
.list--animation--delay1 {
animation-delay: 0.5s;
-webkit-animation-delay: 0.5s;
}
.list--animation--delay2 {
animation-delay: 1s;
-webkit-animation-delay: 1s;
}
I need same animation and with small size button.
may i know how to do this? thanks in advance.
Try to use this:
.line { background: #ccc;width: 30%;height: 16%;margin: 10% auto;} line__first { margin-top: 15%;}
check out this
demo
You have to add class with delay in jQuery code..
$('.item1').addClass('list--animation');
$('.item2').delay(1000).queue(function(){
$(this).addClass('list--animation--delay1').clearQueue();
});
$('.item3').delay(2000).queue(function(){
$(this).addClass('list--animation--delay2').clearQueue();
});
Change in CSS
.list--animation--delay1 {
animation-delay: 0s;
-webkit-animation-delay: 0s;
}
.list--animation--delay2 {
animation-delay: 0s;
-webkit-animation-delay: 0s;
}

Categories

Resources