Closing mobile nav toggle on click - javascript

I have a mobile nav menu with a hamburger toggle that successfully opens the menu on click. I am also adding animation to the toggle button on click. I am using a backdrop to close the nav menu, but I also want to be able to close the menu when the toggle is clicked, and if the backdrop is clicked, for the toggle to animate when the menu is closing. Below is my code so far, any help would be greatly appreciated.
var backdrop = document.querySelector(".backdrop");
var toggleButton = document.querySelector(".toggle-container");
var mobileNav = document.querySelector(".mobile-nav");
backdrop.addEventListener("click", function() {
mobileNav.classList.remove("open");
closeMenu();
});
function closeMenu() {
if (toggleButton) {
mobileNav.classList.remove("open");
}
backdrop.classList.remove("open");
toggleButton.classList.remove("active");
}
toggleButton.addEventListener("click", function() {
mobileNav.classList.add("open");
toggleButton.classList.add("active");
backdrop.classList.add("open");
});
function toggleNav(x) {
x.classList.toggle("change");
}
.backdrop {
position: fixed;
display: none;
top: 197px;
left: 0;
z-index: 100;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
}
.toggle-container {
display: inline-block;
cursor: pointer;
margin: 10px;
z-index: 105;
}
.bar1,
.bar2,
.bar3 {
width: 2rem;
height: 5px;
background-color: black;
margin: 6px 0;
transition: 0.4s;
}
.change .bar1 {
-webkit-transform: rotate(-45deg) translate(-9px, 6px);
transform: rotate(-45deg) translate(-9px, 6px);
}
.change .bar2 {
opacity: 0;
}
.change .bar3 {
-webkit-transform: rotate(45deg) translate(-8px, -8px);
transform: rotate(45deg) translate(-8px, -8px);
}
.mobile-nav {
display: none;
position: fixed;
z-index: 101;
top: 60px;
left: 0;
background: white;
width: 30%;
height: 100vh;
}
.mobile-nav__items {
width: 90%;
height: 100%;
list-style: none;
margin: 10% auto;
padding: 0;
font-family: 'Quantico', sans-serif;
}
.mobile-nav__item {
margin: 1rem 0;
}
.mobile-nav__item a {
font-size: 1.5rem;
text-decoration: none !important;
color: #15396c;
}
#media (min-width: 60rem) {
.toggle-container {
display: none;
}
}
.open {
display: block !important;
}
<div class="backdrop"></div>
<div class="toggle-container" onclick="toggleNav(this)">
<div class="bar1">
</div>
<div class="bar2">
</div>
<div class="bar3">
</div>
</div>
<nav class="mobile-nav">
<ul class="mobile-nav__items">
<li class="mobile-nav__item">
<a href="#">Home
</a>
</li>
<li class="mobile-nav__item">
<a href="#">Link 1
</a>
</li>
<li class="mobile-nav__item">
<a href="#">Link 2
</a>
</li>
<li class="mobile-nav__item">
<a href="#">Link 3
</a>
</li>
<li class="mobile-nav__item">
<a href="#">Link 4
</a>
</li>
</ul>
</nav>

I have cleaned-up the JS and made some changes to get it working. Namely, I moved the inline onClick to the event listener, and merged a few of the other functions to make it easier to understand (but feel free to separate these if needed).
The major change was to add the active and change classes to the toggleButton when open, and then remove the active and change classes when the backdrop is clicked.
var backdrop = document.querySelector(".backdrop");
var toggleButton = document.querySelector(".toggle-container");
var mobileNav = document.querySelector(".mobile-nav");
backdrop.addEventListener("click", function() {
mobileNav.classList.remove("open");
backdrop.classList.remove("open");
toggleButton.classList.remove("active", "change");
});
toggleButton.addEventListener("click", function() {
mobileNav.classList.add("open");
toggleButton.classList.add("active", "change");
backdrop.classList.add("open");
});
.backdrop {
position: fixed;
display: none;
left: 0;
z-index: 100;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
}
.toggle-container {
display: inline-block;
cursor: pointer;
margin: 10px;
z-index: 105;
}
.bar1,
.bar2,
.bar3 {
width: 2rem;
height: 5px;
background-color: black;
margin: 6px 0;
transition: 0.4s;
}
.change .bar1 {
-webkit-transform: rotate(-45deg) translate(-9px, 6px);
transform: rotate(-45deg) translate(-9px, 6px);
}
.change .bar2 {
opacity: 0;
}
.change .bar3 {
-webkit-transform: rotate(45deg) translate(-8px, -8px);
transform: rotate(45deg) translate(-8px, -8px);
}
.mobile-nav {
display: none;
position: fixed;
z-index: 101;
top: 60px;
left: 0;
background: white;
width: 30%;
height: 100vh;
}
.mobile-nav__items {
width: 90%;
height: 100%;
list-style: none;
margin: 10% auto;
padding: 0;
font-family: 'Quantico', sans-serif;
}
.mobile-nav__item {
margin: 1rem 0;
}
.mobile-nav__item a {
font-size: 1.5rem;
text-decoration: none !important;
color: #15396c;
}
#media (min-width: 60rem) {
.toggle-container {
display: none;
}
}
.open {
display: block !important;
}
<div class="backdrop"></div>
<div class="toggle-container">
<div class="bar1">
</div>
<div class="bar2">
</div>
<div class="bar3">
</div>
</div>
<nav class="mobile-nav">
<ul class="mobile-nav__items">
<li class="mobile-nav__item">
Home
</li>
<li class="mobile-nav__item">
Link 1
</li>
<li class="mobile-nav__item">
Link 2
</li>
<li class="mobile-nav__item">
Link 3
</li>
<li class="mobile-nav__item">
Link 4
</li>
</ul>
</nav>

Related

Change color of hamburger menu on click

I want to change the color of the hamburger menu when the menu is opened. When the user clicks on the hamburger menu, the color should change from black to white and and vice versa. I´m not using a button for the menu but three spans. I haven't tried anything yet, because I´m pretty new and espacially js is still very difficult for me. Thanks for helping me!
const hamburger = document.querySelector(".hamburger");
const navMenu = document.querySelector(".nav-menu");
hamburger.addEventListener("click", () => {
hamburger.classList.toggle("active");
navMenu.classList.toggle("active");
});
document.querySelector(".nav.link").forEach((n) =>
n.addEventListener("click", () => {
hamburger.classList.remove("active");
navMenu.classList.remove("active");
})
);
.hamburger {
display: none;
cursor: pointer;
}
.bar {
display: block;
width: 25px;
height: 3px;
margin: 5px auto;
-webkit-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
background-color: black;
}
#media (max-width: 1000px) {
.hamburger {
display: block;
}
.hamburger.active .bar:nth-child(2) {
opacity: 0;
}
.hamburger.active .bar:nth-child(1) {
transform: translateY(8px) rotate(45deg);
}
.hamburger.active .bar:nth-child(3) {
transform: translateY(-8px) rotate(-45deg);
}
.nav-menu {
position: fixed;
left: -100%;
top: 0px;
gap: 0;
flex-direction: column;
background-color: black;
width: 100%;
text-align: center;
}
.nav-item {
margin: 16px 0;
display: flex;
flex-direction: column;
}
.nav-menu.active {
left: 0;
}
.menu a {
color: white;
}
}
<nav id="nav" class="navbar">
<ul class="nav-menu">
<li id="current" class="nav-item">
<a
href="file:///C:/Users/.../index.html"
class="nav-link"
>Home</a
>
</li>
<li>
<a
href="file:///C:/Users/.../about.html"
class="nav-link"
>About</a
>
</li>
</ul>
<div class="hamburger">
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</div>
</nav>
To change the color of the bars, you just need to add this to your css:
.hamburger.active .bar {
background-color: gray;
}
You wrote that you want the color to change from white to black and vice versa, but i wouldnt recommend you that, because you cant see the white bars on a white background. This is why i set the color to gray in this example.
Also, you made a mistake with the layering. You can see the hamburger infront of the menu when its open. To fix this, just set z-index to 2:
.nav-menu {
z-index: 2;
}
Here's a full example:
const hamburger = document.querySelector(".hamburger");
const navMenu = document.querySelector(".nav-menu");
hamburger.addEventListener("click", () => {
hamburger.classList.toggle("active");
navMenu.classList.toggle("active");
});
document.querySelector(".nav.link").forEach((n) =>
n.addEventListener("click", () => {
hamburger.classList.remove("active");
navMenu.classList.remove("active");
})
);
.hamburger {
display: none;
cursor: pointer;
}
.bar {
display: block;
width: 25px;
height: 3px;
margin: 5px auto;
-webkit-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
background-color: black;
}
#media (max-width: 1000px) {
.hamburger {
display: block;
}
.hamburger.active .bar {
background-color: gray;
}
.hamburger.active .bar:nth-child(2) {
opacity: 0;
}
.hamburger.active .bar:nth-child(1) {
transform: translateY(8px) rotate(45deg);
}
.hamburger.active .bar:nth-child(3) {
transform: translateY(-8px) rotate(-45deg);
}
.nav-menu {
position: fixed;
left: -100%;
top: 0px;
gap: 0;
flex-direction: column;
background-color: black;
width: 100%;
text-align: center;
z-index: 2;
}
.nav-item {
margin: 16px 0;
display: flex;
flex-direction: column;
}
.nav-menu.active {
left: 0;
}
.menu a {
color: white;
}
}
<nav id="nav" class="navbar">
<ul class="nav-menu">
<li id="current" class="nav-item">
<a
href="file:///C:/Users/.../index.html"
class="nav-link"
>Home</a
>
</li>
<li>
<a
href="file:///C:/Users/.../about.html"
class="nav-link"
>About</a
>
</li>
</ul>
<div class="hamburger">
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</div>
</nav>

how to animate an element using js

i made a navbar for practice and tried to hide and show its content only when its title is clicked.
i managed to do it with toggling a hidden class on and off.
but i also want it to have transition and slide down not just to apear out of nowhere. i couldn't do this part.
i put transition inside nav-bar__list-box tweaked the hidden class with and without display:block but i didn't have any success.
hidden class:
.u-hidden-navbar {
display: none;
visibility: hidden;
height: 0 !important;
}
idk what else to do but to ask here for advise.
const btnNavBar = document.querySelectorAll(".nav-bar__heading-box");
const navList = document.querySelectorAll(".nav-bar__list-box");
for (let i = 0; i < btnNavBar.length; i++) {
btnNavBar[i].addEventListener(`click`, function () {
navList[i].classList.toggle("u-hidden-navbar");
for (let b = 0; b < navList.length; b++) {
if (b !== i) {
navList[b].classList.add("u-hidden-navbar");
}
}
});
}
*,
*::after,
*::before {
box-sizing: inherit;
padding: 0;
margin: 0;
}
html {
font-size: 62.5%;
}
body {
box-sizing: border-box;
font-size: 1.6rem;
line-height: 1.5;
}
ul {
list-style: none;
}
a {
text-decoration: none;
display: inline-block;
color: #e6e6e6;
}
img {
vertical-align: bottom;
}
.u-hidden-navbar {
display: none;
visibility: hidden;
height: 0 !important;
}
.nav-bar {
margin: 2rem;
border-radius: 0.8rem;
overflow: hidden;
order: 1;
background-color: #e6e6e6;
width: 30rem;
}
.nav-bar__heading-box {
background-color: #3b3b3b;
padding: 1rem;
}
.nav-bar__heading-box:not(:last-child) {
border-bottom: 1px solid #1b1b1b;
}
.nav-bar__list-box {
font-weight: 700;
font-size: 1.6rem;
transition: 5s all ease;
}
.nav-bar__item:not(:last-child) {
border-bottom: 1px solid #1b1b1b;
}
.nav-bar__link {
padding: 1rem 2rem 1rem;
color: #973ae4;
position: relative;
display: block;
transition: 0.4s all ease;
}
.nav-bar__link:hover {
color: #e6e6e6;
transform: translateY(0);
}
.nav-bar__link:hover::before {
transform: scaleX(1);
box-shadow: inset 0.2rem 0.2rem 0.5rem rgba(27, 27, 27, 0.6);
opacity: 1;
}
.nav-bar__link::before {
content: "";
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
transform-origin: left;
transform: scaleX(0.1);
opacity: 0;
background-color: #973ae4;
transition: all 0.3s ease-in-out;
z-index: -1;
}
<aside class="nav-bar">
<div class="nav-bar__heading-box">
<h3 class="heading-tertiary">HTML Topics</h3>
</div>
<div class="nav-bar__list-box u-hidden-navbar">
<ul class="nav-bar__list">
<li class="nav-bar__item">
<a
href="pages/js_topic_01.html"
class="nav-bar__link"
target="content"
>Link</a
>
</li>
<li class="nav-bar__item">
<a
href="pages/js_topic_01.html"
class="nav-bar__link"
target="content"
>Link</a
>
</li>
</ul>
</div>
<div class="nav-bar__heading-box">
<h3 class="heading-tertiary">CSS Topics</h3>
</div>
<div class="nav-bar__list-box u-hidden-navbar">
<ul class="nav-bar__list">
<li class="nav-bar__item">
<a
href="pages/js_topic_01.html"
class="nav-bar__link"
target="content"
>Link</a
>
</li>
<li class="nav-bar__item">
<a
href="pages/js_topic_01.html"
class="nav-bar__link"
target="content"
>Link</a
>
</li>
</ul>
</div>
<div class="nav-bar__heading-box">
<h3 class="heading-tertiary">JS Topics</h3>
</div>
<div class="nav-bar__list-box u-hidden-navbar">
<ul class="nav-bar__list">
<li class="nav-bar__item">
<a
href="pages/js_topic_01.html"
class="nav-bar__link"
target="content"
>1- JS High-level overview</a
>
</li>
<li class="nav-bar__item">
<a href="hello.html" class="nav-bar__link" target="content"
>Link</a
>
</li>
</ul>
</div>
</aside>
The browser does not know how to interpolate this kind of animation, so you'll have to be a little bit more specific about how you'd like the hidden element to appear.
Switching from display: block to display: none or from visibility: visible to visibility: hidden is a "on/off" situation with no way to guess what the middle state will be...
Instead you could try to transition from :
opacity: 0 to opacity: 1
transform: scaleY(0) to transform: scaleY(1)
both
You can be really creative, and rely on keyframed animations with several intermediate steps, but it's up to you to define the strategy.
document.querySelector('button').addEventListener('click', () => {
document.querySelector('.togglable').classList.toggle('hidden')
})
.togglable{
padding: 50px;
background: red;
transform: scaleY(1);
opacity: 1;
color: #FFF;
transition: .75s;
}
.togglable.hidden{
opacity: 0;
transform: scaleY(0);
}
<button>Click me</button>
<div class="togglable hidden">Hello</div>

responsive navigation toggle menu issue

I have been working on my portfolio website and I can't seem to get my responsive navigation working properly.
The normal navigation works fine, but the responsive navigation toggle menu presents issues on the mobile version. When the toggle is clicked it changes from the menu icon to the X icon, but the drop-down navigation menu doesn't appear.
I have been trying to solve this issue and cannot seem to find a solution. Any feedback would be appreciated, HTML, CSS & JavaScript below.
$(window).load(function() {
$('span.nav-btn').click(function() {
$('ul.nav').toggle();
})
$(window).resize(function() {
if ($(window).width() > 660) {
$('ul.nav').removeAttr('style')
}
})
});
function myFunction(x) {
x.classList.toggle("change");
}
nav {
letter-spacing: 1.9px;
float: right;
padding: 10px;
margin: 60px 150px 0px 0px;
}
.nav>li {
display: inline-block;
}
.nav>li>a {
color: #000;
font-size: 12px;
padding: 18px;
transition: all 0.5s ease;
text-transform: uppercase;
}
.nav>li>a:hover {
color: #c3dbc5;
}
.nav .current {
font-weight: bolder;
}
#media screen and (max-width: 900px) {
nav {
margin: 0px;
padding: 0px;
}
.nav {
display: none;
}
ul {
padding: 0px;
}
.nav>li {
margin-top: 50px;
padding: 15px 0px 0px 15px;
width: 100%;
list-style: none !important;
text-align: center;
}
.nav>li>a {
font-size: 16px;
}
.container_nav {
display: block;
cursor: pointer;
position: relative;
padding: 50px;
margin-top: 0px;
}
.container_nav.change {
display: block;
cursor: pointer;
}
.bar1,
.bar2,
.bar3 {
width: 35px;
height: 5px;
background-color: #333;
margin: 6px 0;
transition: 0.4s;
}
.change .bar1 {
-webkit-transform: rotate(-45deg) translate(-9px, 6px);
transform: rotate(-45deg) translate(-9px, 6px);
}
.change .bar2 {
opacity: 0;
}
.change .bar3 {
-webkit-transform: rotate(45deg) translate(-8px, -8px);
transform: rotate(45deg) translate(-8px, -8px);
}
}
<nav role="navigation" id="nav">
<ul class="nav">
<li>Work</li>
<li>About</li>
<li>Resume</li>
<li>Contact</li>
</ul>
<div class="container_nav" onclick="myFunction(this)">
<div class="bar1"></div>
<div class="bar2"></div>
<div class="bar3"></div>
<span class="nav-btn"></span>
</div>
</nav>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You need to change a couple of things in your code to get things done.
Get your nav hamburger icon out of the nav container.
The comment says it right, remove the onclick function from the container_nav div.
Replace your entire jquery code with
$(document).ready(function () {
$("div.container_nav").click(function () {
$("div.container_nav").toggleClass("change");
$("ul.nav").toggleClass("toggle-menu");
});
});
You're adding .change both the time to the container_nav which isn't toggling the menu because nothing changes at .nav so rename your .container_nav.change class to .nav.toggle-menu.
The comment section is always open if you're stuck again.

How can I make an animation like this?

I want to make something like this, just like in the code I wrote, but the problema is that when the animation is back to it's original position, the links stays there but invisible, and I want them to stay in display: none :(
When I always try to make that those links stays in display: none the animation looks like that does not want to work...
HTML
<body>
<nav>
<div class="hamburger">
<span class="hamburger_stick stick1"></span>
<span class="hamburger_stick stick2"></span>
<span class="hamburger_stick stick3"></span>
</div>
<ul class="nav_list_container">
<a class="nav_list_link link1" href="">Servicios</a>
<a class="nav_list_link link2" href="">Contacto</a>
</ul>
</nav>
<header>
<div>
<h1>Eliana Moura</h1>
<h2>Enfermera Profesional Matriculada</h2>
<p>Más de 10 años apoyando y sanando pacientes en la Ciudad de Santa Fe.</p>
<p>Y hoy, ¿cómo te sentís? ¿En qué te puedo ayudar?</p>
Leer más
</div>
<div>
<img src="" alt="">
</div>
</header>
CSS
#import "standar";
$color1: #dcf1fb;
$color2: #f8b14c;
$color3: #777887;
$color4: #384e5e;
$typo: 'Ubuntu', sans-serif;
* {
font-family: $typo;
}
body {
width: 100vw;
height: 100vh;
background-color: $color1;
}
header {
background-color: $color1;
}
nav {
display: flex;
flex-direction: row-reverse;
width: 100%;
}
nav .nav_list_container {
display: flex;
flex-direction: row-reverse;
width: 100%;
}
nav .nav_list_container .nav_list_link {
margin: 10px 5px;
padding: 10px 8px;
text-transform: uppercase;
font-weight: bold;
opacity: 0;
transform: translateX(20px);
transition: all .2s ease-in-out;
}
.hamburger {
width: 40px;
height: 30px;
line-height: 5px;
padding: 15px 20px;
}
.hamburger .hamburger_stick {
display: inline-block;
width: 100%;
height: 3px;
margin: auto;
background-color: #000000;
transition: all .2s ease-in-out;
}
.selected {
transform: rotate(-45deg) translate(-3px, 8px);
}
.selected2 {
transform: translateX(20px); opacity: 0;
}
.selected3 {
transform: rotate(45deg) translate(-3px, -8px);
}
.selected4 {
opacity: 1 !important;
display: initial !important;
transform: translateX(0) !important;
}
JS
$(document).ready(function() {
var selected = false
$(".hamburger").click(function() {
$(".stick1").toggleClass("selected")
$(".stick2").toggleClass("selected2")
$(".stick3").toggleClass("selected3")
$(".nav_list_link").toggleClass("selected4")
})
})

JavaScript Responsive Menu

I have this navigation menu as in the image here.
Below is my JS that I currently have to make it responsive so that it opens up on clicking it but it is not working:
function showMenu(event) {
event.preventDefault();
let element = document.getElementById('header');
if (element.classList.contains('active')) {
element.className = "";
} else {
element.className = "active";
}
}
header {
padding: 0 !important;
background: #fff;
}
header.active {
box-shadow: 0 1px 5px 1px rgba(0, 0, 0, 0.2);
}
header.fixed {
padding: 0 0;
}
header button {
position: absolute;
top: 12px;
right: 25px;
display: block;
width: 30px;
height: 40px;
padding-top: 6px;
border: none;
background: #fff;
}
header button span {
position: relative;
top: 0;
display: block;
width: 100%;
height: 2.5px;
margin-bottom: 5px;
transition: all .2s ease;
border-radius: 15px;
background: #0d2366;
}
header button span:nth-child(2) {
right: 0;
width: 80%;
opacity: 1;
}
header button span:nth-child(3) {
width: 60%;
}
header.active button span:nth-child(1) {
top: 8px;
left: -4px;
-ms-transform: rotate(38deg);
transform: rotateZ(38deg);
}
header.active button span:nth-child(2) {
right: -100%;
opacity: 0;
}
header.active button span:nth-child(3) {
top: -6px;
left: -4px;
width: 100px;
-ms-transform: rotate(-38deg);
transform: rotateZ(-38deg);
}
header ul.menu-left {
display: none;
}
header img {
margin-left: 25px !important;
}
header.active ul.menu-left {
display: block;
float: none;
clear: both;
}
header.active ul.menu-left li {
display: block !important;
padding: 10px 20px;
}
header ul.menu-right {
display: none;
}
<!--Header-->
<header id="header">
<div class="wrapper">
<a href="/">
<img src="images/pulse.png" alt="logo">
</a>
<button id="submenu">
<span></span>
<span></span>
<span></span>
</button>
<!--Menu Links-->
<ul class="menu-left">
<li>Home</li>
<li>About</li>
<li>Services</li>
<li>Pricing</li>
<li>Contact</li>
</ul>
<ul class="menu-right">
<li class="menu-cta">Get Started</li>
</ul>
</div>
</header>
The active class here represents the responsive menu icon.
Any help is highly appreciated.
Thanks!
By using the addEventListener you can watch the click event. After clicking the button, the third line below will toggle between adding and removing the class 'active' on the id="header"
document.getElementById("submenu").addEventListener("click", function(event) {
event.preventDefault();
document.getElementById("header").classList.toggle("active");
});

Categories

Resources