Fixing the Mobile Double-Click Link Issue - javascript

Im setting up a onclick dropdown navigation bar for the mobile part of my website, The problem im having is when it takes a double click in order for it to drop down. The result I want is for it to drop down on the first click.
The only thing I've tried so far is a Javascript function that I will show in my code.
function myFunction() {
var x = document.getElementById("submenu1");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
function myFunction_2() {
var y = document.getElementById("submenu2");
if (y.style.display === "none") {
y.style.display = "block";
} else {
y.style.display = "none";
}
}
.main-nav {
display: flex;
}
.main-nav ul {
display: flex;
flex-wrap: wrap;
flex: 1;
list-style: none;
}
.main-nav li {
text-align: center;
position: relative;
width: 100%;
border-bottom: 1px solid white;
}
#submenu1 .submenu1-li:first-of-type {
border-top: 1px solid white;
}
.main-nav a {
display: flex;
display: block;
align-items: center;
justify-content: center;
flex: 1;
color: #fff;
background-color: #000;
padding: 5% 0%;
}
.submenu1-li {
position: absolute;
top: 0px;
}
#submenu1 {
display: none;
flex-direction: column;
position: absolute;
width: 100%;
}
.submenu2-li {
position: absolute;
top: 0px;
}
#submenu2 {
display: none;
flex-direction: column;
position: absolute;
width: 100%;
}
#submenu2 .submenu2-li:first-of-type {
border-top: 1px solid white;
}
#active {
background-color: #ffffff;
color: #000000;
height: 100%;
}
#submenu1 a:hover {
color: black;
background-color: white;
}
#desktop-port-move:hover #submenu2 {
display: block;
}
<nav class="main-nav">
<ul>
<li>
<a id="hide" href="javascript:void(0)" onclick="myFunction()">Menu
<span class="arrow">▼</span>
</a>
<ul id="submenu1">
<li class="submenu1-li">
<a id="active" href="home.html">Home</a>
</li>
<li class="submenu1-li">
About
</li>
<li id="desktop-contact-move" class="submenu1-li" >
Contact
</li>
<li id="desktop-port-move" class="submenu1-li" style:"order: 1;">
<a href="javascript:void(0)" onclick="myFunction_2();">Portfolio
<span class="arrow">▼</span>
</a>
<ul id="submenu2">
<li class="submenu2-li">
Designs
</li>
<li class="submenu2-li">
Websites
</li>
<li class="submenu2-li">
Photography
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
I expect the output to be a dropdown menu that responds on first click.
but the output im getting is a dropdown menu that responds on the second click, which is wrong for what I want.
Thanks in advance
and blessings to those who help

The reason it's not showing on the first click is that this condition
if (x.style.display === "none")
is false since you've set display: none; in CSS stylesheet. So a really quick way to fix this would be to add display: none; inline:
<ul id="submenu1" style="display:none;">
But a cleaner way would be to use classes to control menu visibility. See the snippet below.
function myFunction() {
var x = document.getElementById("submenu1");
x.classList.toggle('hidden');
}
.main-nav {
display: flex;
}
.main-nav ul {
display: flex;
flex-wrap: wrap;
flex: 1;
list-style: none;
}
.main-nav li {
text-align: center;
position: relative;
width: 100%;
border-bottom: 1px solid white;
}
#submenu1 .submenu1-li:first-of-type {
border-top: 1px solid white;
}
.main-nav a {
display: flex;
display: block;
align-items: center;
justify-content: center;
flex: 1;
color: #fff;
background-color: #000;
padding: 5% 0%;
}
.submenu1-li {
position: absolute;
top: 0px;
}
#submenu1 {
flex-direction: column;
position: absolute;
width: 100%;
}
#submenu1.hidden {
display: none;
}
.submenu2-li {
position: absolute;
top: 0px;
}
#submenu2 {
display: none;
flex-direction: column;
position: absolute;
width: 100%;
}
#submenu2 .submenu2-li:first-of-type {
border-top: 1px solid white;
}
#active {
background-color: #ffffff;
color: #000000;
height: 100%;
}
#submenu1 a:hover {
color: black;
background-color: white;
}
#desktop-port-move:hover #submenu2 {
display: block;
}
<nav class="main-nav">
<ul>
<li>
<a id="hide" href="javascript:void(0)" onclick="myFunction()">Menu
<span class="arrow">▼</span>
</a>
<ul id="submenu1" class="hidden">
<li class="submenu1-li">
<a id="active" href="home.html">Home</a>
</li>
<li class="submenu1-li">
About
</li>
<li id="desktop-contact-move" class="submenu1-li" >
Contact
</li>
<li id="desktop-port-move" class="submenu1-li" style:"order: 1;">
<a href="javascript:void(0)" onclick="myFunction_2();">Portfolio
<span class="arrow">▼</span>
</a>
<ul id="submenu2">
<li class="submenu2-li">
Designs
</li>
<li class="submenu2-li">
Websites
</li>
<li class="submenu2-li">
Photography
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>

Ok so here the problem is that the x.style.display returns blank string because that property is defined in stylesheet.
1st solution is to use inline css
2nd is apply another check for blank string like this.
function myFunction() {
var x = document.getElementById("submenu1");
if (x.style.display === "none" || x.style.display === "") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
function myFunction_2() {
var y = document.getElementById("submenu2");
if (y.style.display === "none" || y.style.display === "") {
y.style.display = "block";
} else {
y.style.display = "none";
}
}
.main-nav {
display: flex;
}
.main-nav ul {
display: flex;
flex-wrap: wrap;
flex: 1;
list-style: none;
}
.main-nav li {
text-align: center;
position: relative;
width: 100%;
border-bottom: 1px solid white;
}
#submenu1 .submenu1-li:first-of-type {
border-top: 1px solid white;
}
.main-nav a {
display: flex;
display: block;
align-items: center;
justify-content: center;
flex: 1;
color: #fff;
background-color: #000;
padding: 5% 0%;
}
.submenu1-li {
position: absolute;
top: 0px;
}
#submenu1 {
display: none;
flex-direction: column;
position: absolute;
width: 100%;
}
.submenu2-li {
position: absolute;
top: 0px;
}
#submenu2 {
display: none;
flex-direction: column;
position: absolute;
width: 100%;
}
#submenu2 .submenu2-li:first-of-type {
border-top: 1px solid white;
}
#active {
background-color: #ffffff;
color: #000000;
height: 100%;
}
#submenu1 a:hover {
color: black;
background-color: white;
}
#desktop-port-move:hover #submenu2 {
display: block;
}
<nav class="main-nav">
<ul>
<li>
<a id="hide" href="javascript:void(0)" onclick="myFunction()">Menu
<span class="arrow">▼</span>
</a>
<ul id="submenu1">
<li class="submenu1-li">
<a id="active" href="home.html">Home</a>
</li>
<li class="submenu1-li">
About
</li>
<li id="desktop-contact-move" class="submenu1-li" >
Contact
</li>
<li id="desktop-port-move" class="submenu1-li" style:"order: 1;">
<a href="javascript:void(0)" onclick="myFunction_2();">Portfolio
<span class="arrow">▼</span>
</a>
<ul id="submenu2">
<li class="submenu2-li">
Designs
</li>
<li class="submenu2-li">
Websites
</li>
<li class="submenu2-li">
Photography
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
More information about the problem at : Fixing the Mobile Double-Click Link Issue

Related

HTML drop-down menu with icons and text

I have taken over the code from this post. As I have explained there, I have basically no HTML knowledge, yet I have this HTML part of my project that I have to finish.
So, the code creates a bar with a drop-down menu, but I want to extend it to have an icon next to the names. I have looked at these examples but I can't figure out how to combine them. Is there someone who could help?
const projectsTab = document.getElementById('projects')
const tabName = projectsTab.querySelector('.tab-name')
const projectLinks = document.querySelector('.project-links')
projectsTab.addEventListener('click', e => {
const isOpen = projectLinks.classList.contains('open')
if (isOpen) projectLinks.classList.remove('open')
else projectLinks.classList.add('open')
})
// link event listeners
const links = [...projectLinks.children] // turn this into an array
links.forEach(link => link.addEventListener('click', e => {
tabName.innerText = link.innerText
}))
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: 'Segoe UI', sans-serif;
}
nav {
position: fixed;
width: 100%;
height: 50px;
background: #222;
top: 0;
left: 0;
color: white;
display: flex;
}
nav>* {
flex: 1;
}
#logo {
padding-left: 20px;
font-size: 30px;
text-transform: uppercase;
letter-spacing: 2px;
display: flex;
justify-content: flex-start;
align-items: center;
}
nav ul {
display: flex;
list-style: none;
height: 100%;
}
nav ul li {
position: relative;
flex: 1;
background: #222;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: 0.2s;
}
nav ul li:hover {
background: #555;
}
.project-links {
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
left: 0;
top: 100%;
width: 100%;
background-color: white;
color: black;
/* This is the height of this div + height of the nav bar */
transform: translateY(-135%);
transition: 0.2s;
z-index: -1;
}
.project-links.open {
transform: translateY(0);
}
.project-link {
height: 50px;
display: flex;
align-items: center;
padding-left: 20px;
text-decoration: none;
color: white;
cursor: pointer;
transition: 0.2s;
background: #222;
color: white;
}
.project-link:hover {
background: #555;
}
<nav>
<div id="logo">Logo</div>
<ul>
<li>About</li>
<li id="projects">
<span class="tab-name">Projects</span>
<div class="project-links">
<a class="project-link" href="#">Link 1</a>
<a class="project-link" href="#">Link 2</a>
<a class="project-link" href="#">Link 3</a>
</div>
</li>
<li>Contact</li>
</ul>
</nav>
Assuming you want to use Font Awesome icons, just add the proper i tag referencing the right icon beside the text in the corresponding a tags.
const projectsTab = document.getElementById('projects')
const tabName = projectsTab.querySelector('.tab-name')
const projectLinks = document.querySelector('.project-links')
projectsTab.addEventListener('click', e => {
const isOpen = projectLinks.classList.contains('open')
if (isOpen) projectLinks.classList.remove('open')
else projectLinks.classList.add('open')
})
// link event listeners
const links = [...projectLinks.children] // turn this into an array
links.forEach(link => link.addEventListener('click', e => {
tabName.innerText = link.innerText
}))
document.addEventListener("click", e => {
if(!projectsTab.contains(e.target)){
projectLinks.classList.remove("open");
}
})
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: 'Segoe UI', sans-serif;
}
nav {
position: fixed;
width: 100%;
height: 50px;
background: #222;
top: 0;
left: 0;
color: white;
display: flex;
}
nav>* {
flex: 1;
}
#logo {
padding-left: 20px;
font-size: 30px;
text-transform: uppercase;
letter-spacing: 2px;
display: flex;
justify-content: flex-start;
align-items: center;
}
nav ul {
display: flex;
list-style: none;
height: 100%;
}
nav ul li {
position: relative;
flex: 1;
background: #222;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: 0.2s;
}
nav ul li:hover {
background: #555;
}
.project-links {
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
left: 0;
top: 100%;
width: 100%;
background-color: white;
color: black;
/* This is the height of this div + height of the nav bar */
transform: translateY(-135%);
transition: 0.2s;
z-index: -1;
}
.project-links.open {
transform: translateY(0);
}
.project-link {
height: 50px;
display: flex;
align-items: center;
padding-left: 20px;
text-decoration: none;
color: white;
cursor: pointer;
transition: 0.2s;
background: #222;
color: white;
}
.project-link:hover {
background: #555;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<nav>
<div id="logo">Logo</div>
<ul>
<li>About</li>
<li id="projects">
<span class="tab-name">Projects</span>
<div class="project-links">
<a class="project-link" href="#"><i class="fa fa-envelope"></i> Link 1</a>
<a class="project-link" href="#"><i class="fa fa-envelope"></i> Link 2</a>
<a class="project-link" href="#"><i class="fa fa-envelope"></i> Link 3</a>
</div>
</li>
<li>Contact</li>
</ul>
</nav>
To close the dropdown when the user clicks elsewhere, add an event listener for click and check whether the target is a subchild of projectsTab.
Since your dropdown menu elements are already flex containers, you can simply add an image at the beginning of each of them, give them a class (icon) and change a bit the padding. Here I put icon { padding: 3px; } and I removed the 20px padding at the beginning of menu elements, because it squished the images against the text.
I also added some JavaScript to close the menu when you click elsewhere.
const projectsTab = document.getElementById('projects')
const tabName = projectsTab.querySelector('.tab-name')
const projectLinks = document.querySelector('.project-links')
projectsTab.addEventListener('click', e => {
const isOpen = projectLinks.classList.contains('open')
if (isOpen) projectLinks.classList.remove('open')
else projectLinks.classList.add('open')
})
addEventListener('click', e => {
var target = e.target;
if (!(target.classList.contains('project-link') || target.classList.contains('project-link') || target.classList.contains('tab-name') || target.id == "projects")) {
projectLinks.classList.remove('open');
} else {
e.stopPropagation();
}
});
// link event listeners
const links = [...projectLinks.children] // turn this into an array
links.forEach(link => link.addEventListener('click', e => {
tabName.innerText = link.innerText
}))
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: 'Segoe UI', sans-serif;
}
nav {
position: fixed;
width: 100%;
height: 50px;
background: #222;
top: 0;
left: 0;
color: white;
display: flex;
}
nav>* {
flex: 1;
}
#logo {
padding-left: 20px;
font-size: 30px;
text-transform: uppercase;
letter-spacing: 2px;
display: flex;
justify-content: flex-start;
align-items: center;
}
nav ul {
display: flex;
list-style: none;
height: 100%;
}
nav ul li {
position: relative;
flex: 1;
background: #222;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: 0.2s;
}
nav ul li:hover {
background: #555;
}
.project-links {
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
left: 0;
top: 100%;
width: 100%;
background-color: white;
color: black;
/* This is the height of this div + height of the nav bar */
transform: translateY(-135%);
transition: 0.2s;
z-index: -1;
}
.project-links.open {
transform: translateY(0);
}
.project-link {
height: 50px;
display: flex;
align-items: center;
padding-left: 5px;
text-decoration: none;
color: white;
cursor: pointer;
transition: 0.2s;
background: #222;
color: white;
}
.project-link:hover {
background: #555;
}
.icon {
padding-right: 3px;
}
<nav>
<div id="logo">Logo</div>
<ul>
<li>About</li>
<li id="projects">
<span class="tab-name">Projects</span>
<div class="project-links">
<a class="project-link" href="#"><img class="icon" src="http://lorempixel.com/20/20/cats/">Link 1</a>
<a class="project-link" href="#"><img class="icon" src="http://lorempixel.com/20/20/cats/">Link 2</a>
<a class="project-link" href="#"><img class="icon" src="http://lorempixel.com/20/20/cats/">Link 3</a>
</div>
</li>
<li>Contact</li>
</ul>
</nav>
This is actually pretty easy just like the example you linked to first add the link to the icon library inside the <head></head> tag of your html:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
then add the <i/> tag inside the <a></a> tag of your drop down. Your html code should look like so
<nav>
<div id="logo">Logo</div>
<ul>
<li>About</li>
<li id="projects">
<span class="tab-name">Projects</span>
<div class="project-links">
<a class="project-link" href="#"><i class="fa fa-home"/>Link 1</a>
<a class="project-link" href="#"><i class="fa fa-search"/>Link 2</a>
<a class="project-link" href="#"><i class="fa fa-globe"/>Link 3</a>
</div>
</li>
<li>Contact</li>
</ul>
</nav>

How to make dropdown menu onclick and close when clicking outside element with Vanilla javascript only?

I'm trying to make dropdown menu onlick and close its menu when clicking outside element.
When i clicked on the News element it doesn't show anything.
I would like it to show when it's clicked and close it's menu when clicking anywhere.
function dropDownMenu() {
var btnNavNews = document.querySelector('.nav__news');
var dropNewSub = document.querySelector('.nav__news__sub');
btnNavNews.addEventListener('click', function () {
dropNewSub.classList.toggle('show');
})
document.addEventListener('click', function (e) {
if (e.target != btnNavNews && e.target.parentNode != dropNewSub) {
dropNewSub.classList.remove('show');
}
})
}
dropDownMenu();
/*Block*/
.nav li {
display: inline-block;
list-style: none;
color: black;
width: 100px;
height: auto;
border: 1px solid red;
font-size: 20px;
text-align: center;
}
/*Element*/
.nav__news__sub {
display: none;
width: 100%;
}
.nav__news__sub__ul {
display: flex;
position: absolute;
width: 70%;
height: 50%;
padding-bottom: 2%;
margin-top: 1%;
padding-right: 2%;
align-items: center;
justify-content: space-evenly;
background-color: grey;
}
.nav__news__sub__ul li {
width: 30%;
height: 50%;
margin-bottom: 10%;
}
.nav__content {
border: solid 1px blue;
margin-top: 50%;
}
.show {
display: block;
}
.nav__item a {
display: block;
}
.nav__item li {
text-align: left;
}
<html>
<head>
<link rel="stylesheet" href="index.css">
<script src="index.js" defer></script>
</head>
<body>
<ul class="nav">
<li Home</li>
<li class="nav__news" News
<div class="nav__news__sub">
<ul class="nav__news__sub__ul">
<li class="img" Example
<div class="nav__content">
<h1>Topic</h1>
</div>
</li>
<li Example2</li>
<li Example3</li>
</ul>
</div>
</li>
</ul>
</body>
</html</html>
Update my code is now works fine, i used wrong variable and change toggle method to remove method
You just used a wrong variable. You should use btnNavNews instead.
Although fixed, I think this logic is still wrong as it will toggle the dropdown if you click anywhere.
function dropDownMenu() {
var btnNavNews = document.querySelector('.nav__news');
var dropNewSub = document.querySelector('.nav__news__sub');
btnNavNews.addEventListener('click', function() {
dropNewSub.classList.toggle('show');
})
document.addEventListener('click', function(e) {
if (e.target != btnNavNews && e.target.parentNode != btnNavNews) {
dropNewSub.classList.toggle('show');
}
})
}
dropDownMenu();
/*Block*/
.nav li {
display: inline-block;
list-style: none;
color: black;
width: 100px;
height: auto;
border: 1px solid red;
font-size: 20px;
text-align: center;
}
/*Element*/
.nav__news__sub {
display: none;
width: 100%;
}
.nav__news__sub__ul {
display: flex;
position: absolute;
width: 70%;
height: 50%;
padding-bottom: 2%;
margin-top: 1%;
padding-right: 2%;
align-items: center;
justify-content: space-evenly;
background-color: grey;
}
.nav__news__sub__ul li {
width: 30%;
height: 50%;
margin-bottom: 10%;
}
.nav__content {
border: solid 1px blue;
margin-top: 50%;
}
.show {
display: block;
}
.nav__item a {
display: block;
}
.nav__item li {
text-align: left;
}
<ul class="nav">
<li Home
</li>
<li class="nav__news" News
<div class="nav__news__sub">
<ul class="nav__news__sub__ul">
<li class="img" Example
<div class="nav__content">
<h1>Topic</h1>
</div>
</li>
<li Example2
</li>
<li Example3
</li>
</ul>
</div>
</li>
</ul>
I suggest you use remove instead so that the dropdown will be hidden when you click anywhere else other than the "News" button:
function dropDownMenu() {
var btnNavNews = document.querySelector('.nav__news');
var dropNewSub = document.querySelector('.nav__news__sub');
btnNavNews.addEventListener('click', function() {
dropNewSub.classList.toggle('show');
})
document.addEventListener('click', function(e) {
if (e.target != btnNavNews && e.target.parentNode != btnNavNews) {
dropNewSub.classList.remove('show');
}
})
}
dropDownMenu();
/*Block*/
.nav li {
display: inline-block;
list-style: none;
color: black;
width: 100px;
height: auto;
border: 1px solid red;
font-size: 20px;
text-align: center;
}
/*Element*/
.nav__news__sub {
display: none;
width: 100%;
}
.nav__news__sub__ul {
display: flex;
position: absolute;
width: 70%;
height: 50%;
padding-bottom: 2%;
margin-top: 1%;
padding-right: 2%;
align-items: center;
justify-content: space-evenly;
background-color: grey;
}
.nav__news__sub__ul li {
width: 30%;
height: 50%;
margin-bottom: 10%;
}
.nav__content {
border: solid 1px blue;
margin-top: 50%;
}
.show {
display: block;
}
.nav__item a {
display: block;
}
.nav__item li {
text-align: left;
}
<ul class="nav">
<li Home
</li>
<li class="nav__news" News
<div class="nav__news__sub">
<ul class="nav__news__sub__ul">
<li class="img" Example
<div class="nav__content">
<h1>Topic</h1>
</div>
</li>
<li Example2
</li>
<li Example3
</li>
</ul>
</div>
</li>
</ul>

How do I hide an element on resize?

I'm trying to hide a mobile nav menu when the user resizes the screen past a certain point (767px). I thought this would be fairly straight-forward, but I can't get it to work. Any suggestions?
ps My constrainNav function is being called in the body tag (not shown).
// Toggle between hamburger and full mobile menu //
const nav = document.getElementById("mobile-nav");
const hamburger = document.getElementById("hamburger");
const width = window.innerWidth;
function navToggle() {
if (nav.style.display === "") {
nav.style.display = "block";
} else {
nav.style.display = "";
}
}
// Keep mobile-nav visible only when 767px or less
function constrainNav() {
if (nav && width > 767) {
nav.style.display = "none";
}
}
<nav class="nav">
<div id="navbar" class="nav__navbar"">
<div class="nav__left">
<img src="src/assets/img/Grieve-logo.png" class="nav__img" alt="grieve logo">
</div>
<div class="nav__right">
<ul class="nav__list">
<li class="nav__list-item"><a class="nav__list__link" href="#">Wines</a></li>
<li class="nav__list-item"><a class="nav__list__link" href="#">Vineyard</a></li>
<li class="nav__list-item"><a class="nav__list__link" href="#">About</a></li>
<li class="nav__list-item"><a class="nav__list__link" href="#">Winemaker</a></li>
<li class="nav__list-item"><a class="nav__list__link" href="#">Visit</a></li>
<li class="nav__list-item"><a class="nav__list__link" href="#">Buy</a></li>
</ul>
<i class="fa fa-bars"></i>
</div>
<div class="nav__navbar nav__navbar--mobile" id="mobile-nav">
<div class="nav__left nav__left--mobile">
<img src="src/assets/img/XXXXXX-logo.png" class="nav__img" alt="XXXXX logo">
<i class="fa fa-bars"></i>
</div>
<ul class="nav__list--mobile">
<li class="nav__list__item--mobile"><a class="nav__list__link--mobile" href="#">Wines</a></li>
<li class="nav__list__item--mobile"><a class="nav__list__link--mobile" href="#">Vineyard</a></li>
<li class="nav__list__item--mobile"><a class="nav__list__link--mobile" href="#">About</a></li>
<li class="nav__list__item--mobile"><a class="nav__list__link--mobile" href="#">Winemaker</a></li>
<li class="nav__list__item--mobile"><a class="nav__list__link--mobile" href="#">Visit</a></li>
<li class="nav__list__item--mobile"><a class="nav__list__link--mobile" href="#">Buy</a></li>
</ul>
</div>
</div>
</nav>
.nav {
position: sticky; // * curious to see how this works once we get to browser testing.
top: 0;
margin-top: -3px; // * necessary maybe? Not sure how to get rid of that small gap above the nav.
height: 100%;
&__navbar {
width: 100%;
overflow: hidden;
height: 3rem;
background-color: $colorPrimary;
display: flex;
justify-content: space-between;
padding: 0 1.5rem;
align-items: center;
&--mobile {
display: none;
position: absolute;
top: -17.625rem;
left: 0;
background-color: $colorSecondary;
max-width: 100%;
height: auto;
}
}
&__left {
color: $colorWhite;
margin: 0.75rem 0 0 0;
&--mobile {
display: flex;
justify-content: space-between;
}
}
&__img {
width: 5.625rem;
}
&__right {
margin: 0;
}
&__hamburger {
display: none;
color: $colorWhite;
margin: 0;
#include respond(med) {
display: block;
}
}
&__list {
list-style: none;
display: flex;
text-transform: uppercase;
justify-content: center;
#include respond(med) {
display: none;
}
&--mobile {
display: flex;
flex-direction: column;
list-style: none;
padding: 8rem 0;
align-items: center;
}
&__link {
text-decoration: none;
color: $colorWhite;
cursor: pointer;
text-transform: uppercase;
font-size: 1rem;
margin: 0 1rem;
#media (max-width: 40.625rem) {
margin: 0 0.5rem;
}
&--mobile {
text-decoration: none;
color: $colorWhite;
cursor: pointer;
text-transform: uppercase;
font-size: 1rem;
margin: 0 1rem;
#include respond(med) {
font-size: 2rem;
}
}
}
&__item {
&--mobile {
padding: 2rem;
}
}
}
}
I think this should be enough code. I can provide more. Thanks!
use css media query, in this case you dont need javascript.
#media screen and (min-width: 767px) {
.nav {
display: none
}
}

Element width to match horizontal position of other element

Let's say we have a navigation div which contains elements. Below navigation div there is some bar that must expand to the width where it matches one of the navigation elements (3rd one in this case).
<div id="main_navigator">
<div id="main_navigator_upper">
<a id="main_navigator_logo" src="/"></a>
<ul id="main_navigator_r1">
<li>
<a class="main_nav_btn">BTN 1</a>
</li>
<li>
<a class="main_nav_btn">BTN 2</a>
</li>
<li>
<a class="main_nav_btn">BTN 3</a>
</li>
<li>
<a class="main_nav_btn">BTN 4</a>
</li>
<li id="main_navigator_l1">
<div id="main_navigator_s1"></div>
</li>
<li>
<ul id="main_navigator_regbox">
<li>
<p id="regbox_signin">sign in</p>
</li>
<li>
<div id="main_navigator_regbox_s1"></div>
</li>
<li>
<a id="regbox_signup" href="sign_up">sign up</a>
</li>
</ul>
</li>
</ul>
</div>
<div id="main_navigator_bottom">
<div id="main_navigator_progression"></div>
</div>
</div>
From this code, main_navigator_progression div must expand its width so it matches BTN 3.
You can see the concept here.
I've written a simple JS code, but it doesn't seem to be neat and doesn't always work:
function initializeProgressorPos() {
document.getElementById("main_navigator_progression").setAttribute("style", ("width: " + (document.getElementsByClassName("main_nav_btn")[2].getBoundingClientRect().x - document.getElementsByClassName("main_nav_btn")[2].getBoundingClientRect().width) + "px"))
}
initializeProgressorPos();
$(window).resize(function() {
initializeProgressorPos();
});
Is there any way to create such a function that works even when browser is scaled? What could be wrong with my code? Is there any chance that this can be done with pure css?
As you have floatted the element to the right, first you have to get the width of document, then exclude the width from left of document to the right of element from that amount:
function initializeProgressorPos() {
var elementRight=$(document).width()- $('.main_nav_btn:eq(2)').offset().left - $('.main_nav_btn:eq(2)').width();
$("#main_navigator_progression").css({"width": elementRight + "px"});
}
initializeProgressorPos();
$(window).resize(function() {
initializeProgressorPos();
});
body {
margin: 0;
overflow-y: scroll;
}
#main_navigator {
position: fixed;
background-color: black;
width: 100%;
}
#main_navigator_upper {
position: relative;
display: flex;
flex-direction: row;
}
#main_navigator_logo {
width: 416px;
height: 120px;
background-color: white;
}
#main_navigator_r1 {
display: flex;
flex-direction: row;
align-items: center;
flex-grow: 1;
flex-shrink: 1;
padding: 0;
padding-right: 5%;
text-align: center;
margin-top: 0px;
height: 98px;
list-style-type: none;
}
#main_navigator_r1 li {
flex-grow: 1;
flex-shrink: 1;
/* flex-basis: 0; */
flex-basis: auto; /* new */
}
#main_navigator_l1 {
flex-grow: 0.1 !important;
}
#main_navigator_r1 li .main_nav_btn {
color: white;
display: block;
height: 100%;
font-family: "nexa_bold";
font-size: 0.9em;
text-decoration: none;
}
#main_navigator_s1 {
display: inline-block;
width: 2px;
height: 35px;
background-color: #B28039;
}
#main_navigator_regbox {
position: relative;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
list-style-type: none;
margin: 0px;
padding: 0px;
}
#main_navigator_regbox li {
display: inline-block;
flex-grow: 0.1;
flex-shrink: 0.1;
}
#regbox_signin {
display: block;
cursor: pointer;
white-space: nowrap;
text-decoration: none;
color: #B28039;
font-size: 0.9em;
font-family: "nexa_light";
}
#regbox_signup {
display: block;
white-space: nowrap;
text-decoration: none;
color: white;
font-size: 0.9em;
font-family: "nexa_light";
}
#main_navigator_regbox_s1 {
display: inline-block;
width: 1.4px;
height: 13.5px;
background-color: white;
}
#main_navigator_bottom {
background-color: black;
height: 24px;
}
#main_navigator_progression {
position: relative;
background-color: #B28039;
height: 100%;
width: 416px;
float: right;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<body>
<div id="main_navigator">
<div id="main_navigator_upper">
<a id="main_navigator_logo" src="/"></a>
<ul id="main_navigator_r1">
<li>
<a class="main_nav_btn">BTN 1</a>
</li>
<li>
<a class="main_nav_btn">BTN 2</a>
</li>
<li>
<a class="main_nav_btn">BTN 3</a>
</li>
<li>
<a class="main_nav_btn">BTN 4</a>
</li>
<li id="main_navigator_l1">
<div id="main_navigator_s1"></div>
</li>
<li>
<ul id="main_navigator_regbox">
<li>
<p id="regbox_signin">sign in</p>
</li>
<li>
<div id="main_navigator_regbox_s1"></div>
</li>
<li>
<a id="regbox_signup" href="sign_up">sign up</a>
</li>
</ul>
</li>
</ul>
</div>
<div id="main_navigator_bottom">
<div id="main_navigator_progression"></div>
</div>
</div>
</body>
</html>
This is a proof of concept.
You can use a combination of a custom HTML5 data-* attribute and an ::after pseudo-element on your navigation menu (and a dash of javascript) to indicate which menu item you have most recently selected.
Despite the dash of javascript, most of the work is done using CSS.
Working Example:
var menu = document.querySelector('nav ul');
var menuItems = [... menu.getElementsByTagName('li')];
function selectMenu() {
menu.dataset.selectedMenu = (menuItems.indexOf(this) + 1);
}
for (var i = 0; i < menuItems.length; i++) {
menuItems[i].addEventListener('click', selectMenu, false);
}
nav ul {
display: flex;
position: relative;
margin: 0;
padding: 0;
}
nav li {
flex: 0 0 60px;
padding: 12px 12px 24px;
color: rgb(255, 255, 255);
background-color: rgb(255, 0, 0);
list-style-type: none;
cursor: pointer;
}
nav ul::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
height: 12px;
background-color: rgba(0, 0, 0, 0.5);
transition: width 0.6s linear;
}
nav ul[data-selected-menu="1"]::after {
width: 80px;
}
nav ul[data-selected-menu="2"]::after {
width: 160px;
}
nav ul[data-selected-menu="3"]::after {
width: 240px;
}
nav ul[data-selected-menu="4"]::after {
width: 320px;
}
nav ul[data-selected-menu="5"]::after {
width: 400px;
}
<nav>
<ul data-selected-menu="1">
<li class="active">Menu 1</li>
<li>Menu 2</li>
<li>Menu 3</li>
<li>Menu 4</li>
<li>Menu 5</li>
</ul>
</nav>

Submenu doesn't render correctly on screen resize (and unexpected behaviour)

I have 5 links on my vertical nav. On screen resize my vertical nav becomes a horizontal nav with three (of those 5 links) showing and another link called menu which displays the other two remaining links.
For some reason, on screen resize, when menu appears, the list content is already displayed and then when menu is clicked, it leaves the hover properties even when you're not hovering over it. Here are visuals:
1. On screen resize, it appears like this:
2. When hovering over menu:
Which is OK. I only want the links to appear when the menu link is clicked, not hovered over. But I do not understand why menu talking up two li spaces.
3. When clicking menu:
This is OK. However, note how the Menu li is now perfectly sized.
4. After clicking on menu and then moving the mouse away from the link:
As mentioned, I do not know what's causing these issues.
Here is my current approach:
$(document).ready(function() {
$(".show").click(function() {
$(".subMenu").toggleClass("active");
return false;
});
});
.site-wrapper {
height: 100%;
min-height: 100%;
display: flex;
}
/* make divs appear below each other on screen resize */
#media screen and (max-width: 540px) {
.site-wrapper {
flex-direction: column;
}
}
ul.subMenu {
display: none;
}
.subMenu.active {
display: flex;
flex-direction: column;
}
li.show {
display: none;
}
.nav-container {
border-right: 1px solid #E4E2E2;
height: 100%;
width: 200px;
background-color: #f4f3f3;
}
.logo-holder {
text-align: center;
}
.nav {
text-align: justify;
}
nav:after {
content: "";
display: table;
clear: both;
}
.nav-link {
display: block;
text-align: left;
color: #333;
text-decoration: none;
margin-left: 0px;
padding-left: 15px;
}
.nav-link:hover {
background-color: #333;
color: #f4f3f3;
}
.nav ul {
width: 100%;
/* make div span div */
padding: 0px;
}
.nav ul li {
list-style-type: none;
}
.nav li:hover a {
color: #f4f3f3;
}
.active {
text-align: left;
padding-left: 15px;
text-decoration: none;
background-color: #333;
color: #f4f3f3;
}
#media screen and (max-width: 540px) {
.nav-container {
width: 100%;
height: 100px;
background-color: #f4f3f3;
border-bottom: 0.5px solid #f4f3f3;
}
.nav-link {
padding: 10px;
}
.logo-holder {
overflow: hidden;
display: block;
margin: auto;
width: 40%;
}
.nav-container nav ul {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.logo-holder {
text-align: left;
}
#navigation-div {
background-color: #f4f3f3;
margin-top: 0;
}
.socials {
display: none;
}
.hide {
display: none;
}
.show {
display: inline-block !important;
}
.nav ul li {}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="site-wrapper">
<div class="nav-container">
<div class="logo-holder">
<img class="user-select-none" src="images/temp-logo.jpeg" alt="temp" />
</div>
<div id="navigation-div">
<nav class="nav">
<ul>
<li><a class="nav-link active" href="">Test 1</a></li>
<li><a class="nav-link " href="">Test 2</a></li>
<li><a class="nav-link" href="">Test 3</a></li>
<li class="hide"><a class="nav-link hide" href="">Test 4</a></li>
<li class="hide"><a class="nav-link hide" href="">Test 5</a></li>
<li class="show"><a class="nav-link" href="">Menu</a>
<ul class="subMenu">
<li><a class="nav-link" href="">Test 4</a></li>
<li><a class="nav-link" href="">Test 5</a></li>
</ul>
</li>
</ul>
</nav>
</div>
</div>
</div>
Explanation:
You have so many things messed up. Most important to note is that sub elements are inheriting from main elements. For example, if we have the following HTML:
<ul id="main_menu">
<li>list item 1</li>
<li>list item 2</li>
<li>
<ul id="sub_menu">
<li>sub list item 1</li>
</ul>
</li>
</ul>
And this CSS:
#main_menu li {/* This styling will also be applied to sub_menu!! */
color: red;
}
So if you want to apply to only direct li under main menu, use > which means only direct elements, like so:
#main_menu > li {/* This styling will be applied only to direct li, sub_menu li will not take this styling */
color: red;
}
Fixing the problem:
1- Add !important to sub menu:
ul.subMenu {
display: none !important;
}
2- Comment or remove this line:
.nav li:hover a {
/* color: #f4f3f3; */
}
3- Your sub menu is inheriting some unwanted styling from the main menu. Add these should fix it for you:
.subMenu a.nav-link {
background-color: #f4f3f3;
color: #333;
}
.subMenu a.nav-link:hover {
background-color: #333;
color: #f4f3f3;
}
.subMenu.active {
display: block !important;
}
Here's a demo.
For some reason, on screen resize, when menu appears, the list content is already displayed
You can use jQuery's resize function to do stuff when you resize.
But I do not understand why menu talking up two li spaces.
Menu is taking up two li spaces because it contains a ul that is two spaces wide which is forcing it's width.
Adding a width to the anchor tag will make it look a little better as it won't inherit the width from the li.
a.nav-link { width: 50px;}
After clicking on menu and then moving the mouse away from the link.
Add a class to the parent of the submenu using jQuery so you can control styling.
Here's the code, hope it helps!
jQuery
$(document).ready(function() {
$(".subMenu").addClass('hide');
$(".show").click(function() {
$(".show").toggleClass('active-parent');
$(".subMenu").toggleClass("active");
$(".subMenu").toggleClass("hide");
return false;
});
});
$(window).resize(function(){
$(".subMenu").addClass('hide');
});
html
<div class="site-wrapper">
<div class="nav-container">
<div class="logo-holder">
<img class="user-select-none" src="images/temp-logo.jpeg" alt="temp" />
</div>
<div id="navigation-div">
<nav class="nav">
<ul>
<li><a class="nav-link active" href="">Test 1</a></li>
<li><a class="nav-link " href="">Test 2</a></li>
<li><a class="nav-link" href="">Test 3</a></li>
<li class="hide"><a class="nav-link hide" href="">Test 4</a></li>
<li class="hide"><a class="nav-link hide" href="">Test 5</a></li>
<li class="show"><a class="nav-link" href="">Menu</a>
<ul class="subMenu">
<li><a class="nav-link" href="">Test 4</a></li>
<li><a class="nav-link" href="">Test 5</a></li>
</ul>
</li>
</ul>
</nav>
</div>
</div>
</div>
css
.site-wrapper {
height: 100%;
min-height: 100%;
display: flex;
}
/* make divs appear below each other on screen resize */
#media screen and (max-width: 540px) {
.site-wrapper {
flex-direction: column;
}
}
ul.subMenu {
display: none;
}
.subMenu.active {
display: flex;
flex-direction: column;
}
li.show {
display: none;
}
.nav-container {
border-right: 1px solid #E4E2E2;
height: 100%;
width: 200px;
background-color: #f4f3f3;
}
.logo-holder {
text-align: center;
}
.nav {
text-align: justify;
}
nav:after {
content: "";
display: table;
clear: both;
}
.nav-link {
display: block;
text-align: left;
color: #333;
text-decoration: none;
margin-left: 0px;
padding-left: 15px;
}
.nav-link:hover {
background-color: #333;
color: #f4f3f3;
}
.nav ul {
width: 100%;
/* make div span div */
padding: 0px;
}
.nav ul li {
list-style-type: none;
}
.nav li:hover a {
color: #f4f3f3;
}
.active {
text-align: left;
padding-left: 15px;
text-decoration: none;
background-color: #333;
color: #f4f3f3;
}
#media screen and (max-width: 540px) {
.nav-container {
width: 100%;
height: 100px;
background-color: #f4f3f3;
border-bottom: 0.5px solid #f4f3f3;
}
.nav-link {
padding: 10px;
}
.logo-holder {
overflow: hidden;
display: block;
margin: auto;
width: 40%;
}
.nav-container nav ul {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.logo-holder {
text-align: left;
}
#navigation-div {
background-color: #f4f3f3;
margin-top: 0;
}
.socials {
display: none;
}
.hide {
display: none;
}
.nav-container nav .hide{
display: none;
}
.show {
display: inline-block !important;
}
a.nav-link {
width: 50px;
}
.active-parent a.nav-link {
color: #ffffff;
background: #333;
}
.nav ul li {}
}
No 2.
You're setting both ul to display as flex, change it so it will only applied to parent ul only
.nav-container nav>ul {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
Cosmetic for your second level links when user click the menu
.selected a,
.active a {
background-color: #333;
color: #f4f3f3;
}
I also added some class to make styling easier when the menu is open
$(this).toggleClass('selected');
(function($) {
$(document).ready(function() {
$(".show").click(function() {
$(this).toggleClass('selected');
$(".subMenu").toggleClass("active");
return false;
});
});
})(jQuery);
.site-wrapper {
height: 100%;
min-height: 100%;
display: flex;
}
/* make divs appear below each other on screen resize */
#media screen and (max-width: 540px) {
.site-wrapper {
flex-direction: column;
}
}
ul.subMenu {
display: none;
}
.subMenu.active {
display: flex;
flex-direction: column;
}
li.show {
display: none;
}
.nav-container {
border-right: 1px solid #E4E2E2;
height: 100%;
width: 200px;
background-color: #f4f3f3;
}
.logo-holder {
text-align: center;
}
.nav {
text-align: justify;
}
nav:after {
content: "";
display: table;
clear: both;
}
.nav-link {
display: block;
text-align: left;
color: #333;
text-decoration: none;
margin-left: 0px;
padding-left: 15px;
}
.nav-link:hover {
background-color: #333;
color: #f4f3f3;
}
.nav ul {
width: 100%;
/* make div span div */
padding: 0px;
}
.nav ul li {
list-style-type: none;
}
.nav>li:hover a {
color: #f4f3f3;
}
.active {
text-align: left;
padding-left: 15px;
text-decoration: none;
background-color: #333;
color: #f4f3f3;
}
.selected a,
.active a {
background-color: #333;
color: #f4f3f3;
}
#media screen and (max-width: 540px) {
.nav-container {
width: 100%;
height: 100px;
background-color: #f4f3f3;
border-bottom: 0.5px solid #f4f3f3;
}
.nav-link {
padding: 10px;
}
.logo-holder {
overflow: hidden;
display: block;
margin: auto;
width: 40%;
}
.nav-container nav>ul {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.logo-holder {
text-align: left;
}
#navigation-div {
background-color: #f4f3f3;
margin-top: 0;
}
.socials {
display: none;
}
.hide {
display: none;
}
.show {
display: inline-block !important;
}
.nav ul li {}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="site-wrapper">
<div class="nav-container">
<div class="logo-holder">
<img class="user-select-none" src="images/temp-logo.jpeg" alt="temp" />
</div>
<div id="navigation-div">
<nav class="nav">
<ul>
<li><a class="nav-link active" href="">Test 1</a></li>
<li><a class="nav-link " href="">Test 2</a></li>
<li><a class="nav-link" href="">Test 3</a></li>
<li class="hide"><a class="nav-link hide" href="">Test 4</a></li>
<li class="hide"><a class="nav-link hide" href="">Test 5</a></li>
<li class="show"><a class="nav-link" href="">Menu</a>
<ul class="subMenu">
<li><a class="nav-link" href="">Test 4</a></li>
<li><a class="nav-link" href="">Test 5</a></li>
</ul>
</li>
</ul>
</nav>
</div>
</div>
</div>

Categories