How do I collapse a menu on a one-page layout? - javascript

I have taken over a project from another developer that I am trying to clean up and improve. The company who owns the site wanted a one-page layout, so I began building that, but I am having trouble with the responsive navbar, which comes with a dropdown menu. My problem is that when I press one of the links in the dropdown section, it will take me to the correct section of the page, but if I want to go to one of the other links afterwards I have to refresh the page, because the dropdown menu will not appear when I hover over the list item.
I know it sounds confusing, but let me show you the test page I am making, and maybe it will be more clear (I am sorry that it is not in english)
http://www.handig.dk/test/index.html
When you are on the page, hover over the item called "Menukort". You notice that the dropdown menu appears right? Try clicking on one of the links. Once you have done that, try hovering over "Menukort" again. Do you notice that the dropdown menu no longer appears?
Also if you CLICK on "Menukort", you are brought back to the top of the page, which I do not want either.
Do you have any suggestions of how to fix this problem?
Here is the code for the navbar.
The HTML
<section class="navigation">
<div class="nav-container" id="myHeader">
<nav>
<div class="nav-mobile"><a id="nav-toggle" href="#!"><span></span></a></div>
<ul class="nav-list">
<li>Forside</li>
<li>Om os</li>
<li> Menukort
<ul class="nav-dropdown">
<li>Frokost</li>
<li>Aften</li>
<li>Drikkevarer</li>
</ul>
</li>
<li>Bordbestilling</li>
<li> Mad ud af huset
<ul class="nav-dropdown">
<li>Take Away</li>
<li>Festbuffet</li>
<li>Brunch</li>
<li>Receptionsmad</li>
</ul>
</li>
<li>Selskaber</li>
<li>Hotellet</li>
<li>Find os</li>
</ul>
</nav>
</div>
</section>
The CSS
.nav-container {
display: flex;
justify-content: center;
max-width: 100%;
margin: 0 auto;
background-color: #f1f1f1;
}
.navigation {
display: flex;
justify-content: center;
height: 70px;
background-color: #f1f1f1;
}
nav ul {
list-style: none;
margin: 0;
padding: 0;
background-color: #f1f1f1;
}
nav ul li {
float: left;
position: relative;
background-color: #f1f1f1;
}
nav ul li a,
nav ul li a:visited {
display: block;
padding: 0 20px;
line-height: 70px;
color: #333;
text-decoration: none;
background-color: #f1f1f1;
}
nav ul li a:hover,
nav ul li a:visited:hover {
color: #84a0a8;
}
nav ul li a:not(:only-child):after,
nav ul li a:visited:not(:only-child):after {
padding-left: 4px;
content: '';
}
nav ul li ul li {
min-width: 190px;
}
nav ul li ul li a {
padding: 15px;
line-height: 20px;
}
.nav-dropdown {
position: absolute;
display: none;
z-index: 1;
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.15);
background-color: #f1f1f1;
}
nav ul li:hover .nav-dropdown {
display: block;
}
.sticky {
position: fixed;
top: 0;
width: 100%;
box-shadow: 0 2px 4px 0 rgba(0,0,0,.2);
}
.sticky + .nav-container {
padding-top: 102px;
}
/* Mobile navigation */
.nav-mobile {
display: none;
height: 35px;/* ???? */
/*width: 25px;*/
}
#media only screen and (max-width: 798px) {
.nav-mobile {
display: block;
position:relative;
}
nav {
width: 100%;
padding: 70px 0 15px;
}
nav ul {
display: none;
}
nav ul li {
float: none;
}
nav ul li a {
padding: 15px;
line-height: 20px;
}
nav ul li ul li a {
padding-left: 30px;
}
.nav-dropdown {
position: static;
}
}
#media screen and (min-width: 799px) {
.nav-list {
display: block !important;
}
}
#nav-toggle{
position:relative;
padding:10px 35px 16px;
display:table;
margin:-35px auto 0;
}
#nav-toggle span{margin:auto;left:0;right:0;}
#nav-toggle span,
#nav-toggle span:before,
#nav-toggle span:after {
cursor: pointer;
border-radius: 1px;
height: 5px;
width: 35px;
background: #333;
position: absolute;
display: block;
content: "";
transition: all 300ms ease-in-out;
}
#nav-toggle span:before {
top: -10px;
}
#nav-toggle span:after {
bottom: -10px;
}
#nav-toggle.active span {
background-color: transparent;
}
#nav-toggle.active span:before,
#nav-toggle.active span:after {
top: 0;
}
#nav-toggle.active span:before {
transform: rotate(45deg);
}
#nav-toggle.active span:after {
transform: rotate(-45deg);
}
The JavaScript (The slideUp function does not work either for some reason. I cannot get the menu to close after I click on a link in the mobile menu)
(function($) { // Begin jQuery
$(function() { // DOM ready
// If a link has a dropdown, add sub menu toggle.
$('nav ul li a:not(:only-child)').click(function(e) {
$(this).siblings('.nav-dropdown').toggle();
// Close one dropdown when selecting another
$('.nav-dropdown').not($(this).siblings()).hide();
e.stopPropagation();
});
// Clicking away from dropdown will remove the dropdown class
$('html').click(function() {
$('.nav-dropdown').hide();
});
// Toggle open and close nav styles on click
$('#nav-toggle').click(function() {
$('nav ul').slideToggle();
});
// Hamburger to X toggle
$('#nav-toggle').on('click', function() {
this.classList.toggle('active');
});
$('.nav-dropdown li a').on("click", function(){
$('#nav-toggle').slideUp();
});
}); // end DOM ready
})(jQuery); // end jQuery

Here is the problem:
$('html').click(function() {
$('.nav-dropdown').hide();
});
When you put .hide make that the css hide the element and you cant see it replace it.

I added a hover function to toggle the menu just as the click is doing. Right now, the css provides that rule, but gets overwritten by the JQuery after it toggles it closed. Use javascript:void(0) instead of # to avoid anchoring to the top of the page.
Pen:
https://codepen.io/richiegarcia/pen/oNxmXGK
(function($) { // Begin jQuery
$(function() { // DOM ready
//Hover shows submenu
$('nav ul li a:not(:only-child)').hover(function(e) {
$(this).children('.nav-dropdown').toggle();
// Close one dropdown when selecting another
});
// If a link has a dropdown, add sub menu toggle.
$('nav ul li a:not(:only-child)').click(function(e) {
$(this).siblings('.nav-dropdown').toggle();
// Close one dropdown when selecting another
$('.nav-dropdown').not($(this).siblings()).hide();
e.stopPropagation();
});
// Clicking away from dropdown will remove the dropdown class
$('html').click(function() {
$('.nav-dropdown').hide();
});
// Toggle open and close nav styles on click
$('#nav-toggle').click(function() {
$('nav ul').slideToggle();
});
// Hamburger to X toggle
$('#nav-toggle').on('click', function() {
this.classList.toggle('active');
});
$('.nav-dropdown li a').on("click", function(){
$('#nav-toggle').slideUp();
});
}); // end DOM ready
})(jQuery); // end jQuery

Related

Dropdown - cant click on the items

I'm trying to fix my dropdown, whenever I hover over my dropdown I can't click on the items because it disappears before I can click on them. I don't know how to fix it. Here is a bit of code I have.
#navContainer {
margin: 0;
padding: 0;
padding-top: 17px;
width: 220px;
}
#navContainer ul {
margin: 0;
padding: 0;
list-style: none;
}
#navContainer ul li {
position: relative;
}
#navContainer ul li span {
display: block;
}
#navContainer ul li a {
text-decoration: underline;
color: orange;
display: block;
padding: 8px;
font-weight: bold;
font-size: large;
}
#navContainer ul ul {
position: absolute;
display: none;
}
#navContainer ul li:hover ul {
width: 80%;
position: absolute;
display: block;
left: 88px;
top: 0;
}
<div id="navContainer">
<ul>
<li><span>Home</span></li>
<li>
<span>About </span>
<ul>
</ul>
</li>
<li>
<span>Quiz's</span>
<ul>
<li>McDonalds</li>
<li>KFC</li>
<li>Burger King</li>
<li>Subway</li>
</ul>
</li>
<li><span>Info</span></li>
</ul>
</div>
This is how my page looks, if i try to move my mouse from McDonalds to KFC my navbar disapears
I tried to make it so the navbar toggles when i click on Quiz's but i couldn't make it work. I hope someone can help me fix it.
Just a couple of issues with your selectors in your CSS. I added background-color so you can see visually how they are connected. Also, the span seemed unnecessary.
#navContainer {
margin: 0;
padding: 0;
padding-top: 17px;
width: 220px;
position: relative;
}
#navContainer ul {
margin: 0;
padding: 0;
list-style: none;
background: lightgrey;
position: relative;
}
ul>li {
position: relative;
}
#navContainer ul li a {
text-decoration: underline;
color: orange;
display: block;
padding: 8px;
font-weight: bold;
font-size: large;
position: relative;
}
#navContainer ul>li>ul {
position: absolute;
display: none;
left: 100%;
width: 100%;
background-color: pink;
top: 0px;
}
#navContainer>ul>li:hover>ul {
display: block;
}
<div id="navContainer">
<ul>
<li>Home</li>
<li>
About
<ul>
</ul>
</li>
<li>
Quiz's
<ul>
<li>McDonalds</li>
<li>KFC</li>
<li>Burger King</li>
<li>Subway</li>
</ul>
</li>
<li>Info</li>
</ul>
</div>
You set the submenu ul to be visible when hovered on parent li item here: #navContainer ul li:hover ul, so as soon as mouse leaves parent li, the submenu ul visibility is set back to none.
Added a border to the li elements to demonstrate.
https://jsfiddle.net/rojqczsp/
You have to work around this. May be try making parent li elements big enough to hold the submenu ul and set the submenu ul position to absolute to keep it within the parent element's dimensions. Or something else. But hope you understand how it works.

Is there a way to make my navbar active and also keep hover effect?

Hi im wondering how i can make my navbar also active so when im on my secton page for about for example. I want the red line to be under About and so on. How do i accomplish that?
I have been struggeling to make it active but cant do it and its the last thing and then im 100% satisfied with my page... well atleast for now... please help me would love all the help i can get.
window.addEventListener('scroll', function(){
var header = document.querySelector('header');
header.classList.toggle('sticky', window.scrollY > 0);
});
<!---Sticky navbar---->
header ul {
position: relative;
display: flex;
}
header ul li {
position: relative;
list-style: none;
}
header ul li a {
position: relative;
display: inline-block;
margin: 0 15px;
color: white;
text-decoration: none;
}
header.sticky ul li a{
color: black;
}
header ul li a::after{
content:'';
width: 0;
height: 3px;
background: #ff004f;
position: absolute;
left: 0;
bottom: -6px;
transition: 0.5s;
}
header ul li a:hover::after{
width: 100%;
}
<header>
MajorJammbaa
<div class="toggle" onclick="toggleMenu();"></div>
<ul class="menu">
<li><a class="active" href="#home" onclick="toggleMenu();">Home</a></li>
<li>About</li>
<li>Portfolio</li>
<li>Contact</li>
</ul>
</header>
<!--Front page image and text-------------------------------------------------------------------------------------------------------------------------------------------------->
<section class="landing-page" id="home">
You could create the function toggleMenu(element) which adds a class active to the given element and remembers it until the next call. When the function is called the next time it first checks if there is an active menu entry and deactivates it.
Consider the following code:
window.addEventListener('scroll', function() {
const header = document.querySelector('header');
header.classList.toggle('sticky', window.scrollY > 0);
});
let elActiveAnchor = null;
function toggleMenu(elAnchor) {
elActiveAnchor?.classList.remove('active');
(elActiveAnchor = elAnchor).classList.add('active');
}
toggleMenu(document.getElementById("menu-home"));
header ul {
position: relative;
display: flex;
}
header ul li {
position: relative;
list-style: none;
}
header ul li a {
position: relative;
display: inline-block;
margin: 0 15px;
color: gray;
text-decoration: none;
}
header.sticky ul li a {
color: black;
}
header ul li a::after {
content:'';
width: 0;
height: 3px;
background: #ff004f;
position: absolute;
left: 0;
bottom: -6px;
transition: 0.5s;
}
header ul li a:hover::after,
/* This is the new selector for the "active" menu entry */
header ul li a.active::after {
width: 100%;
}
<header>
MajorJammbaa
<div class="toggle" onclick="toggleMenu();"></div>
<ul class="menu">
<li><a id="menu-home" href="#home" onclick="toggleMenu(this)">Home</a></li>
<li>About</li>
<li>Portfolio</li>
<li>Contact</li>
</ul>
</header>
<!-- Front page image and text -->
<section class="landing-page" id="home">

Responsive mobile navbar links wont work on mobile

I have an issue with the responsive sidebar nav links(anchor tags) won't click
Here is the part of the HTML code
<!-- Nav -->
<nav class="main-nav">
<img src="img/logo-dark-transparent.png" alt="AS Logo" class="logo">
<ul class="main-menu">
<li>Home</li>
<li>About Me</li>
<li>Projects</li>
<li>Contact Me</li>
</ul>
....
</nav>
The main CSS code for navbar is here
.main-nav{
display: flex;
justify-content: space-between;
align-items: center;
height: 60px;
padding: 20px 0;
z-index: 1;
/* font-size: 1.5em; */
font-size: clamp(.5rem, .8vw + 1rem, 1.5rem);
}
.main-nav .logo{
width: 110px;
}
.main-nav ul{
display: flex;
}
.main-nav .main-menu li{
padding: 0 2em;
}
.main-nav .main-menu li a{
padding-bottom: 2px;
}
.main-nav .main-menu li a:hover{
border-bottom: 2px solid var(--text-color);
}
The CSS code for side nav is
#media(max-width:700px){
.container{
overflow-x: hidden;
}
section{
height: auto;
}
/* Navbar */
.menu-btn{
display: block;
}
.menu-btn:hover{
opacity: 0.5;
}
.main-nav ul.main-menu{
display: block;
position: absolute;
top: 0;
left: 0;
background: var(--bg-color);
filter: brightness(0.85);
width: 60%;
height: 100%;
opacity: 0.9;
padding: 30px;
transform: translateX(-500px);
transition: transform 0.5s ease;
}
.main-nav ul.main-menu.show{
transform: translateX(-20px);
}
.main-nav ul.main-menu li{
padding: 20px;
}
.main-nav ul.main-menu li:first-child{
margin-top: 2rem;
}
.main-nav ul.right-menu{
margin-right: 60px;
}
But the show class is toggled dynamically by JS code below
//Toggle Menu
const mainMenu = document.querySelector('.main-menu');
document.querySelector('.menu-btn').addEventListener('click', () => {
mainMenu.classList.toggle('show');
})
Also, I wanted to achieve smooth scrolling which works on desktop version but doesn't in the mobile sidebar menu using this JS code snippet
//Vanilla JS Smooth Scroll
document.querySelectorAll('.main-menu a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
I have been debugging for hours with no success, any help or advice would be appreciated.
Maybe the id of div you want to scroll with do not match the link(href) addresses.You need to make sure this. Also, you can do a null check in the JavaScript code as follows.
document.querySelectorAll('.main-menu a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
var elmnt = document.querySelector(this.getAttribute('href'));
if(elmnt != null) {
elmnt.scrollIntoView({
behavior: 'smooth'
});
}
});
});
Add !important in your CSS code
.menu-btn { display: block !important; }

Navigation bar issue with media queries

When my page is resized for mobile via media queries, I show a menu bar (handle), that allows the user to click and slideToggle the navigation bar, so they can see it.
When I manually resize my page, I notice the following issue:
When I was in mobile view, and the navigation bar was visible, then when I resize it, the nav bar is visible. But, if I close the nav bar in mobile view, and then resize to full screen, my nav bar disappears, and I'm not sure why. I believe there is a problem with my jQuery. Can anyone point me in the right direction?
$(document).ready(function() {
var handle = $(".handle");
var navigation = $(".navigation");
handle.click(function() {
navigation.slideToggle();
});
});
nav ul {
background-color: #43a286;
overflow: hidden;
color: white;
padding: 0;
text-align: center;
margin: 0;
}
nav ul li:hover {
background-color: #399077;
transition: 0.5s;
}
nav ul li {
display: inline-block;
padding: 20px;
}
.handle {
width: 100%;
background: #005c48;
text-align: left;
box-sizing: border-box;
padding: 15px;
color: white;
display: none;
}
.handle i {
float: right;
cursor: pointer;
}
#media screen and (max-width: 400px) {
nav ul li {
box-sizing: border-box;
width: 100%;
display: block;
padding: 15px;
text-align: left;
box-shadow: 1px 1px #399077;
}
.handle {
display: block;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<nav>
<div class="handle">Menu</div>
<ul class="navigation">
<li>Home</li>
<li>About</li>
<li>Service</li>
<li>Contact</li>
</ul>
</nav>
You need to reset the navigation from hidden to visible after switch back to desktop view, otherwise it will remain hidden if he navigation is hidden. You can do it via resize() function:
$(document).ready(mobileNav);
$(window).on('resize', mobileNav);
function mobileNav() {
var handle = $(".handle");
var navigation = $(".navigation");
if (window.innerWidth <= 400) {
navigation.hide();
} else {
navigation.show();
}
handle.unbind().click(function() {
navigation.slideToggle();
});
}
Also, <a> is not allowed directly under <ul>, so move them into <li>s.
jsFiddle
$(document).ready(mobileNav);
$(window).on('resize', mobileNav);
function mobileNav() {
var handle = $(".handle");
var navigation = $(".navigation");
if (window.innerWidth <= 400) {
navigation.hide();
} else {
navigation.show();
}
handle.unbind().click(function() {
navigation.slideToggle();
});
}
nav ul {
background-color: #43a286;
overflow: hidden;
color: white;
padding: 0;
text-align: center;
margin: 0;
}
nav ul li:hover {
background-color: #399077;
transition: 0.5s;
}
nav ul li {
display: inline-block;
}
nav ul li a {
display: block;
padding: 20px;
color: #fff;
}
.handle {
width: 100%;
background: #005c48;
text-align: left;
box-sizing: border-box;
padding: 15px;
color: white;
display: none;
}
.handle i {
float: right;
cursor: pointer;
}
#media screen and (max-width: 400px) {
nav ul li {
box-sizing: border-box;
width: 100%;
display: block;
text-align: left;
box-shadow: 1px 1px #399077;
}
nav ul li a {
padding: 15px;
}
.handle {
display: block;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<nav>
<div class="handle">Menu</div>
<ul class="navigation">
<li>Home</li>
<li>About</li>
<li>Service</li>
<li>Contact</li>
</ul>
</nav>
If you slideToggle the navigation menu once the .handle was clicked - it is now hidden. If you will resize the window (after the navigation is hidden) - it will still be hidden (because you did nothing to show it again).
You can use the resize event to run any other function once the window was resized (note that you will need to check if the resize was to shrink or enlarge the window, then you will need to check if the navigation is visible or not - and then to show it (if it's hidden).

How do I hide my dropdown menu?

I am making a website using html, and now I want to make a dropdown menu wich animates down slowly. This is my code:
<html>
<head>
<style type="text/css">
.nav {
background-color: #25AAA0;
position: fixed;
width: 100%;
margin: 0;
padding: 0;
z-index: 1000;
}
.nav_wrapper {
width: 90%;
margin: 0 auto;
text-align: left;
}
.nav ul {
list-style-type: none;
margin: 0;
padding: 0;
position: relative;
}
.nav ul li {
display: inline-block;
}
.nav ul li:hover {
background-color: #66C3BC;
}
.nav ul li a,visited {
text-decoration: none;
color: white;
padding: 15px;
display: block;
}
.nav ul li a:hover {
padding: 15px;
}
.nav ul #dropdown {
position: absolute;
background-color: black;
top: 0
}
</style>
</head>
<body>
<div class="nav">
<div class="nav_wrapper">
<ul>
<li>Vanilla<ul id="dropdown">
<li>Survival</li>
<li>Creative</li>
</ul></li><li>
Modded</li><li>
Servers</li><li>
Help</li>
</ul>
</div>
</div>
</body>
</html>
This is what it looks like.
What needs to happen is that the black part is behind and not in front of the rest of the navigation menu, so I can slide it down using jQuery. Does anyone know how to do this? I already tried something with z-index, but that doesn't work. And please don't tell me how I can animate the sliding down, I'm not asking that, I'm asking how I can put the black stuff behind the rest of the navigation bar.
I hope you react soon.
.nav ul #dropdown {
position: absolute;
background-color: black;
top: 50px;
}
.nav ul > li {position: relative;}
Be careful about relative and absolute positions.
You can animate it with CSS on :hover event or with javascript. I can help you with this if you wants but it's better for you to try first :)
You can hide it with several ways in CSS like display:none; visibility:hidden; or opacity:0; or height:0;
Here is a CSS solution I've made : See this fiddle

Categories