Why won't my sidebar media query work in Javascript? - javascript

I have a sidebar that slides out 250px using javscript on the desktop view. When it comes to the mobile view I want the sidebar to take up 100% width. I am trying to use Media Queries in Javascript but no matter what changes I make It seems to overwrite my styles I have for my sidebar on the desktop view.
HTML
<nav class="navbar">
<div id="toggle-btn" class="sidemenu-btn">
<i class="fas fa-bars"></i>
</div>
<div id="toggle-nav" class="navbar-items animated fadeInLeft delay-1s">
Home
About
Skills
Portfolio
Contact
</div>
</nav>
CSS
.navbar {
height: 100%;
width: 0;
position: fixed;
background: #141313;
}
.navbar .sidemenu-btn {
font-size: 2.5rem;
padding: 3rem 0;
text-align: center;
margin-left: 1rem;
cursor: pointer;
color: #141313;
}
.navbar .navbar-items {
display: flex;
flex-direction: column;
text-align: center;
display: none;
margin-left: 1rem;
}
.navbar .navbar-items a {
text-decoration: none;
color: white;
padding: 1.2rem 0;
font-weight: 400;
font-size: 1.2rem;
text-transform: uppercase;
}
.navbar .navbar-items a:hover {
text-decoration: line-through;
}
#media screen and (max-width: 768px) {
.navbar {
position: relative;
}
}
JS
const toggleBtn = document.querySelector("#toggle-btn");
const toggleNav = document.querySelector(".navbar");
const togglenavItems = document.querySelector('.navbar-items');
toggleBtn.addEventListener("click", sideMenu);
toggleBtn.addEventListener("click", mediaQuery);
function sideMenu() {
if (toggleNav.style.width === "250px") {
toggleNav.style.width = "0px";
} else {
toggleNav.style.width = "250px";
}
}
function mediaQuery() {
const x = window.matchMedia('(max-width: 768px)');
const y = document.querySelector('.navbar');
if (x.matches && y.style.width === "100%") {
y.style.width = "0px";
} else {
y.style.width = "100%";
}
}

Media queries can do the work. You don't need js for changing the width of the navbar-items. See this
const toggleBtn = document.querySelector("#toggle-btn");
const toggleNav = document.querySelector(".navbar");
const togglenavItems = document.querySelector('.navbar-items');
toggleBtn.addEventListener("click", sideMenu);
function sideMenu() {
toggleNav.classList.toggle('open');
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.navbar {
height: 100%;
width: 100%;
position: fixed;
}
.sidemenu-btn {
font-size: 2.5rem;
padding: 0;
text-align: center;
cursor: pointer;
color: green;
position: absolute;
right: 20px;
top: 20px;
}
.navbar-items {
display: flex;
flex-direction: column;
text-align: center;
width: 250px;
height: 100%;
padding-left: 1rem;
background: #141313;
transition: all .5s ease;
}
.navbar .navbar-items a {
text-decoration: none;
color: white;
padding: 1.2rem 0;
font-weight: 400;
font-size: 1.2rem;
text-transform: uppercase;
}
.navbar .navbar-items a:hover {
text-decoration: line-through;
}
#media (max-width: 768px) {
.navbar-items {
width: 100%;
}
}
.navbar.open .navbar-items {
width: 0;
}
<nav class="navbar">
<div id="toggle-btn" class="sidemenu-btn">
<i class="fas fa-bars"></i>
Toggle
</div>
<div id="toggle-nav" class="navbar-items animated fadeInLeft delay-1s">
Home
About
Skills
Portfolio
Contact
</div>
</nav>
Just adding the media query you can change the width of the element, no need to check in js
#media (max-width: 768px) {
.navbar-items {
width: 100%;
}
}
Adding a .open class that will be added on the .navbar and will trigger the transition
.navbar.open .navbar-items {
width: 0;
}
Your js was now simplified
const toggleBtn = document.querySelector("#toggle-btn");
const toggleNav = document.querySelector(".navbar");
toggleBtn.addEventListener("click", sideMenu);
function sideMenu() {
toggleNav.classList.toggle('open');
}

This is easier done with CSS to control how it looks on the mobile/desktop, with JS just handling the logic. The following will fix the style discrepancy, and make your JS easier to navigate.
CSS
.navbar{
width: 250px;
height: 100%;
position: fixed;
background: #141313;
}
.navHidden{
width: 0px !important;
}
/* smaller screen size */
#media screen and (max-width:768px) {
.navbar{
width: 100%;
}
}
HTML
<nav class="navbar navHidden">
JS
function sideMenu() {
toggleNav.classList.toggle("navHidden")
}
Sidenote
In your included code, the click of your toggle button you will be setting the width of the navbar to 250px, but then it will be passed through to your next function, which will then swap it to 100% in EVERY CASE regardless of screen size, so the toggle function you have written will never work.

Related

Responsive hamburger menu using ul/li tags

I've been trying to follow a few tutorials to turn a horizontal menubar into a drop-down hamburger menu when displayed on smaller screens, but I'm struggling to make it come together properly. I noticed a lot of tutorials seem to do away with ul/li format, which I'd like to save for semantic and accessible reasons, but this has left me struggling to get the dropdown to appear correctly on the screen.
My goal is to allow the hamburger menu to open the four menu items, centered on the screen, below the top header bar. I've managed to make the hamburger menu "work," but it's opening the items not centered and not below the top menubar. Any suggestions that don't require revamping the entire menubar code, if possible?
const menu = document.querySelector(".nav");
let open;
function openMenu() {
if (open) {
menu.style.display = "none";
open = false;
} else if (!open) {
menu.style.display = "block";
open = true;
}
}
.menubar {
width: 100%;
height: 50px;
line-height: 50px;
vertical-align: middle;
background-color: #fff;
border-bottom: 1px solid #f5f5f5;
position: fixed;
top: 0;
-webkit-user-select: all;
user-select: none;
display: flex;
align-items: center;
}
.logo {
font-size: 24px;
display: flex;
align-items: center;
padding-left: 15px;
position: absolute;
}
.nav {
display: flex;
font-size: 18px;
flex-direction: row;
list-style: none;
margin: 0 auto;
padding: 0;
}
.nav li {
margin: 0 15px;
}
.hamburger {
margin: 0 13px 0 auto;
height: inherit;
}
#media screen and (min-width: 801px) {
.nav {
display: flex !important;
}
.hamburger {
display: none;
}
}
#media screen and (max-width: 800px) {
.hamburger {
display: flex;
}
.nav {
display: none;
text-align: center;
}
}
<body>
<div class="menubar">
WEBSITE NAME
<ul class="nav">
<li>HOME</li>
<li>MENU1</li>
<li>MENU2</li>
<li>ABOUT</li>
</ul>
<input type="image" class="hamburger" onclick={openMenu()} src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Hamburger_icon.svg/800px-Hamburger_icon.svg.png" />
</div>
</body>
Accompanying JSFiddle.
You can add a window load and resizing listener. When the window gets smaller than 800px the script will add a class to your element.
I currently have it set to place a class .mobile. Made the necessary stylistic changes to this class for the mobile menu
Add this in your JS code:
window.addEventListener('resize', setMobileClass);
window.addEventListener('load', setMobileClass);
function setMobileClass() {
if (window.innerWidth <= 800) {
menu.classList.add('mobile');
} else {
menu.classList.remove('mobile');
}
};
Add this in your CSS:
.mobile {
position: absolute;
right: 0px;
top: 50px;
}
EXAMPLE:
const menu = document.querySelector(".nav");
let open;
function openMenu() {
if (open) {
menu.style.display = "none";
open = false;
} else if (!open) {
menu.style.display = "block";
open = true;
}
}
window.addEventListener('resize', setMobileClass);
window.addEventListener('load', setMobileClass);
function setMobileClass() {
if (window.innerWidth <= 800) {
menu.classList.add('mobile');
} else {
menu.classList.remove('mobile');
}
};
.menubar {
width: 100%;
height: 50px;
line-height: 50px;
vertical-align: middle;
background-color: #fff;
border-bottom: 1px solid #f5f5f5;
position: fixed;
top: 0;
-webkit-user-select: all;
user-select: none;
display: flex;
align-items: center;
}
.logo {
font-size: 24px;
display: flex;
align-items: center;
padding-left: 15px;
position: absolute;
}
.nav {
display: flex;
font-size: 18px;
flex-direction: row;
list-style: none;
margin: 0 auto;
padding: 0;
}
.nav li {
margin: 0 15px;
}
.hamburger {
margin: 0 13px 0 auto;
height: inherit;
}
#media screen and (min-width: 801px) {
.nav {
display: flex !important;
}
.hamburger {
display: none;
}
}
#media screen and (max-width: 800px) {
.hamburger {
display: flex;
}
.nav {
display: none;
text-align: center;
}
}
.mobile {
position: absolute;
right: 0px;
top: 50px;
}
<div class="menubar">
WEBSITE NAME
<ul class="nav">
<li>HOME</li>
<li>MENU1</li>
<li>MENU2</li>
<li>ABOUT</li>
</ul>
<input type="image" class="hamburger" onclick={openMenu()}
src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Hamburger_icon.svg/800px-Hamburger_icon.svg.png" />
</div>
I found a fitting and elegant solution based on 54ka's answer. Instead of adding a mobile class with extra JS code, I modified screen-size restricted nav class to be the following:
#media screen and (max-width: 800px) {
.hamburger {
display: flex;
}
.nav {
display: none;
position: absolute;
text-align: center;
width: 100%;
right: 0px;
top: 50px;
}
}
This ensured that the menu would appear centered, underneath the menubar. Additional background-color and border commands can be added to clean up the dropdown menu.

visibility style does not change second time click in javascript and css

I'm trying to create a responsive navbar.
When screen size is reduced I'm using media query to style visibility of #nav-items to hidden and display a menu icon.
I have written a javascript code to handle on click on menu icon style #nav-itmes to visible and hidden (trying to toggle by if condition to check style value)
Problem: on first click result is ok. #nav-items are visible but again when i click #nav-items style does not change to hidden (while i can console click event is there on every click)
Can anyone guide me ?
There are several approach to have this result to toggle an element but I want to only know what is issue in below code. (only javascript please).
let nav_icon = document.getElementById("nav-icon");
nav_icon.addEventListener("click", () => {
console.log('clicked');
let nav_items = document.getElementById("nav-items");
nav_items.style.visibility = nav_items.style.visibility = "hidden" ? "visible" : "hidden";
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: Arial, sans-serif;
}
a,
ul,
h3 {
text-decoration: none;
color: white;
list-style-type: none;
font-weight: bold;
}
body {
background-image: url("/img/bg.jpg");
}
img {
display: none;
height: 30px;
width: 30px;
margin-right: 10px;
position: fixed;
top: .4em;
right: .2em;
}
.navbar {
display: flex;
height: 40px;
width: 100%;
align-items: center;
justify-content: space-between;
background-color: #ABA9A966;
gap: 10px;
}
nav a,
header h3 {
margin: 0px 10px 0px 10px;
}
nav a:hover {
background-color: grey;
}
#media screen and (max-width: 800px) {
nav a,
header h3 {
margin: 0px 5px 0px 5px;
font-size: 15px;
}
}
#media screen and (max-width: 600px) {
.navbar {
flex-flow: column;
}
header {
display: none;
}
nav {
width: auto;
text-align: center;
background-color: #ABA9A966;
position: fixed;
visibility: hidden;
top: 2.5em;
right: 0;
}
nav a {
margin: 0;
height: 22px;
padding-top: 3px;
display: block;
width: 8rem;
font-size: 14px;
}
img {
display: block;
}
}
<meta name="viewport" content="width=device-width, initial-scale=1">
<div class="navbar">
<header>
<h3>Hello Guest</h3>
</header>
<nav id="nav-items">
Home
Dispatch
Account
Report
Control
</nav>
</div>
<img src="/img/menu.png" id="nav-icon">
Often you cannot see the style of an element in JS if the style was applied in a stylesheet
You can toggle a class instead
For example
nav { visibility: hidden; }
nav.show { visibility: visible; }
and js
const nav_icon = document.getElementById("nav-icon");
const nav_items = document.getElementById("nav-items");
nav_icon.addEventListener("click", () => {
console.log('clicked');
nav_items.classList.toggle("show")
});
const nav_icon = document.getElementById("nav-icon");
const nav_items = document.getElementById("nav-items");
nav_icon.addEventListener("click", () => {
console.log('clicked');
nav_items.classList.toggle("show")
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: Arial, sans-serif;
}
a,
ul,
h3 {
text-decoration: none;
color: white;
list-style-type: none;
font-weight: bold;
}
body {
background-image: url("/img/bg.jpg");
}
img {
height: 30px;
width: 30px;
margin-right: 10px;
position: fixed;
top: .4em;
right: .2em;
}
.navbar {
display: flex;
height: 40px;
width: 100%;
align-items: center;
justify-content: space-between;
background-color: #ABA9A966;
gap: 10px;
}
nav { visibility: hidden; }
nav a,
header h3 {
margin: 0px 10px 0px 10px;
}
nav a:hover {
background-color: grey;
}
#media screen and (max-width: 800px) {
nav a,
header h3 {
margin: 0px 5px 0px 5px;
font-size: 15px;
}
}
#media screen and (max-width: 600px) {
.navbar {
flex-flow: column;
}
header {
display: none;
}
nav {
width: auto;
text-align: center;
background-color: #ABA9A966;
position: fixed;
visibility: hidden;
top: 2.5em;
right: 0;
}
nav a {
margin: 0;
height: 22px;
padding-top: 3px;
display: block;
width: 8rem;
font-size: 14px;
}
img {
display: block;
}
}
nav.show {
visibility: visible;
}
<meta name="viewport" content="width=device-width, initial-scale=1">
<div class="navbar">
<header>
<h3>Hello Guest</h3>
</header>
<nav id="nav-items">
Home
Dispatch
Account
Report
Control
</nav>
</div>
<img src="/img/menu.png" id="nav-icon" title="ICON" alt="ICON">
Think this line is incorrect:
nav_items.style.visibility = nav_items.style.visibility = "hidden" ? "visible" : "hidden";
The equality check should be:
nav_items.style.visibility === "hidden"
so this may work:
nav_items.style.visibility = (nav_items.style.visibility === "hidden" ? "visible" : "hidden");
Try the css property for media-query: display:none !important;

Fixing react-responsive-carousel display on mobile

I'm still a beginner with ReactJS and I need to create a Carousel that is responsive, the way I need to leave is like this:
I was able to create Carousel on both desktop and responsive using the react-responsive-carousel library.
The problem is that in the mobile format, when I pass the slides of each Carousel, the expected behavior is not happening. When I click to show the next slide, in Carousel it still shows the current slide, and just a piece of the next slide.
It is easier to explain by showing a short gif I made, notice what happens when I click to show the next slide.
When it is in the desktop format, Carousel works the right way, I also created a small gif to show it.
Can you tell me what you’re doing wrong so that Carousel is working that way?
import React from "react";
import PropTypes from "prop-types";
import "./carousel.scss";
import { Carousel as CarouselLib } from "react-responsive-carousel";
import { CAROUSEL_ITEMS } from "./Carousel.utils";
const Carousel = ({ subtitle, testID, title }) => {
const items = React.useMemo(
() =>
CAROUSEL_ITEMS.map((item) => (
<div key={item.id}>
<div className="images">
<img className="image" src={item.url} alt="" />
</div>
<div className="infos">
<h3>{item.title}</h3>
<span>{item.subtitle}</span>
</div>
</div>
)),
[]
);
return (
<div data-testid={`${testID}_Container`} className="carousel-container">
<div className="carousel-header">
<h5>{subtitle}</h5>
<h3>{title}</h3>
</div>
<div className="carousel-content">
<CarouselLib
centerMode
showStatus={false}
dynamicHeight={false}
emulateTouch
swipeScrollTolerance={50}
centerSlidePercentage={30}
showThumbs={false}
infiniteLoop
showIndicators
renderArrowPrev={(onClickHandler, hasPrev, label) =>
hasPrev && <div />
}
renderArrowNext={(onClickHandler, hasNext, label) =>
hasNext && (
<button
type="button"
onClick={onClickHandler}
className="custom-arrow"
data-testid={`${testID}_Button_Next`}
/>
)
}
>
{items}
</CarouselLib>
</div>
</div>
);
};
Carousel.propTypes = {
subtitle: PropTypes.string,
testID: PropTypes.string.isRequired,
title: PropTypes.string
};
Carousel.defaultProps = {
testID: "Carousel",
subtitle: "READ OUR CLIENT",
title: "CASES"
};
export default Carousel;
.carousel {
&-container {
.images {
background-color: #fff;
width: 100%;
max-width: 416px;
height: 280px;
.image {
width: 100%;
height: auto;
background-position: center center;
background-repeat: no-repeat;
}
#media (max-width: 600px) {
max-width: 270px;
height: auto;
}
}
.infos {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
h3 {
font-family: Alliance2;
color: #000;
line-height: 0.76;
font-size: 2.5rem;
letter-spacing: normal;
font-style: normal;
font-weight: normal;
font-stretch: normal;
margin: 24px 0 20px 0;
#media (max-width: 600px) {
font-size: 1.5rem;
}
}
span {
font-family: Alliance2;
color: #000;
line-height: 0.76;
font-size: 1rem;
letter-spacing: normal;
font-style: normal;
font-weight: 500;
font-stretch: normal;
text-transform: uppercase;
margin-bottom: 30px;
#media (max-width: 600px) {
font-size: 0.625rem;
}
}
}
.carousel {
.slide {
background-color: transparent !important;
#media (max-width: 1024px) {
min-width: 50% !important;
}
#media (max-width: 600px) {
min-width: 90% !important;
}
}
.control-dots {
.dot {
border-radius: 0 !important;
background-color: #000 !important;
width: 33px !important;
height: 3px !important;
box-shadow: none !important;
opacity: 1 !important;
&.selected {
height: 7px !important;
}
&:focus {
outline: none !important;
}
}
}
}
}
&-header {
color: #000;
font-family: 'Alliance2';
font-weight: 300;
margin: auto;
max-width: 1300px;
text-transform: uppercase;
#media (max-width: 960px) {
align-items: center;
display: flex;
flex-direction: column;
}
h5 {
font-size: 1rem;
font-weight: bold;
margin: 0;
}
h3 {
height: 80px;
margin-top: 13px;
margin-bottom: 44px;
color: #000;
font-size: 3.5rem;
line-height: 1.04;
letter-spacing: -1.1px;
#media (max-width: 960px) {
font-size: 1.87rem;
}
#media (max-width: 600px) {
margin-bottom: 0;
}
}
}
&-content {
margin: auto;
max-width: 1440px;
width: 100%;
.custom-arrow {
position: absolute;
top: 7em;
bottom: auto;
right: 4.3em;
background-color: transparent;
border: none;
border-left: 4px solid #000;
border-bottom: 4px solid #000;
width: 67px;
height: 67px;
transform: rotate(225deg);
cursor: pointer;
&:focus {
outline: none !important;
}
}
}
}
Thank you very much in advance for any help/tip.
I don't know react-responsive-carousel , I'm using react-slick (here) in my projects and I never had a problem with the responsive.
I had a similar trouble with this lib, i solved the mobile question adding a few lines of CSS to the main div of my Carousel component:
#media only screen and (max-width: 600px) {
.carousel-wrapper{
max-width: 100%;
}
}

Toggle nav menu when clicked on nav links or outside

I have been trying to make my mobile navigation menu to toggle back when I click outside the navigation links or when I click on one of them. I have looked around and I only find jQuery example which I'm avoiding. I want to have an example with JavaScript ES6. So, how can I make it work?
Here is my code:
const navSlide = () => {
const burger = document.querySelector('.burger');
const nav = document.querySelector('.nav-links');
burger.addEventListener('click', () => {
nav.classList.toggle('nav-active');
})
}
navSlide();
html {
scroll-behavior: smooth;
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
font-family: Gelion;
background-color: #fa555204;
}
.nav-links li a, .logo {
text-decoration: none;
}
ul {
list-style: none;
}
.main-nav {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 18px;
height: 10%;
padding: 20px 0;
}
.nav-links {
display: flex;
}
.nav-links li {
padding: 0 15px;
}
.burger{
display: none;
}
/* Media Query - Mobile */
#media only screen and (max-width: 700px) {
body {
overflow-x: hidden;
}
/* Burger Menu */
.nav-links {
position: fixed;
right: 0;
height: 100vh;
width: 60%;
top: 0vh;
background-color: var(--secondary-color);
display: flex;
justify-content: space-evenly;
align-items: center;
flex-direction: column;
transform: translateX(100%);
transition: transform 0.5s ease-in;
z-index: 1;
}
.nav-links li a {
color: #fff;
}
.nav-active {
transform: translateX(0%);
}
.main-nav .burger {
display: block;
cursor: pointer;
font-size: 35px;
}
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css" rel="stylesheet"/>
<nav class="main-nav">
<a href="#" class="logo" />Logo</a>
<ul class="nav-links">
<li>Overview</li>
<li>Contagion</li>
<li>Symptoms</li>
<li>Prevention</li>
<li>Contact</li>
</ul>
<div class="burger">
<i class="fas fa-bars"></i>
</div>
</nav>
you can use css very easy for this Using :focus Selector
checkout this link : https://www.w3schools.com/cssref/sel_focus.asp
or try this
.classname:focus{
//your code here will run while client focused in this class
}

Why does my div still display when its height is set to 0?

I understand this is probably a question that has been asked before, but I haven't found a post or another question that has solved this issue.
I want to make a drop down mobile menu with Javascript by toggling the height of the #mobileMenu div. I wanted the div to have an initial height of 0 when the document loads, and add its full height when the triggering button is clicked. The only issue is when I set the div's initial height to 0, the document still displays the div with a height of 27.59px which doesn't make much sense to me.
I've tried adding: overflow: hidden; / line-height: 0; / display: block but no matter what I do, the div will not go below 27.59px in height. I even completed the Javascript functionality and the div will open to 154px in height, but when closed it goes back to 27.59px instead of 0.
const openBtn = document.querySelector('.open');
const closeBtn = document.querySelector('.close');
const mobileMenu = document.getElementById('mobileMenu');
openBtn.addEventListener('click', e => {
mobileMenu.classList.remove('hidden');
mobileMenu.classList.add('active');
openBtn.style.display = 'none';
closeBtn.style.display = 'block';
});
closeBtn.addEventListener('click', e => {
mobileMenu.classList.remove('active');
mobileMenu.classList.add('hidden');
openBtn.style.display = 'block';
closeBtn.style.display = 'none';
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
position: relative;
}
/* Header */
header {
display: flex;
justify-content: space-around;
align-items: center;
padding: .5rem;
height: 60px;
position: fixed;
top: 0;
left: 0;
right: 0;
}
header h2 {
font-family: 'Calistoga';
letter-spacing: 2px;
}
header i {
font-size: 1.5rem;
}
header i:hover {
cursor: pointer;
}
header i.close {
display: none;
}
/* Mobile Nav */
#mobileMenu {
padding: .8rem 0;
border-top: 1px solid #000;
border-bottom: 1px solid #000;
position: fixed;
top: 92px;
left: 0;
right: 0;
overflow: hidden;
transition: height .7s ease-in-out;
}
#mobileMenu.hidden {
height: 0;
line-height: 0;
display: block;
}
#mobileMenu.active {
height: 154px;
}
.mobile-nav {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
list-style: none;
}
.mobile-nav li {
padding: .3rem 0;
}
.mobile-nav li a {
text-decoration: none;
font-size: 1.2rem;
color: #000;
}
<header>
<h2>Website Header</h2>
<i class="fas fa-chevron-down open"></i>
<i class="fas fa-chevron-up close"></i>
</header>
<div id="mobileMenu" class="hidden">
<ul class="mobile-nav">
<li>
Home
</li>
<li>
Services
</li>
<li>
About
</li>
<li>
Contact
</li>
</ul>
</div>
With or without the overflow: hidden; / line-height: 0; / display: block the result remains the same.
Any help would be much appreciated. Thank you for your time.
Try to set hidden property on mobileMenu div, and update accordingly on button click. This way you avoid messing with css classes
const openBtn = document.querySelector('.open');
const closeBtn = document.querySelector('.close');
const mobileMenu = document.getElementById('mobileMenu');
openBtn.addEventListener('click', e => {
mobileMenu.hidden = false;
//mobileMenu.classList.add('active');
openBtn.style.display = 'none';
closeBtn.style.display = 'block';
});
closeBtn.addEventListener('click', e => {
//mobileMenu.classList.remove('active');
mobileMenu.hidden = true;
openBtn.style.display = 'block';
closeBtn.style.display = 'none';
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
position: relative;
}
/* Header */
header {
display: flex;
justify-content: space-around;
align-items: center;
padding: .5rem;
height: 60px;
position: fixed;
top: 0;
left: 0;
right: 0;
}
header h2 {
font-family: 'Calistoga';
letter-spacing: 2px;
}
header i {
font-size: 1.5rem;
}
header i:hover {
cursor: pointer;
}
header i.close {
display: none;
}
/* Mobile Nav */
#mobileMenu {
padding: .8rem 0;
border-top: 1px solid #000;
border-bottom: 1px solid #000;
position: fixed;
top: 92px;
left: 0;
right: 0;
overflow: hidden;
transition: height .7s ease-in-out;
}
#mobileMenu.hidden {
height: 0;
line-height: 0;
display: block;
}
#mobileMenu.active {
height: 154px;
}
.mobile-nav {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
list-style: none;
}
.mobile-nav li {
padding: .3rem 0;
}
.mobile-nav li a {
text-decoration: none;
font-size: 1.2rem;
color: #000;
}
<header>
<h2>Website Header</h2>
<i class="fas fa-chevron-down open"></i>
<i class="fas fa-chevron-up close"></i>
</header>
<div id="mobileMenu" hidden>
<ul class="mobile-nav">
<li>
Home
</li>
<li>
Services
</li>
<li>
About
</li>
<li>
Contact
</li>
</ul>
</div>
How about making the default for the menu your hidden state and removing the hidden class. Block is the default display for a div so that's not needed. Try setting padding on #mobileMenu to 0, and setting margin on .mobile-nav to .8rem 0
Using your logic but with this only change will fix it:
#mobileMenu.hidden {
height: 0;
+ padding: 0; /*the initial padding: .8rem 0; creates the 27.59px height (0.8rem top + 0.8rem bottom)*/
line-height: 0;
display: block;
}

Categories