Add 2nd sub nav to accordion style menu - javascript

I'm looking to have an additional subnav to this accordion menu. I tried to add a child element to the nav ul li, but that didn't seem to work. Ideally, I would like to be able to list web projects under "web" and print under "print".
FIDDLE: http://jsfiddle.net/schermerb/rGMAu/1/
.header button {
cursor:pointer;
float:right;
padding:5px;
margin:10px 10px;
border:none;
border:1px solid #ececec;
background:#444;
color:#ececec;
}
.nav {
text-align:center;
background:#444;
}
.nav ul li {
text-transform:capitalize;
display:block;
border-bottom:1px solid #ececec;
}
.nav a {
display:block;
padding:10px;
color:#ececec;
}
.nav a:hover {
background:#029b9d;
color:#ececec;
}
<button id="show">Menu <span>+</span> <span style="display:none;">-</span>
</button>
<div class="clear"></div>
</div>
<div class="nav">
<ul>
<li>Home
</li>
<li>About
</li>
<li>Web
</li>
<li>Print
</li>
</ul>
</div>

I have updated your js
$('.nav, .nav li ul').hide();
$('#show').click(function () {
$(".nav").toggle();
$("span").toggle();
});
$('.nav li').click(function(){
$(this).children('ul').toggle();
});
Updated jsFiddle File

Adding a child element was the right path.
http://jsfiddle.net/jonigiuro/rGMAu/2/
<li>Web
<ul class="sub">
<li class="item">item1</li>
<li class="item">item2</li>
</ul>
</li>
You hide the child element by default, and when you hover on the parent, you show the it:
ul li:hover ul
Here's the revelant css for your case:
.nav ul li ul {
color: red;
margin: 0;
padding: 0;
display: none;
}
.nav ul li:hover ul {
display: block;
}
.nav ul li ul li {
padding: 10px 0;
}

Related

How to deal with multi-level menus on touch screen devices which are using :hover and :focus for clickable top-level links?

Have a look at the following menu:
.clearfix::after {
content: "";
clear: both;
display: table;
}
#my-menu-inner > ul {
margin:10px;
width:100%;
background-color:yellow;
list-style-type:none;
position:relative;
}
#my-menu-inner > ul > li {
float:left;
margin:20px;
}
#my-menu-inner > ul > li > a {
padding:20px;
border:1px solid black;
display:block;
}
#my-menu-inner > ul > li > div.sub {
position:absolute;
top:calc(100% - 20px);
background-color:red;
padding:40px;
display:none;
left:0;
width:100vw;
}
#my-menu-inner > ul > li a:hover + div.sub, #my-menu-inner > ul > li a:focus + div.sub,
#my-menu-inner > ul > li > div.sub:hover, #my-menu-inner > ul > li > div.sub:focus {
display:block;
}
<div id="whatever">Just something before ...</div>
<div id="my-menu">
<div id="my-menu-inner">
<ul class="clearfix">
<li>
foo
<div class="sub">
<ul>
<li>mobile</li>
<li>users</li>
</ul>
</div>
</li>
<li>
bar
<div class="sub">
<ul>
<li>never</li>
<li>see me</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
This is a nicely working menu for everybody who is having a mouse or a touchpad. However: Users of mobile devices will never ever see the submenu as they instantly go to the href location as soon as they click one of the links. And they do not have hover states, ofc.
What I thought about:
Idea 1: Have a seperate mobile menu for touch devices. This is great because most designs have seperate mobile menus anyway.
Problem: #media screen (max-width: 1000px) will not be a sufficient method to detect if a user is able to hover/focus as everyone with a large touchscreen for instance would be excluded.
Idea 2: preventDefault() on clicking the links. Check if mouse movement was detected before and if so, follow the link. If not require a second click.
Problem: Requiring two clicks is probably not user friendly (many will not recognize the link is clickable).
What is a good and recommended way to deal with this situation?
I think a good practise is to make a visible clickable element. You should not only think about the implementation but about how the user will interact. The user need to know there is a sub menu and to do this you can add a small icon that may appear everywhere even if we can :hover.
Here is a simplified example where hover work by default. In case we cannot hover, we can click the icon to show the menu. Simply use an icon that make the click intuitive for users.
$('li span').click(function() {
$(this).next('.sub').toggleClass('show');
$(this).toggleClass('open');
})
.clearfix::after {
content: "";
clear: both;
display: table;
}
#my-menu-inner > ul {
margin:10px;
width:100%;
background-color:yellow;
list-style-type:none;
position:relative;
}
#my-menu-inner > ul > li {
float:left;
margin:20px;
}
#my-menu-inner > ul > li > a {
padding:20px;
border:1px solid black;
display:inline-block;
}
#my-menu-inner > ul > li > span {
text-decoration:none;
display:inline-block;
padding:20px 5px;
border:1px solid black;
margin-right:-10px;
cursor:pointer;
}
#my-menu-inner > ul > li > span:before {
content:"▼"
}
#my-menu-inner > ul > li > span.open:before {
content:"▲"
}
#my-menu-inner > ul > li > div.sub {
position:absolute;
top:calc(100% - 20px);
background-color:red;
padding:40px;
display:none;
left:0;
width:100vw;
}
#my-menu-inner > ul > li a:hover ~ div.sub,
#my-menu-inner > ul > li span:hover ~ div.sub,
#my-menu-inner > ul > li a:focus ~ div.sub,
#my-menu-inner > ul > li span:focus ~ div.sub,
#my-menu-inner > ul > li > div.sub:hover,
#my-menu-inner > ul > li > div.sub:focus,
#my-menu-inner > ul > li > div.sub:hover,
#my-menu-inner > ul > li > div.sub.show{
display:block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="whatever">Just something before ...</div>
<div id="my-menu">
<div id="my-menu-inner">
<ul class="clearfix">
<li>
foo<span></span>
<div class="sub">
<ul>
<li>mobile</li>
<li>users</li>
</ul>
</div>
</li>
<li>
bar<span></span>
<div class="sub">
<ul>
<li>never</li>
<li>see me</li>
</ul>
</div>
</li>
<li>
I don't have submenu
</li>
</ul>
</div>
</div>

jQuery .hover() or .mouseleave() not working on chrome

Problem description:
In my menu when .mouseenter() the menu opens and when .mouseleave() it closes, but if i click a lot , the .mouseleave() event is executed.
This only happened on chrome browser.
I have other .click() events inside my menu, but every click I made, the .mouseleave() event is execute.
$(document).ready(function() {
$("#nav1 li").hover(
function() {
$(this).find('ul').slideDown();
},
function() {
$(this).find('ul').slideUp();
});
});
#nav1 a {
color: #FFFFFF;
}
#nav1 li ul li a:hover {
background-color: #394963;
}
div ul li ul {
background-color: #4a5b78;
list-style: none
}
#nav1 > li > a {
padding: 16px 18px;
display: block;
border-bottom: 2px solid #212121;
}
#nav1 li ul li a {
padding: 10px 0;
}
div {
background-color: #000000;
background-color: #343434;
width: 280px;
}
/* Hide Dropdowns by Default */
#nav1 li ul {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<ul id="nav1">
<li>Hover here and infinite click
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
<li>Menu Heading 2
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
</ul>
<div>
Try click "Hover here and infinite click" to see this problem.
EDIT:
As you guys said, the problem occurs in this example.
Here is a video: Video link
When you click many times the browser has lost the element reference, try this example:
<div id="container">
<ul id="nav1">
<li>Menu Heading 1
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
<li>Menu Heading 2
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
<li>Menu Heading 3
<ul>
<li>Stage1</li>
<li>Stage2</li>
<li>Stage3</li>
<li>Stage4</li>
</ul>
</li>
</ul>
<div>
Css
ul,
li,
a {
padding: 0px;
margin: 0px;
}
.show {
display: block !important;
}
#nav1 a {
color: #FFFFFF;
}
#nav1 li ul li a:hover {
background-color: #394963;
}
div ul li ul {
background-color: #4a5b78;
list-style: none
}
#nav1 > li > a {
background-color: #343434;
padding: 16px 18px;
text-decoration: none;
display: block;
border-bottom: 2px solid #212121;
background: linear-gradient(top, #343434, #111111);
}
#nav1 li ul li a {
padding: 10px 0;
padding-left: 30px;
text-decoration: none;
display: block;
}
div {
background-color: #000000;
background-color: #343434;
width: 280px;
}
/* Hide Dropdowns by Default */
#nav1 li ul {
display: none;
}
JS
$(document).ready(function() {
$("#nav1 li").hover(
function(e) {
let ulMenu = $(this).find('ul');
ulMenu.addClass('show');
//$(this).find('ul').slideDown();
},
function(e) {
if(e.relatedTarget){
let ulMenu = $(this).find('ul');
ulMenu.removeClass('show');
} else {
console.log('fail ');
}
//$(this).find('ul').slideUp();
});
});
Codepen Example Works
You can add a stropPropagation in your click event.
$("#nav1 li").click(
function(e){
e.stopPropagation();
});
maybe the event is getting lost in the process, try to verify it, and if so set the actual element.
see this: https://api.jquery.com/event.relatedTarget/

How to display dropdown menu slider effect from bottom to top after hover?

I have display drop down menu slider effect from bottom to top after hover with linearly and all drop down text should be display left align.
I tried some code but when i hovered first menu my second menu displaying on right side.would you help me in this?
HTML
<div class="right-menu-bar">
<ul class="main-menu">
<li>Menu
<ul>
<li>menu1 details</li>
<li>menu1 details</li>
<li>menu1 details</li>
</ul>
</li>
<li>Menu
<ul>
<li>menu1 details</li>
<li>menu1 details</li>
<li>menu1 details</li>
</ul>
</li>
</ul>
</div>
CSS
.right-menu-bar ul.main-menu > li
{
float: left;
margin: 15px;
font-size: 16px;
}
li ul
{
list-style: none;
background: #3498db;
z-index: 2;
font-size: 16px;
padding:0 ;
}
li ul li
{
text-transform: capitalize;
}
.main-menu li > ul {
display:none;
}
.main-menu li:hover > ul {
display:block;
}
li ul li a{
text-decoration: none;
color: #fff;
padding: 10px 50px;
display:block;
text-align: left !important;
}
li ul li a:hover{
background-color:#5dade2;
text-decoration: none;
color: #000;
}
I thought your problem is stop the second menu slide to right when hover the 1st menu. so adding the position:absolute property to dropdown menu to avoid the second menu sliding.
Now I am adding sideDown() and slideUp() to show or hide the dropdown on menu hover Try below code.
//Hide and Show The Sub Menus
$(".jquery-test ul li.menu-list").hover(function(){
$(this).find('ul').stop().slideDown();
},function(){
$(this).find('ul').stop(true,true).slideUp();
});
.jquery-test ul.menu li.menu-list{display:inline-block;padding-right:20px;}
.jquery-test ul{list-style:none;padding-left:10px;}
.jquery-test ul.menu li.menu-list ul.submenu {display:none;}
.jquery-test ul.menu li.menu-list ul.submenu{position:absolute;}
.jquery-test ul.menu li.menu-list ul.submenu li{position:relative;left:0px;}
.jquery-test ul li a{text-decoration:none;color:#000;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="jquery-test">
<ul class="menu">
<li class="menu-list">Menu1
<ul class="submenu">
<li>Menu1.0</li>
<li>Menu1.1</li>
<li>Menu1.2</li>
<li>Menu1.3</li>
</ul>
</li>
<li class="menu-list">Menu2
<ul class="submenu">
<li>Menu2.1</li>
<li>Menu2.2</li>
<li>Menu2.3</li>
<li>Menu2.4</li>
</ul>
</li>
<li class="menu-list">Menu3
<ul class="submenu">
<li>Menu3.0</li>
<li>Menu3.1</li>
<li>Menu3.2</li>
<li>Menu3.3</li>
</ul>
</li>
</ul>
You can do this by applying position: absolute; to the menus that appear, like this:
.main-menu li:hover > ul {
display:block;
position: absolute;
}
Working Fiddle

Nested UL Height

I have a menu with nested UL's to work as a drop down menu. In the drop down I have another nested UL with LI's that are pragmatically generated so I don't know how many are going to be in their.
I was trying to set the height of the second UL on load so that I can put a border around the dropdown.
HTML:
<ul>
<li>1</li>
<li>2
<ul>
<li>2a
<ul class="submenu">
<li>2a1</li>
<li>2a2</li>
<li>2a3</li>
<li>2a4</li>
<li>2a5</li>
</ul>
</li>
<li>2b
<ul class="submenu">
<li>2b1</li>
<li>2b2</li>
<li>2b2</li>
<li>2b2</li>
<li>2b2</li>
<li>2b2</li>
<li>2b2</li>
<li>2b2</li>
<li>2b2</li>
<li>2b2</li>
</ul>
</li>
</ul>
</li>
<li>3</li>
</ul>
CSS:
ul {
list-style-type: none;
}
ul li {
display: inline-block;
/*float: left;*/
width: 100px;
}
ul li:hover {
background-color: #cc0505;
color: white;
}
ul li ul {
/*visibility: hidden;*/
position: absolute;
padding: 0px;
border: 2px solid black;
/*min-height:120px;*/
}
ul li:hover ul {
visibility: visible;
}
ul li ul li {
/*display: inline;
float: left;*/
color: black;
}
ul li ul li:hover {
background-color: white;
color: black;
}
ul li ul li ul {
border: none;
min-height:0px;
}
ul li ul li ul li {
display: block;
/*float: none;*/
}
ul li ul li ul li:hover {
background-color: #cc0505;
color: white;
}
I have tried using $('ul ul ul').each and $('ul ul ul').next() to loop through any UL on the third level but it only seems to be picking up the first occurrence.
A jsfiddle I set up with my code and a few attempts I have made to get this right. http://jsfiddle.net/kZ236/2/
the problem is, that height() always takes the height of the first element of the set, no matter what you do before calling that.
using each() together with a Math.max will work
http://jsfiddle.net/kZ236/3/
your code with next() didn't work as the ul didn't had a next element. next() is no iterator through the set of $('ul ul ul') but getting the next sibbling in the dom tree.
Try this:
$(document).ready(function () {
$('#nav>li>ul').each(function(){
var maxHt=0;
$(this).find('.submenu').each(function(){
var bottomPosition=$(this).height() +$(this).position().top
maxHt= bottomPosition>maxHt ? bottomPosition : maxHt;
});
$(this).height( maxHt)
})
})
DEMO

creates a line break before and after drop down menu in css

When I created a drop down menu using css, it generates a line break before and after drop down menu
Here is html code
<body>
<!--nav class="navi"-->
<div class="navi" id="navi">
<ul>
<li>Home</li>
<li>About us
<ul>
<li>History</li>
<li>Company Profile</li>
<li>Core Values And Mission</li>
<li>Strategy</li>
</ul>
</li>
<li>Our Brands
<ul>
<li>HAMARA GLUCOSE D</li>
<li>HAMARA HEALTH CARE PATENT PRODUCTS</li>
<li>WAHT'S NEW</li>
</ul>
</li>
<li>Nutrition Space
<ul>
<li>Product FAQ</li>
<li>Health & Wellness</li>
</ul>
</li>
<li>Media
<ul>
<li>News Paper Clippings</li>
<li>Product Photos</li>
<li>Founder which...</li>
</ul>
</li>
<li>HSS</li>
<li>Copackers & Investors</li>
<li>Career</li>
<li>Communities</li>
<li>Contact Us</li>
</ul>
</div>
<!--/nav-->
</body>
and here is css code
<style>
.navi ul li
{
float:left;
}
.navi ul li a
{
display:block;
padding: 10px;
text-decoration:none;
}
.navi ul li:hover > a
{
color:white;
}
.navi ul
{
display:inline-table;
list-style:none;
padding: 0 0px;
position:relative;
background:#C93;
}
.navi ul ul
{
display: none;
position:absolute;
}
.navi ul ul li
{
/*display:block;*/
float:none;
}
.navi ul li:hover > ul
{
display:block;
background:#FC0707;
}
</style>
So I don't want to generate a line break
*{
padding:0;
margin:0;
}
Add this to styles
try using the white-space property
assign this to the div:
.navi
{
white-space: nowrap;
}
some more examples
If you meant the first layer of a remove display:block; from below code else if it is the second layer of a i.e. menu options
Try chaning
.navi ul li a {
display:block;
padding: 10px;
text-decoration:none; }
to
.navi ul li > a {
display:block;
padding: 10px;
text-decoration:none; }
I believe that block style has been applied to ALL the a creating a break inside the menu options too
Where it generates line break? By default div display type is block which takes 100% width of its parent and obviously pushed content down which is next to it in the flow.
Do you want to add content before and after the menu?
#navi{
display: inline;
}
Also make before and after content's display property to inline ( if no width is specified ) or inline-block ( if you want to specify width ).

Categories

Resources