I have this javascript code I am using to add a hamburger menu in my webpage
const hamburger = document.querySelector(".hamburger");
hamburger.addEventListener("click", mobileMenu);
function mobileMenu() {
hamburger.classList.toggle("active");
Menu.classList.toggle("active");
}
menuLink.forEach(n => n.addEventListener("click", closeMenu));
function closeMenu() {
hamburger.classList.remove("active");
Menu.classList.remove("active");
}
and i want to add a hamburger menu so webpage would be responsive for small devices.. no errors are occurring but still no results are being showed when i run my code.
how can i change this code in order to work
const Menu = document.getElementById('navbar__list');
const sections = document.querySelectorAll('section');
/**
* End Global Variables
*/
// build the nav
NavBuilder = () => {
//to loop from section 1 to 4 and add sections to navigation
for (s = 0; s < sections.length; s++) {
const liElem = document.createElement('li');
//const divElem = document.createElement("div");
const Id = sections[s].id;
const DataNav = sections[s].dataset.nav;
liElem.innerHTML = `<a class="menu__link" href="#${Id}">${DataNav}</a>`;
Menu.appendChild(liElem);
}
}
NavBuilder();
//when scroll add your-active class to section and class active to navigation bar elements
window.addEventListener('scroll', () => {
sections.forEach(s => {
const topDistance = s.getBoundingClientRect().top;
// if the distance to the top is between 0-150px
if (topDistance >= 0 && topDistance < 150) {
s.classList.add('your-active-class');
// add class active to navugation in order to highlight the navigation when scrolling
document.querySelector(`a[href="#${s.id}"]`).classList.add("active");
// otherwise, remove the class
} else {
s.classList.remove('your-active-class');
document.querySelector(`a[href="#${s.id}"]`).classList.remove("active");
}
});
});
//set style to highlight active navigation bar elements
const menuLink = document.querySelectorAll(".menu__link");
addStyle = () => {
menuLink.forEach((anchor) => {
anchor.addEventListener("click", function() {
menuLink.forEach((anchor) => {
anchor.classList.remove("active");
});
anchor.classList.add("active");
});
});
}
addStyle();
scrollFunction = () => {
const menuLink = document.querySelectorAll(".menu__link");
menuLink.forEach((anchor) => {
anchor.addEventListener("click", function(event) {
event.preventDefault();
document.querySelector(anchor.getAttribute("href")).scrollIntoView({
behavior: "smooth",
});
});
});
};
scrollFunction();
const hamburger = document.querySelector(".hamburger");
hamburger.addEventListener("click", mobileMenu);
function mobileMenu() {
hamburger.classList.toggle("active");
Menu.classList.toggle("active");
}
menuLink.forEach(n => n.addEventListener("click", closeMenu));
function closeMenu() {
hamburger.classList.remove("active");
Menu.classList.remove("active");
}
#media only screen and (max-width: 768px) {
.navbar__list {
position: fixed;
left: -100%;
top: 5rem;
flex-direction: column;
background-color: #fff;
width: 100%;
border-radius: 10px;
text-align: center;
transition: 0.3s;
box-shadow: 0 10px 27px rgba(0, 0, 0, 0.05);
}
.navbar__list.active {
left: 0;
}
.hamburger {
display: block;
cursor: pointer;
}
}
.navbar__menu ul {
padding: 2px;
padding-left: 0;
margin: 0;
text-align: left;
background-color: gray;
}
.navbar__menu li {
display: inline-block;
}
.navbar__menu .menu__link {
display: inline-block;
padding: 7px;
font-weight: bold;
text-decoration: none;
color: #fff;
}
.navbar__menu .menu__link:hover {
background: #333;
color: #fff;
transition: ease 0.3s all;
}
<link href="https://fonts.googleapis.com/css?family=Fira+Sans:900|Merriweather&display=swap" rel="stylesheet">
<!-- HTML Follows BEM naming conventions
IDs are only used for sections to connect menu achors to sections -->
<header class="page__header">
<nav class="navbar__menu">
<!-- Navigation starts as empty UL that will be populated with JS -->
<ul id="navbar__list"></ul>
<div class="hamburger">
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</div>
</nav>
</header>
In the solution below I just focused on creating <a> elements dynamically and applying the .active class style by firing their click events. There are undefined behaviors in the solution you developed:
You tried to use the sections variable in many places even though the <section> element is not defined.
The local variable s used in the for loop is not defined using the let or var keywords.
You must add <a> elements to <li> elements and <li> elements as child nodes to <ul> for its current style to be applicable.
The page height must be greater than 100% for the scroll event to be triggered.
To capture the click events of dynamically created elements, you need a more specialized technique than the classical method.
const Menu = document.getElementById('navbar__list');
const sections = document.querySelectorAll('section');
const menuLink = document.querySelectorAll(".menu__link");
/* The structure you are using does not allow the creation of <a> elements because the <section> element is not defined. */
NavBuilder = (counter) => {
for (let s = 1; s <= counter ; s++) {
let liElement = document.createElement('li');
let aElement = document.createElement('a');
let textNode = document.createTextNode(s);
aElement.className = "menu__link";
aElement.setAttribute("href", "#");
aElement.appendChild(textNode);
aElement.setAttribute("id", `${s}`);
liElement.appendChild(aElement);
Menu.appendChild(liElement);
}
}
/* I used jQuery to catch "click" events as the <a> elements are created dynamically. */
$(document).on('click', '.menu__link', function() {
console.clear();
console.log(this);
$('.menu__link').removeClass("active");
$(this).addClass("active");
});
/* The <a> elements are created when the page loads. */
window.addEventListener('load', function(e) {
NavBuilder(10);
});
.navbar__menu ul {
padding: 2px;
padding-left: 0;
margin: 0;
text-align: left;
background-color: gray;
}
.active {
color: red !important;
}
.navbar__menu li {
display: inline-block;
}
.navbar__menu .menu__link {
display: inline-block;
padding: 7px;
font-weight: bold;
text-decoration: none;
color: #fff;
}
.navbar__menu .menu__link:hover {
background: #333;
color: #fff;
transition: ease 0.3s all;
}
#media only screen and (max-width: 768px) {
.navbar__list {
position: fixed;
left: -100%;
top: 5rem;
flex-direction: column;
background-color: #fff;
width: 100%;
border-radius: 10px;
text-align: center;
transition: 0.3s;
box-shadow: 0 10px 27px rgba(0, 0, 0, 0.05);
}
.navbar__list.active {
left: 0;
}
.hamburger {
display: block;
cursor: pointer;
}
}
<link href="https://fonts.googleapis.com/css?family=Fira+Sans:900|Merriweather&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header class="page__header">
<nav class="navbar__menu">
<ul id="navbar__list">
<!--
<li><a class="menu__link" href="#">First</a></li>
<li><a class="menu__link" href="#">Second</a></li>
<li><a class="menu__link" href="#">Thirth</a></li>
-->
</ul>
<div class="hamburger">
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</div>
</nav>
</header>
Related
I have this dropdown menu of multiple different bubbles and I want the menu that drops down underneath the bubbles to close when I click elsewhere, the last line of JS code that I provided in my example was my attempt at making this work but it seems to not be working for some reason. I included the total code for what I'm doing.
function toggleVisibility(link) {
// get the corresponding list
var list = link.parentElement.nextElementSibling;
// toggle the visibility of the list
if (list.style.display === "none") {
// hide all other lists
var otherLists = document.querySelectorAll(".dropdown-list-models");
for (var i = 0; i < otherLists.length; i++) {
otherLists[i].style.display = "none";
}
// position the selected list below the previous list
list.style.top = (link.parentElement.offsetTop + link.parentElement.offsetHeight) + "px";
// show the selected list
list.style.display = "block";
} else {
list.style.display = "none";
}
}
var container = document.querySelector(".dropdown-container-models");
container.addEventListener("click", function() {
var list = this.querySelector("ul");
if (list.style.display === "none") {
list.style.display = "block";
} else {
list.style.display = "none";
}
});
// add event listeners to each list item
var listItems = document.querySelectorAll(".dropdown-container-models ul li");
listItems.forEach(function(listItem) {
listItem.addEventListener("click", function() {
var link = this.querySelector("a");
window.location.href = link.href;
});
});
// Get the dropdown menu
var dropdownMenu = document.getElementById("myDropdownMenu");
// When the user clicks anywhere outside of the dropdown menu, close it
window.onclick = function(event) {
if (!event.target.matches('.dropdown-list-models')) {
dropdownMenu.classList.remove('show');
}
}
a {
color: white;
text-decoration: none;/* Change this to the desired color */
transition: #04AA6D 0.2s;
}
.dropdown-container-models {
position: relative; /* create a positioning context for the list items */
background-color: #333;
color: white;
text-decoration: none;
width: 150px;
text-align: center;
transition: background-color 0.2s;
display: inline-block;
cursor: pointer;
font-family: Arial, Helvetica, sans-serif;
border-radius: 10px;
}
.dropdown-container-models ul li {
cursor: pointer;
}
.dropdown-list-models {
position: absolute; /* position the list items absolutely */
display: none; /* hide the list by default */
top: 100px; /* hide the list by default */
list-style-type: none; /* remove the bullet points for the list items */
padding: 0; /* remove the padding for the list */
left: 0; /* position the list items at the left edge of the list */
transition: border 0.2s; /* add a transition effect for the border */
background-color: #b0b0b0;
color: black;
text-decoration: none;
width: 150px;
text-align: center;
transition: background-color 0.2s;
font-family: Arial, Helvetica, sans-serif;
border-radius: 10px;
}
.dropdown-list-models.show {
display: block; /* Show the menu when the .show class is added */
}
.dropdown-list-models li:hover {
background-color: #04AA6D;
transition: background-color 0.2s;
border-radius: 10px;/* change the background color of the list items to green when they are hovered over */
}
.dropdown-list-models li {
color: black; /* set the color of the list items to black */
text-align: center;
transition: #04AA6D 0.2s;
}
<div class="dropdown-container-models">
<p>Global Models</p>
<ul class="dropdown-list-models" id="myDropdownMenu">
<li>GFS</li>
<li>CMC</li>
<li>ECMWF</li>
</ul>
</div>
<div class="dropdown-container-models">
<p>Mesoscale Models</p>
<ul class="dropdown-list-models" id="myDropdownMenu">
<li>NAM 12km</li>
<li>NAM 3km</li>
<li>HRRR</li>
<li>HREF</li>
<li>NBM</li>
</ul>
</div>
<div class="dropdown-container-models">
<p>Ensembles</p>
<ul class="dropdown-list-models" id="myDropdownMenu">
<li>GEFS</li>
<li>GEPS</li>
<li>EPS</li>
</ul>
</div>
<div class="dropdown-container-models">
<p>Super Ensemble</p>
</div>
I'm sure there are several ways of doing this, but the tricky thing is that elements like <ul> do not have a blur event. Because of this, you have to sort of manually detect when the user clicks outside of an element.
I added 2 functions that basically utilize the elementsFromPoint() method and an event listener on the body. With this, you can get a list of all elements located at the x/y positions of the mouse when the user clicks anywhere in the document. Then you just check to see if your dropdown element is at the clicked location, if not you can trigger some other action (passed in as a function), like hiding the dropdown.
I also took out a bit of your original code because it wasn't really necessary. It seemed like you had multiple method of showing/hiding the dropdowns all in the code together, which made for some weird results. So here is a simplified version with the added blur detection:
document.querySelectorAll(".dropdown-container-models").forEach(d => {
d.addEventListener("click", e => {
const dropdown = e.target.closest(".dropdown-container-models").querySelector("ul")
if(dropdown) {
dropdown.style.display = "block"
_ElementBlur(e.target, () => {
dropdown.style.display = "none"
})
}
})
})
document.querySelectorAll(".dropdown-container-models ul li").forEach(listItem => {
listItem.addEventListener("click", e => {
window.location.href = e.target.querySelector("a").href
})
})
// Functions for getting a 'blur' event on an element
const _ElementBlur = (el, f = false) => {
const ac = new AbortController()
document.body.addEventListener("click", _CheckBlur(el, f, ac), { signal: ac.signal })
}
const _CheckBlur = (el, f = false, ac) => {
return e => {
if(!document.elementsFromPoint(e.clientX, e.clientY).filter(efp => efp == el).length || !document.elementsFromPoint(e.clientX, e.clientY).length) {
if(f && typeof(f) == "function") f()
ac.abort()
}
}
}
html, body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
a {
color: white;
text-decoration: none;/* Change this to the desired color */
transition: #04AA6D 0.2s;
}
.dropdown-container-models {
position: relative; /* create a positioning context for the list items */
background-color: #333;
color: white;
text-decoration: none;
width: 150px;
text-align: center;
transition: background-color 0.2s;
display: inline-block;
cursor: pointer;
font-family: Arial, Helvetica, sans-serif;
border-radius: 10px;
}
.dropdown-container-models ul li {
cursor: pointer;
}
.dropdown-list-models {
position: absolute; /* position the list items absolutely */
display: none; /* hide the list by default */
top: 100px; /* hide the list by default */
list-style-type: none; /* remove the bullet points for the list items */
padding: 0; /* remove the padding for the list */
left: 0; /* position the list items at the left edge of the list */
transition: border 0.2s; /* add a transition effect for the border */
background-color: #b0b0b0;
color: black;
text-decoration: none;
width: 150px;
text-align: center;
transition: background-color 0.2s;
font-family: Arial, Helvetica, sans-serif;
border-radius: 10px;
}
.dropdown-list-models.show {
display: block; /* Show the menu when the .show class is added */
}
.dropdown-list-models li:hover {
background-color: #04AA6D;
transition: background-color 0.2s;
border-radius: 10px;/* change the background color of the list items to green when they are hovered over */
}
.dropdown-list-models li {
color: black; /* set the color of the list items to black */
text-align: center;
transition: #04AA6D 0.2s;
}
<div class="dropdown-container-models">
<p>Global Models</p>
<ul class="dropdown-list-models">
<li>GFS</li>
<li>CMC</li>
<li>ECMWF</li>
</ul>
</div>
<div class="dropdown-container-models">
<p>Mesoscale Models</p>
<ul class="dropdown-list-models">
<li>NAM 12km</li>
<li>NAM 3km</li>
<li>HRRR</li>
<li>HREF</li>
<li>NBM</li>
</ul>
</div>
<div class="dropdown-container-models">
<p>Ensembles</p>
<ul class="dropdown-list-models">
<li>GEFS</li>
<li>GEPS</li>
<li>EPS</li>
</ul>
</div>
<div class="dropdown-container-models">
<p>Super Ensemble</p>
</div>
I'm looking to make a left to right scrolling navigation menu that's items are highlighted as you scroll down the page. This navigation will look similarly to the following in page navigation on Chase.com (https://www.chase.com/digital/customer-service?jp_cmp=rb/tap/off/na/prt). Please note that I want this navigation to stay scrollable on all devices.
Below is what I have so far. I'm currently having the issue with getting the nav options to scroll into focus as they are highlighted.
window.onscroll = function() {
myFunction()
};
var navbar = document.getElementById("inpagenav");
var sticky = inpagenav.offsetTop;
function myFunction() {
if (window.pageYOffset >= sticky) {
inpagenav.classList.add("sticky")
} else {
inpagenav.classList.remove("sticky");
}
}
// cache the navigation links
var $navigationLinks = $('#inpagenav > ul > li > a');
// cache (in reversed order) the sections
var $sections = $($(".pagenavsection").get().reverse());
// map each section id to their corresponding navigation link
var sectionIdTonavigationLink = {};
$sections.each(function() {
var id = $(this).attr('id');
sectionIdTonavigationLink[id] = $('#inpagenav > ul > li > a[href=\\#' + id + ']');
});
// throttle function, enforces a minimum time interval
function throttle(fn, interval) {
var lastCall, timeoutId;
return function() {
var now = new Date().getTime();
if (lastCall && now < (lastCall + interval)) {
// if we are inside the interval we wait
clearTimeout(timeoutId);
timeoutId = setTimeout(function() {
lastCall = now;
fn.call();
}, interval - (now - lastCall));
} else {
// otherwise, we directly call the function
lastCall = now;
fn.call();
}
};
}
function highlightNavigation() {
// get the current vertical position of the scroll bar
var myPadding = $('#inpagenav').height();
var scrollPosition = $(window).scrollTop();
// iterate the sections
$sections.each(function() {
var currentSection = $(this);
// get the position of the section
var sectionTop = currentSection.offset().top;
// if the user has scrolled over the top of the section
if (scrollPosition + myPadding >= sectionTop) {
// get the section id
var id = currentSection.attr('id');
// get the corresponding navigation link
var $navigationLink = sectionIdTonavigationLink[id];
// if the link is not active
if (!$navigationLink.hasClass('active')) {
// remove .active class from all the links
$navigationLinks.removeClass('active');
// add .active class to the current link
$navigationLink.addClass('active');
}
// we have found our section, so we return false to exit the each loop
return false;
}
});
}
$(window).scroll(throttle(highlightNavigation, 100));
// if you don't want to throttle the function use this instead:
// $(window).scroll( highlightNavigation );
.mainimage {
text-align: center;
height: 300px;
background: gray
}
nav {
background: white;
}
.sticky {
position: fixed;
top: 0;
width: 100%;
}
nav ul {
list-style: none;
padding: 0rem;
overflow: auto;
white-space: nowrap;
margin: 0rem;
overflow-x: scroll;
}
nav ul::-webkit-scrollbar-thumb {
background: #000;
}
nav ul li {
padding-top: 1rem;
vertical-align: center;
display: inline-block;
}
nav ul li a {
text-decoration: none;
color: dodgerblue;
display: inline-block;
margin: 0rem 2rem;
padding-bottom: 1rem;
border-bottom: 3px solid transparent;
}
nav ul li a:hover {
color: #0054a4;
border-bottom: 3px solid #0054a4;
}
nav ul li .active {
color: #308ce3;
font-weight: bold;
border-bottom: 3px solid #308ce3;
}
#section1 {
text-align: center;
height: 500px;
padding: 4rem 0rem;
background: orange;
}
#section2 {
text-align: center;
height: 200px;
padding: 4rem 0rem;
background: green;
}
#section3 {
text-align: center;
height: 300px;
padding: 4rem 0rem;
background: blue;
}
#section4 {
text-align: center;
height: 500px;
padding: 4rem 0rem;
background: red;
}
#section5 {
text-align: center;
height: 500px;
padding: 4rem 0rem;
background: pink;
}
#section6 {
text-align: center;
height: 500px;
padding: 7rem 0rem;
background: purple;
}
#section7 {
text-align: center;
height: 500px;
padding: 7rem 0rem;
background: purple;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="menu.css">
<body>
<div id="contentwrapper">
<div class="mainimage">
<h1>The whole world</h1>
</div>
<nav id="inpagenav">
<ul>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
<li>Section 4</li>
<li>Section 5</li>
<li>Section 6</li>
</ul>
</nav>
<section id="section1" class="pagenavsection">
I'm section 1
</section>
<section id="section2" class="pagenavsection">
I'm section 2
</section>
<section id="section3" class="pagenavsection">
I'm section 3
</section>
<section id="section4" class="pagenavsection">
I'm section 4
</section>
<section id="section5" class="pagenavsection">
I'm section 5
</section>
<section id="section6" class="pagenavsection">
I'm section 6
</section>
<section id="section7">lo</section>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="ScrollMenu.js"></script>
</body>
</html>
You might just need to call $navigationLink.scrollIntoView() when you toggle the active class.
Per this answer, you may need to pass special options to scrollIntoView because the items are laid out horizontally.
$navigationLink.scrollIntoView({ inline: 'end' })
// end is my guess; allowable values are: start, center, end, or nearest (the default)
I have a burger (3 lines) <div class="burger"> in my navbar for mobile view (768px/less). When I click on it the menu slides from the right. the burger is hidden in desktop view.
I want to add a width to the menu links #menu li a once I click on the burger, than removing the width once the burger gets clicked on again, or once the page width is above 768px.
So far I managed to get the width to apply to the burger when it's clicked, but even when I click it again and check the desktop view the width won't go away.
My current codes:
// Navbar Slide
const burger = document.querySelector('.burger');
const menu = document.getElementById('menu');
const menuLinks = document.querySelectorAll('#menu li');
const menuCS = window.getComputedStyle(menu);
const width = menuCS.width;
const widthTest = '200px';
const navLinks = document.querySelectorAll('#menu li a');
const navSlide = () => {
burger.addEventListener('click', () => {
// # toggle nav
menu.classList.toggle('menu-active');
// # nav links width
navLinks.forEach((link) => {
link.style.width = width;
});
// # links animation
menuLinks.forEach((link, index) => {
if (link.style.animation) {
link.style.animation = '';
} else {
link.style.animation = `menuLinkFade .5s ease forwards ${index / 7 + 0.4}s`;
}
});
// # burger animation
burger.classList.toggle('toggle');
});
}
navSlide();
#menu {
display: flex;
justify-content: space-around;
width: auto;
height: 8vh;
margin-right: 10%;
}
#menu li a {
display: inline-block;
line-height: 8vh;
color: #ffffff;
text-decoration: none;
padding: 0 20px;
}
.burger {
display: none;
margin-right: 10%;
}
#media screen and (max-width:768px) {
#menu {
position: absolute;
top: 8vh;
right: 0;
height: 92vh;
width: 50%;
display: flex;
flex-direction: column;
align-items: center;
background-color: #313131;
margin: 0;
justify-content: normal;
transform: translateX(100%);
transition: transform .5s ease-in;
}
#menu.menu-active {
transform: translateX(0%);
}
#menu li a {
text-align: center;
padding: 40px 0;
}
.burger {
display: block;
cursor: pointer;
position: absolute;
right: 0;
}
}
<div id="nav">
<div class="logo">
<h4>The Nav</h4>
</div>
<ul id="menu">
<li class="active">Home</li>
<li><a href="#">About</a class="view"></li>
<li><a href="#">Contact</a class="view"></li>
<li><a href="#">Product</a class="view"></li>
</ul>
<div class="burger">
<div class="line1"></div>
<div class="line2"></div>
<div class="line3"></div>
</div>
</div>
I tried different approaches but nothing seems to work for me.
SOLVED. I just added a class="desktop" to the links and put a width: auto !important in it, and than added that to javascript:
// # nav links width
navLinks.forEach((link) => {
link.style.width = width;
link.classList.toggle('desktop');
});
// Check Width
window.addEventListener("resize", function(event) {
if (document.body.clientWidth > 751) {
if (!navLinks.desktop) {
navLinks.forEach((link) => {
link.classList.add('desktop');
});
}
menu.classList.remove('menu-active');
burger.classList.remove('toggle');
menuLinks.forEach((link, index) => {
if (link.style.animation) {
link.style.animation = '';
} else {
link.style.animation = '';
}
});
}
menu.style.transition = '';
});
}
In my site I made a simple dropdown menu, but my problem is that it won't close if mouseleave happens on the <span> that triggers the dropdown.
Here is my code:
//Find the dropdown span
var header = document.getElementById('drop');
//Find the ul with the links
var ul = document.getElementById('nav-dropdown');
//Get the width and apply it to the dropdown items
var width = drop.getBoundingClientRect().width;
ul.style.minWidth = width + "px";
//Round the corners on the last link
var links = document.getElementsByClassName('dropdown-link');
links[links.length - 1].style.borderRadius = "0 0 7px 7px";
var open = 0;
//Onhover, display the dropdown;
header.addEventListener("mouseover", function() {
ul.style.display = "block";
header.style.borderRadius = "7px 7px 0 0";
if (links[0].getBoundingClientRect().width > width) {
links[0].style.borderRadius = "0 7px 0 0";
}
open = 1;
});
//When the mouse leaves the menu, close it.
ul.addEventListener("mouseleave", function() {
ul.style.display = "none";
header.style.borderRadius = "7px";
open = 0;
});
//What I've tried to fix it:
/*
header.addEventListener("mouseleave", function() {
ul.style.display = "none";
header.style.borderRadius = "7px";
});
*/
/*Stylesheet for this stuff*/
* {
font-family: arial;
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 20px;
text-decoration: none;
list-style: none;
}
a:visited {
color: white;
}
a,
#drop {
color: white;
}
a:hover {
color: coral;
}
.header-links-container {
position: relative;
top: 0;
background: rgb(63, 83, 95);
width: 100%;
height: 80px;
opacity: .8;
z-index: 999;
}
.title {
font-weight: bold;
font-size: 30px;
padding: 20px 50px;
position: relative;
float: left;
color: white;
}
.header-links {
position: relative;
float: right;
vertical-align: middle;
}
.nav-links {
margin: auto;
padding-top: 20px;
padding-right: 30px;
}
.nav-link {
position: relative;
float: right;
padding: 0 20px;
font-size: 23px;
padding: 5px 10px;
margin: 5px;
background: #4471ba;
border-radius: 7px;
}
.nav-link:hover {
background: #4480ba;
color: #d1d1d1;
}
#nav-dropdown {
display: none;
margin-top: 42px;
margin-left: 5px;
position: absolute;
}
.dropdown-link {
color: black;
background-color: #ccc;
padding: 5px 10px;
}
.dropdown-link:hover {
color: #000;
background-color: #a7a7a7;
}
.dropdown-link:active {
color: white;
background-color: #3b8cfa;
}
<div class="header-links-container">
<h2 class="title">Title</h2>
<div class="header-links">
<ul class="nav-links">
<li class="nav-link">Photo Gallery</li>
<li class="nav-link">SLAP</li>
<li id="drop" class="nav-link"><span>Dropdown</span></li>
<ul id="nav-dropdown" class="jim">
<a href="#">
<li class="dropdown-link">Link 1</li>
</a>
<a href="#">
<li class="dropdown-link">Link 2</li>
</a>
<a href="#">
<li class="dropdown-link">Longer Link</li>
</a>
<a href="#">
<li class="dropdown-link">Vacuum</li>
</a>
</ul>
</ul>
</div>
</div>
<p>
Relavent JS lines start at Line 16
</p>
And here is the fiddle that might make more sense: https://jsfiddle.net/dLw1hu5n/6/
I've tried closing the dropdown like in the last code block, but then it won't stay open when you go to hover over the links. I've also tried making the menu close when the mouse hovers over the navbar div, but no luck there either.
Can I fix this or do I need to start from square 1?
I would prefere to solve this via css. However, in your case you can try the following:
function displayDropdown() {
ul.style.display = "block";
header.style.borderRadius = "7px 7px 0 0";
if (links[0].getBoundingClientRect().width > width) {
links[0].style.borderRadius = "0 7px 0 0";
}
open = 1;
}
function hideDropdown() {
ul.style.display = "none";
header.style.borderRadius = "7px";
open = 0;
}
//Onhover, display the dropdown;
header.addEventListener("mouseover", function() {
displayDropdown();
});
ul.addEventListener("mouseover", function() {
displayDropdown();
});
//When the mouse leaves the menu, close it.
ul.addEventListener("mouseleave", function() {
hideDropdown();
});
header.addEventListener("mouseleave", function() {
hideDropdown();
});
Your JS is fine but your event listener for mouseleave needs to be on the enclosing div. This way your element stays open until you hover outside of the header
t.addEventListener("mouseleave", function() {
ul.style.display = "none";
header.style.borderRadius = "7px";
open = 0;
});
What is t?
var t = document.getElementById(t);
What element has id T?
Try this fiddle to find out https://jsfiddle.net/dLw1hu5n/12/
If a user, using iPhone (actual devices), lands on my website for the first time the "hamburger menu" will not open the menu at all, and navbar will not appear on scrolldown. It seems to be working just fine on Android devices (except maybe Nexus 4 in portrait mode if we were to believe responsinator ), and Win desktops.
The actual website's backend is made with Razor/ASP.NET but obviously I believe this is a pure frontend issue.
After a refresh it starts to work on Apple devices (well, iPhone) as well. And then sometimes stops working (once or twice it stopped working again, I believe).
Head (tried removing async and defer, did not work):
<script type="text/javascript" src="script.js" async defer></script>
Here is HTML (with bad usage of h2 tag with logo image in it):
<div id="navigation-main">
<h2 class="logo">
<a href="#">
<img src="images/white-logo.png" alt="">
</a>
</h2>
<div id="menu-icon">
<span class="icon-menu-hamburguer"></span>
</div>
<nav id="menu-main">
<ul>
<li><a class="scroll" href="#about-anchor">About us</a></li>
<li><a class="scroll" href="#agenda-anchor">Agenda</a></li>
<li><a class="scroll" href="#gallery-anchor">Gallery</a></li>
<li><a class="scroll" href="#sponsors-anchor">Sponsors</a></li>
<li><a class="scroll" href="#contact-anchor">Contact</a></li>
<li>Log in <img src="images/login_icon.png" alt=""></li>
</ul>
</nav>
CSS:
#navigation-main {
min-height: 60px;
z-index: 9;
overflow: hidden;
-webkit-transition: all 0.5s linear;
-moz-transition: all 0.5s linear;
-ms-transition: all 0.5s linear;
-o-transition: all 0.5s linear;
transition: all 0.5s linear;
}
#navigation-main:active {
background-color: #000000;
}
#navigation-main .logo {
float: left;
}
#navigation-main .logo img {
display: none;
}
#navigation-main nav {
position: relative;
top: 20px;
}
#navigation-main nav ul {
margin: 0;
padding-left: 0;
}
#navigation-main nav ul li {
list-style: none
}
#navigation-main nav ul li a {
color: #FFFFFF;
text-decoration: none
}
#navigation-main #menu-icon {
display: none;
}
#navigation-main.active {
background-color: rgb(0, 0, 0);
position: fixed;
top: 0;
height: 60px;
width: 100%;
margin-bottom: 0;
-webkit-transition: all 0.5s linear;
-moz-transition: all 0.5s linear;
-ms-transition: all 0.5s linear;
-o-transition: all 0.5s linear;
transition: all 0.5s linear;
}
#navigation-main.active img {
display: inline-block;
}
#navigation-main.active #menu-icon {
top: 10px;
}
#navigation-main.active .logo img {
max-width: 50%;
}
#navigation-main.active nav li a {
color: #FFFFFF
}
#navigation-main nav ul li img {
vertical-align: middle;
}
#media (max-width: 768px) {
#navigation-main .logo img {
max-width: 80%
}
#navigation-main #menu-icon {
padding: 18px 12px;
margin: 2px 0;
position: relative;
top: 20px;
display: block;
float: right;
z-index: 10;
cursor: pointer;
}
#navigation-main #menu-icon .icon-menu-hamburguer {
background: #ff0000;
width: 30px;
height: 4px;
margin: 2px 0;
display: block;
}
#navigation-main #menu-icon .icon-menu-hamburguer:after,
#navigation-main #menu-icon .icon-menu-hamburguer:before {
content: '';
background: #ff0000;
width: 30px;
height: 4px;
display: block;
margin: 2px 0;
position: relative;
}
#navigation-main #menu-icon .icon-menu-hamburguer:before {
bottom: 8px;
}
#navigation-main #menu-icon .icon-menu-hamburguer:after {
top: 2px;
}
#navigation-main nav {
display: none;
width: 100%;
}
#navigation-main nav.menu-active {
display: block;
clear: both;
height: 100%;
position: fixed;
z-index: 1;
left: 0;
top: 0;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.80);
overflow-x: hidden;
}
#navigation-main nav.menu-active ul {
position: relative;
top: 15%;
width: 100%;
text-align: center;
margin-top: 30px;
}
#navigation-main nav.menu-active a {
padding: 8px;
text-decoration: none;
font-size: 1.75rem;
display: block;
}
}
#media (min-width: 768px) {
#navigation-main nav {
float: right;
padding-right: 20px;
}
#navigation-main nav ul li,
#navigation-main nav ul li img {
display: inline-block;
}
#navigation-main nav ul li a {
padding: 0 5px;
font-size: 0.9rem;
}
}
Javascript:
(function() {
////////// Sticky navbar and hamburger icon
var headerScroll = getId('navigation-main'),
scrollHeight = 250,
menuIcon = getId('menu-icon'),
menuMain = getId('menu-main'),
classMenu = 'menu-active',
classHeader = 'active';
// Scroll
window.addEventListener("scroll", scrollOn);
function scrollOn() {
animatedScroll(headerScroll, classHeader, scrollHeight);
}
// Responsive menu
menuIcon.onclick = function() {
toggle(menuMain, classMenu);
}
menuMain.onclick = function() {
toggle(menuMain, classMenu);
}
// Moving the element after scrolling
function animatedScroll(element, classN, height) {
y = pageYOffset;
if (y > height) {
element.className = classN;
} else {
element.className = '';
}
}
// Change the element's class
function toggle(element, classe) {
element.className = element.className ? '' : classe;
}
// Return the element
function getId(id) {
return document.getElementById(id);
}
////////// Sticky navbar and hamburger icon
// Feature Test
if ('querySelector' in document && 'addEventListener' in window && Array.prototype.forEach) {
// Function to animate the scroll
var smoothScroll = function(anchor, duration) {
// Calculate how far and how fast to scroll
var startLocation = window.pageYOffset;
var endLocation = anchor.offsetTop;
var distance = endLocation - startLocation;
var increments = distance / (duration / 16);
var stopAnimation;
// Scroll the page by an increment, and check if it's time to stop
var animateScroll = function() {
window.scrollBy(0, increments);
stopAnimation();
};
// If scrolling down
if (increments >= 0) {
// Stop animation when you reach the anchor OR the bottom of the page
stopAnimation = function() {
var travelled = window.pageYOffset;
if ((travelled >= (endLocation - increments)) || ((window.innerHeight + travelled) >= document.body.offsetHeight)) {
clearInterval(runAnimation);
}
};
}
// If scrolling up
else {
// Stop animation when you reach the anchor OR the top of the page
stopAnimation = function() {
var travelled = window.pageYOffset;
if (travelled <= (endLocation || 0)) {
clearInterval(runAnimation);
}
};
}
// Loop the animation function
var runAnimation = setInterval(animateScroll, 16);
};
// Define smooth scroll links
var scrollToggle = document.querySelectorAll('.scroll');
// For each smooth scroll link
[].forEach.call(scrollToggle, function(toggle) {
// When the smooth scroll link is clicked
toggle.addEventListener('click', function(e) {
// Prevent the default link behavior
e.preventDefault();
// Get anchor link and calculate distance from the top
var dataID = toggle.getAttribute('href');
var dataTarget = document.querySelector(dataID);
var dataSpeed = toggle.getAttribute('data-speed');
// If the anchor exists
if (dataTarget) {
// Scroll to the anchor
smoothScroll(dataTarget, dataSpeed || 500);
}
}, false);
});
}
})();
And here is JSFiddle.
If it's touchstart/onclick issue why does it work after the refresh? Should I remove IFFE? Should I put script tag at the end of the page?
What seems to be the issue here?
Apparently the line in the header was an issue.I have removed "async" and the navigation menu started working.
<script type="text/javascript" src="script.js" async defer></script>
changed to:
<script type="text/javascript" src="script.js" defer></script>