Creating a dropdown menu with CSS and JS - javascript

I am having trouble creating a simple dropdown menu nested inside the navigation bar. I have it so that when you hover over the navigation link dropdown appears, however, it disappears when you move down into the box- you can't. I want to be able to navigate in the dropdown box. I have been trying to do this with CSS and recently have tried with JS (though I am very new with JS so sorry, bear with me) I am having trouble understanding how to connect and apply a CSS class with JS so that it only works when you want it to.
const dropdown = document.querySelector('.second-nav-list-wrapper')
dropdown.onmouseenter = () => {
dropdown.classList.toggle('second-nav-list')
}
.second-nav{
position:relative;
}
.second-nav-list{
visibility:hidden;
list-style:none;
font-family:'Raleway';
text-transform:uppercase;
color:grey;
position:absolute;
top:10px;
background-color:rgb(235, 245, 252);
text-align:left;
padding:10px;
line-height: 40px;
display:flex;
}
.second-nav-link{
text-decoration:none;
color:rgb(59, 53, 53);
}
.header-nav-link-dropdown:hover .second-nav .second-nav-list{
visibility:visible;
text-decoration:none;
background-color:rgb(208, 215, 230);
}
<nav class="header-wrapper">
<ul class= "header-nav">
<li class="header-nav-link-wrapper">
Home
</li>
<li class="header-nav-link-wrapper header-nav-link-dropdown">
Recipes
<nav class="second-nav">
<ul class="second-nav-list">
<div class= "second-nav-list-wrapper">
<li>
Breakfast
</li>
<li>
Lunch
</li>
<li>
Snacks
</li>
<li>
Dinner
</li>
</div>
</ul>
</nav>
</li>
<li class="header-nav-link-wrapper">
Cookbooks
</li>

here's one way to do it. We use the onmouseover to open the dropdown. We use the onmouseleave event to close it. Note we are using onmouseleave on the whole navbar so we only close the dropdown when the mouse leaves the navbar and all it's children.
Here are also some examples of how other mouse hover events behave:
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onmousemove_leave_out
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onmousemove_over_enter
const dropdown = document.querySelector('.second-nav-list');
const recipies = document.querySelector('.recipies');
const navbar = document.querySelector('.header-nav')
//this function toggles visibiltity on
recipies.onmouseover = () => {
dropdown.style.visibility = "visible";
}
//this one toggles it off
navbar.onmouseleave = () => {
dropdown.style.visibility = "hidden";
}
.second-nav{
position:relative;
}
/* added background color here, removed the on-hover */
.second-nav-list{
visibility:hidden;
list-style:none;
font-family:'Raleway';
text-transform:uppercase;
color:grey;
position:absolute;
top:10px;
text-align:left;
padding:10px;
line-height: 40px;
display: block;
background-color:rgb(208, 215, 230);
color:rgb(59, 53, 53);
}
<nav class="header-wrapper">
<ul class= "header-nav">
<li class="header-nav-link-wrapper">
Home
</li>
<li class="header-nav-link-wrapper header-nav-link-dropdown">
Recipes <!-- Changed -->
<nav class="second-nav">
<ul class="second-nav-list">
<li>
Breakfast
</li>
<li>
Lunch
</li>
<li>
Snacks
</li>
<li>
Dinner
</li>
</ul>
</nav>
</li>
<li class="header-nav-link-wrapper">
Cookbooks
</li>
</ul>
</nav>

Related

Best way to change navbar dropdown function from CSS-only to Javascript on mobile?

Here is my current CSS-only dropdown menu html:
<div class="main-nav">
<div class="main-nav-container">
<div class="nav-links">
<ul>
<li class="nav-link"><a>Nav Link</a>
<div class="dropdown">
<ul class="dropdown-list-type">
<li>
<ul>
<li>
Option
</li>
<li>
Option
</li>
<li>
Option
</li>
</ul>
</li>
</ul>
</div>
</li>
<li class="nav-link"><a>Nav Link</a>
<div class="dropdown">
<ul class="dropdown-list-type">
<li>
<ul>
<li>
Option
</li>
<li>
Option
</li>
<li>
Option
</li>
</ul>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
Relevant CSS:
.dropdown{
position: absolute;
display: flex;
top: 100%;
border-top: solid 1px var(--white-3);
left: 0;
z-index: 8;
opacity: 0;
pointer-events: none;
transition: .3s; }
.nav-link:hover > .dropdown,
.dropdown-link:hover > .dropdown{
transform: translate(0, 0);
opacity: 1;
pointer-events: auto;
}
On mobile, I want the user to be able to open and close the dropdown by tapping on the "Nav Link". Currently, the user can tap to open, but then has to tap somewhere else to close the dropdown. I figure I need Javascript make it do what I want.
My idea:
Use a media query to remove the hover function on mobile
Use Javascript to add a class to the "Nav Links" on mobile
Using this class, with JS, make the Nav Links toggle the dropdown to display/hide
Is this the best way to do it? If so, how do I add a class to the "Nav Links" with Javascript at a specific screen size?
I would like to just use plain Javascript, no Jquery.
Also, I current want to keep the CSS-only hover approach for desktop. So I want the Javascript function only for the mobile view.
I hope that makes sense to everyone. Thank you!

How to show/hide when hover in/out on specific element

I make a secondary menu and I like it to be displayed when user hover a specific one of the main menu items....
I tried this code but it didn't work...
.second-menu {display:none}
ul li #2:hover + .second-menu {display:block}
<ul>
<li id="1">first</li>
<li id="2">second</li>
<li id="3">third</li>
<ul>
<div class="second-menu">
<ul>
<li>page1</li>
<li>page2</li>
<li>page3</li>
</ul>
</div>
any suggestions?....
only by css or javascript....
If you wish to use CSS, you will have to put your sub menu inside the element that you want to hover.
For the CSS, C.Raf.T's answer is perfect.
If for some reason you want to use javascript you could do something like this
document.getElementById('2').addEventListener('mouseenter', function ()
{
document.getElementById('subMenu').style.display = "block";
});
document.getElementById('2').addEventListener('mouseleave', function ()
{
document.getElementById('subMenu').style.display = "none";
});
Note: the above code requires you to add a "subMenu" id to the div containing your menu. If you wish to display serval menus with only one hover event, use a class instead.
But honestly, the CSS answer is the best way to go if all you need is nested sub menus.
If the sub menu has to be outside of the parent, you will need the javascript.
.second-menu{
display:none;
}
li:hover >.second-menu{
display:block;
}
<ul>
<li id="1">first</li>
<li id="2">second
<ul class="second-menu">
<li>page1</li>
<li>page2</li>
<li>page3</li>
</ul>
</li>
<li id="3">third</li>
<ul>
Answer using Javascript,
document.getElementById('hover').onmouseover = function(){
document.getElementById('second-menu').style.display = 'block';
}
document.getElementById('hover').onmouseout = function(){
document.getElementById('second-menu').style.display = 'none';
}
.second-menu{
display:none;
}
<ul id="hover">
<li id="1">first</li>
<li id="2">second</li>
<li id="3">third</li>
<ul>
<div class="second-menu" id="second-menu">
<ul>
<li>page1</li>
<li>page2</li>
<li>page3</li>
</ul>
</div>
Here is a fiddle
By using pure CSS you have to ensure that your submenu (.second-menu) is a child-node of your hovered HTML-Element. Because CSS unfortunately doesn't know a parent selector.
By using JS you are more flexible. Means placing the submenu wherever you wish.
* { margin: 0; padding: 0; }
.second-menu {display:none; border: 1px solid blue; width: 100%; position: absolute; left: 0; right: 0; }
ul li#two:hover > .second-menu {display:block}
.relative { position: relative; border: 1px solid black; }
li { display: inline-block; }
<ul class="relative">
<li id="one">first</li>
<li id="two">second
<ul class="second-menu">
<li>page1</li>
<li>page2</li>
<li>page3</li>
</ul>
</li>
<li id="three">third</li>
<ul>

Javascript- Multi-level Drop Down Div Positioning?

So I'm trying to to make a horizontal menu with CSS and JavaScript that is multi-level. I have a toggle function that shows the div container of the submenu, however, when it displays it pushes the links below the container. How can I make it so when I click the link to show a div container that it appears below the rest of the links. Also I would like to make it where only one link can be selected and I have no clue how to do it. I've never used JavaScript before and I'm fairly new to CSS.
I've removed almost all styling from my code. but here is the functionality.
#togglebox {
display:none;
}
#togglebox li{
display: inline-block;
}
#extrabox {
display:none;
background: #E6ECF2;
text-align: center;
min-width: 100%;
}
#extrabox li{
display: inline-block;
}
#extrabox2 {
display:none;
background: #E6ECF2;
text-align: center;
min-width: 100%;
}
#extrabox2 li{
display: inline-block;
}
function toggle_visibility(id) {
var e = document.getElementById(id);
if(e.style.display == 'block')
e.style.display = 'none';
else
e.style.display = 'block';
}
<ul class="sub-menu" style="display:inline;">
<li id="NSM1">Normal Sub Menu</li></td>
<li id="SMEL">Sub-menu Item with Second Level</li>
<li id="NSM2">Normal Sub Menu</li>
<br />
</ul>
<div id="togglebox">
<li id="NSSL1">[Normal Link]</li>
<li id="SSL2">[Has extra Level]</li>
<div id="extrabox">
<li id="sublinkea">3rd level item1</li> <li id="sublinkeb">3rd level item2</li> <li id="sublinkea">3rd level item3</li>
<li id="sublinkeb">3rd level item4</li>
</div>
<li id="SSL3"><li id="sublinksc">[Has Extra Level]</li>
<div id="extrabox2">
<li id="sublinkea">3rd level item1</li>
<li id="sublinkeb">3rd level item2</li>
<li id="sublinkea">3rd level item3</li>
<li id="sublinkeb">3rd level item4</li>
</div>
<li id="NSSL2">[Normal Link]</li>
</div>
</div>
It looks to me like the trouble is that you have #extrabox as a child of #togglebox, when you really want it to a sibling. As it is, #extrabox will affect the positioning of any block-level elements that come after it (as siblings) under #togglebox. A quick fix looks like:
<div id="togglebox">
<ul>
<li id="NSSL1">
[Normal Link]
</li>
<li id="SSL2">
<a href="#" onclick="toggle_visibility('extrabox');">
[Has extra Level]
</a>
</li>
</ul>
</div>
<div id="extrabox">
<!-- put #extrabox contents here -->
</div>
(I also went ahead and fixed the a tags that were children of ul; ul only takes li tags as children.)
Similarly, you'll want to move #extrabox2 out from under #extrabox so that it doesn't affect the positioning of its siblings there.
I'm not sure what you mean by, "Also I would like to make it where only one link can be selected." Could you clarify that?
Hope that helps!

Link with hover dropdown menu for Mobile Devices

I've found an issue I just can't seem to solve.
I've got a navigation, 5 links in total. One of the links has a dropdown menu when you hover over it showing 3 more links.
Fine when a mouse is involved. But when you start using touch devices, the parent link consumes all gestures and taps, and the viewer is shown the dropdown for a fraction of a second before being taken to the parent's link page.
I'm wondering if there's a way of making it so the first touch of the parent link shows the dropdown menu, then a second touch would go to that link. touching anything else would just hide the dropdown.
<ul id="main-menu">
<li>Link</li>
<li>Link</li>
<li>Link
<ul class="sub-menu">
<li>Sub Link</li>
<li>Sub Link</li>
<li>Sub Link</li>
</ul>
</li>
<li>Link</li>
<li>Link</li>
</ul>
Anyone have any ideas? jQuery would be ideal
Something like this perhaps? You may want to customize the behavior of the dropdown, but this shows the basic logic of handling the click events and preventing default behaviour (i.e. following links) if the menu isn't open:
$(function() {
$('#main-menu a').click(function(e) {
var listItem = $(this).closest('li');
if (!listItem.is('.open')) {
// Opening drop-down logic here. e.g. adding 'open' class to <li>
e.preventDefault();
listItem.addClass('open');
}
// Otherwise the default behaviour of the event (clicking the link) will be unaffected
});
});
i have done complete bins for above issue also placed demo link here.
Demo: http://codebins.com/bin/4ldqp72
HTML
<ul id="main-menu">
<li>
<a href="#">
Link
</a>
</li>
<li>
<a href="#">
Link
</a>
</li>
<li>
<a href="#">
Link
</a>
<ul class="sub-menu">
<li>
<a href="#">
Sub Link
</a>
</li>
<li>
<a href="#">
Sub Link
</a>
</li>
<li>
<a href="#">
Sub Link
</a>
</li>
</ul>
</li>
<li>
<a href="#">
Link
</a>
</li>
<li>
<a href="#">
Link
</a>
</li>
</ul>
JQuery
$(function() {
$('ul a').click(function(e) {
$('#main-menu li').removeClass('open');
e.preventDefault();
$(this).closest('li').addClass("open");
var pos = $(this).closest('li.open').offset();
$(this).closest('li.open').find("ul.sub-menu").css('top', pos.top + 'px');
});
});
CSS
#main-menu{
list-style:none;
margin:2px;
padding:2px;
}
li{
border:1px solid #333;
background:#ebcdff;
text-align:center;
width:100px;
}
li:hover{
background:#abcdfd;
}
li:hover a{
color:#ff3322;
}
li a{
text-decoration:none;
color:#2466ff;
}
li.open {
background:#abcdfd;
}
li.open a{
text-decoration:none;
color:#ff3322;
}
ul.sub-menu{
list-style:none;
display:none;
}
li.open > ul{
position:absolute;
left:70px;
display:block;
}
Demo: http://codebins.com/bin/4ldqp72

highlight currently selected link in css menu bar

I have a page with this URL: http://localhost:8000/progress/c/?l=1&c=1
And the below content to work as a simple css menu bar.
<div class="menu_div">
<ul>
<li> l1c1 </li>
<li> l1c1 </li>
<li> l1c1 </li>
<li> l1c1 </li>
</ul>
</div>
CSS styling is
.menu_div ul
{
padding:6px;
margin:0px;
font-size:12px;
list-style:none;
text-indent:15px;
}
.menu_div ul li
{
line-height:28px;
border-bottom:1px solid #000;
}
.menu_div ul li a
{
text-decoration:none;
font-color:#3A332D;
display:block;
}
.menu_div ul li a:hover
{
background:blue;
}
.menu_div ul li#active
{
background:blue;
}
When I hover over the links the background color changes but the currently selected menu link is not highlighted in blue.
I'm using django framework.
Try this jQuery code, it will add the class automatically
$(function(){
var url = window.location.href;
$("#menu a").each(function() {
if(url == (this.href)) {
$(this).closest("li").addClass("active");
}
});
});
In your CSS you have a class with the id 'active', this should probably be a class like this:
.menu_div ul li.active
{
background:blue;
}
Further, I wouldn't recommend trying to match the 'active' or better formulated 'current' page using javascript client side.
Instead your script on the server should recognize the current page and add a class to the related menu item so it would look like this:
<li class="active"> l1c1 </li>
Replace your id #active to class .active - that is more right way:
.menu_div ul li.active
{
background:blue;
}
and add this class to active element in your list:
<div class="menu_div">
<ul>
<li class="active"> l1c1 </li>
<li> l1c1 </li>
<li> l1c1 </li>
<li> l1c1 </li>
</ul>
</div>
.menu_div ul li#active
It says the active link needs an id of active. I see no id, hence why it is not blue.
If you want the link to be active, you are going to have to set the item to be active, the browser will not do it for you.
Just
css
.menu_div ul li.active{background:blue}
html
<div class="menu_div">
<ul>
<li id="page1"> l1c1 </li>
<li id="page2"> l1c1 </li>
<li id="page3"> l1c1 </li>
<li id="page4"> l1c1 </li>
</ul>
</div>
script
#In every page just put this script and change the id
<script>$("#page1").addClass('active');</script>

Categories

Resources