Submenu dissappears on mouse hover - javascript

I want the dropdown menu behave like here: https://svyaznoy.ru
var timer;
$(".catalog-menu li").mouseenter(function() {
var that = this;
timer = setTimeout(function(){
$(that).children(".submenu").show();
}, 500);
}).mouseleave(function() {
var that = this;
clearTimeout(timer);
setTimeout(function () {
$(that).children(".submenu").hide();
}, 500);
});
ul {
list-style-type: none;
padding-left: 0;
}
ul.submenu {
display: none;
position: absolute;
left: 100%;
top: 1px;
margin-left: -1px;
}
li {
padding: 10px;
border: 1px solid #ddd;
margin-top: -1px;
}
li.submenu-item {
min-width: 110px;
}
ul.catalog-menu {
width: 150px;
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<ul class="catalog-menu">
<li>
<span>Apple</span>
<ul class="submenu">
<li class="submenu-item">
<span>Laptops</span>
<ul class="submenu">
<li class="submenu-item">Macbook 12</li>
<li class="submenu-item">Macbook Pro 13</li>
<li class="submenu-item">Macbook Pro 15</li>
<li class="submenu-item">Macbook Air Retina</li>
</ul>
</li>
<li class="submenu-item">
<span>iPhones</span>
<ul class="submenu">
<li class="submenu-item">iPhone 8</li>
<li class="submenu-item">iPhone 8 Plus</li>
<li class="submenu-item">iPhone X</li>
<li class="submenu-item">iPhone XS</li>
<li class="submenu-item">iPhone XS Max</li>
</ul>
</li>
</ul>
</li>
<li>Samsung</li>
<li>Xiaomi</li>
</ul>
It works somewhat similar to svyaznoy.ru, but have a bug.
For example, I hover on "Apple" menu item. Laptops and iPhones show up. Next I hover on "Laptops". Some apple laptop models show up. And here's where the bug shows: if my mouse pointer doesn't leave "Laptops" item and goes straight to laptops submenu - all is ok, but when it leaves "Laptops" on the way to laptops list, e.g. it hovers on iPhones for a moment, then laptops list hides, and I want it to stay there. How can I fix this bug?
jsfiddle: https://jsfiddle.net/16region/vtrj9wgk/30/

You can change display: none to visibility: hidden and add transition-delay. And so you wont need jquery/js
ul {
list-style-type: none;
padding-left: 0;
}
ul.submenu {
visibility: hidden;
position: absolute;
left: 100%;
top: 1px;
margin-left: -1px;
transition: 0s visibility;
transition-delay: 0.5s;
}
li {
padding: 10px;
border: 1px solid #ddd;
margin-top: -1px;
}
li:hover > ul.submenu {
visibility: visible;
}
li.submenu-item {
min-width: 110px;
}
ul.catalog-menu {
width: 150px;
position: relative;
}
<ul class="catalog-menu">
<li>
<span>Apple</span>
<ul class="submenu">
<li class="submenu-item">
<span>Laptops</span>
<ul class="submenu">
<li class="submenu-item">Macbook 12</li>
<li class="submenu-item">Macbook Pro 13</li>
<li class="submenu-item">Macbook Pro 15</li>
<li class="submenu-item">Macbook Air Retina</li>
</ul>
</li>
<li class="submenu-item">
<span>iPhones</span>
<ul class="submenu">
<li class="submenu-item">iPhone 8</li>
<li class="submenu-item">iPhone 8 Plus</li>
<li class="submenu-item">iPhone X</li>
<li class="submenu-item">iPhone XS</li>
<li class="submenu-item">iPhone XS Max</li>
</ul>
</li>
</ul>
</li>
<li>Samsung</li>
<li>Xiaomi</li>
</ul>

Related

How to add scrolling to fixed left bar with side drop down menu

I'm looking to have a fixed left bar menu, but allow it to scroll if the screen height becomes short.
Here's the fiddle for what I have so far. I understand it is the overflow css that is causing the dropdown menu to not show, but not sure how to fix. I'm a backend dev, not a front end :)
Adding this allows the left menu to scroll, but then the drop down menu doesn't show:
overflow-y: auto;
overflow-x: hidden;
With that commented out, the drop down menu displays as I'd like, but then the left menu doesn't scroll vertically.
My code for reference, but see above fiddle for working example.
Html:
<nav class="cd-side-nav js-cd-side-nav noPrint" style="">
<ul class="cd-side__list js-cd-side__list" id="menu">
<li class="cd-side__item cd-side__item--has-children">
Menu 1
<ul class="cd-side__sub-list">
<li class="cd-side__sub-item">Sub-Menu-1</li>
<li class="cd-side__sub-item">Sub-Menu-2</li>
<li class="cd-side__sub-item">Sub-Menu-3</li>
<li class="cd-side__sub-item">Sub-Menu-4</li>
</ul>
</li>
<li class="cd-side__item cd-side__item--has-children">
Menu 2
<ul class="cd-side__sub-list">
<li class="cd-side__sub-item">Sub-Menu-1</li>
<li class="cd-side__sub-item">Sub-Menu-2</li>
<li class="cd-side__sub-item">Sub-Menu-3</li>
<li class="cd-side__sub-item">Sub-Menu-4</li>
</ul>
</li>
<li class="cd-side__item cd-side__item--has-children">
Menu etc...
<ul class="cd-side__sub-list">
<li class="cd-side__sub-item">Sub-Menu-1</li>
<li class="cd-side__sub-item">Sub-Menu-2</li>
<li class="cd-side__sub-item">Sub-Menu-3</li>
<li class="cd-side__sub-item">Sub-Menu-4</li>
</ul>
</li>
<li class="cd-side__item cd-side__item--has-children">
Menu etc...
<ul class="cd-side__sub-list">
<li class="cd-side__sub-item">Sub-Menu-1</li>
<li class="cd-side__sub-item">Sub-Menu-2</li>
<li class="cd-side__sub-item">Sub-Menu-3</li>
<li class="cd-side__sub-item">Sub-Menu-4</li>
</ul>
</li>
<li class="cd-side__item cd-side__item--has-children">
Menu etc...
<ul class="cd-side__sub-list">
<li class="cd-side__sub-item">Sub-Menu-1</li>
<li class="cd-side__sub-item">Sub-Menu-2</li>
<li class="cd-side__sub-item">Sub-Menu-3</li>
<li class="cd-side__sub-item">Sub-Menu-4</li>
</ul>
</li>
<li class="cd-side__item">
Menu etc...
</li>
<li class="cd-side__item">
Menu etc...
</li>
<li class="cd-side__item">
Menu etc...
</li>
<li class="cd-side__item">
Menu etc...
</li>
<li class="cd-side__item">
Menu etc...
</li>
</ul>
</nav>
CSS:
.cd-side-nav {
top: 0;
left: 0;
height: 100vh;
position: fixed;
width: 200px;
/* with this commented out - drop down menu displays ok - but left menu doesn't scroll*/
/*
overflow-y: auto;
overflow-x: hidden;
*/
}
.cd-side__item {
height:75px;
border: 1px solid grey;
}
.cd-side__sub-list, .cd-nav__sub-list {
background-color: grey;
display: none;
}
.cd-side__item--has-children:not(.cd-side__item--selected).hover .cd-side__sub-list {
display: block;
position: relative;
z-index: 1;
left: 200px;
top: -20px;
width: 200px;
}
and JS to apply hover class to hovered over menu items:
$(document).ready(function() {
$(".cd-side__item--has-children").on({
mouseenter: function () {
$(this).addClass("hover");
},
mouseleave: function () {
$(this).removeClass("hover");
}
});
});
Here is the CSS code to allow the dropdown menu to scroll:
ul.dropdown-menu {
overflow-y: scroll;
}
For the code you provide above, here is the solution:
ul#menu {
overflow-y: scroll;
height: inherit;
}

ui.position.left not working with css margin: 0 auto

I want to build a scrollable menu that should use margin: 0 auto;
Below is my codepen where it is working fine because I didn't use css margin: 0 auto (refer css panel .wrap class).
But this has two issues:
It is not scrolling end to end - Codepen url: codepen.io/VK009/pen/PRKmNP
While using margin: 0 auto; in .wrap and it's stops working properly because of ui.offset.left- Codepen url:- codepen.io/VK009/pen/yKobVP
How can I make the menu use margin: 0 auto and scroll end to end.
Add This CSS on this ID. Hope this will work.
#nav_main{
overflow-x:scroll;
}
Try to use ui.offset instead of ui.position...The idea is here to drag the element using the difference between the parent width and child width...
var parentPos = $('.samNan').offset();
var parentWidth = $('.samNan').outerWidth();
var childWidth = $('.wrap').outerWidth();
var diff = parentWidth - childWidth;
$(".wrap").draggable({
drag: function(event, ui) {
if (ui.offset.left <= parentPos.left && ui.offset.left >= diff + parentPos.left) {
ui.offset.left = parentPos.left;
} else {
return false;
}
},
scroll: false,
axis: "x"
});
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.samNan {
width: 400px;
position: relative;
margin: 0 auto;
overflow: hidden;
border: 1px solid;
}
.wrap {
background: #ccc;
white-space: nowrap;
display: inline-block;
padding: 20px;
}
#nav_main {
margin: 0;
padding: 0;
}
#nav_main li {
display: inline-block;
}
#nav_main li a {
margin: 0 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"></script>
<div class="samNan">
<div class="wrap">
<ul id="nav_main">
<li class="">Menu 1</li>
<li class="">Menu 2</li>
<li class="">Menu 3</li>
<li class="">Menu 4</li>
<li class="">Menu 5</li>
<li class="">Menu 6</li>
<li class="">Menu 7</li>
<li class="">Menu 8</li>
<li class="">Menu 9</li>
<li class="">Menu 10</li>
<li class="">Menu 11</li>
<li class="">Menu 12</li>
<li class="">Menu 13</li>
<li class="">Menu 14</li>
<li class="">Menu 15</li>
</ul>
</div>
</div>

Rotate the arrow as menu is expanded instead of doing at the end of the animation

As soon as I click the menu is expanded and then arrow is rotated. What I want is as soon as I click, menu should expand and arrow should rotate in parallel. How can I achieve that?
$(document).ready(function() {
$(".r-product-page #menu > li > a").click(function() {
$('ul.sub-menu').not($(this).siblings()).slideUp("slow").parents('.product-menu').removeClass('active');
$(this).siblings("ul.sub-menu").slideToggle("slow", function() {
if ($(this).parents('.product-menu').hasClass('active')) {
$(this).parents('.product-menu').removeClass('active')
} else $(this).parents('.product-menu').addClass('active');
});
});
$(".r-product-page #menu #one").click(function() {
$(".product-container").load("productOne.html");
})
});
.r-product-page {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
}
.r-product-page #menu {
height: 100%;
width: 300px;
}
.r-product-page #menu .product-menu {
color: #4d4d49;
font-size: 18px;
}
.r-product-page #menu .product-menu .sub-menu {
display: none;
}
.r-product-page #menu .product-menu .sub-menu li {
color: #898989;
font-family: 18px;
}
ul {
list-style: none;
}
.product-menu .dropdown-arrow {
transition: transform .2s;
}
.product-menu.active .dropdown-arrow {
transform: rotate(180deg)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="r-product-page container">
<ul style="margin-top:5rem;" id="menu">
<li class="product-menu"><img class="dropdown-arrow" src="https://s1.postimg.org/211j5w7oqn/products_dropdown_arrow.png" alt="New york">
template A
<ul class="sub-menu">
<li>x</li>
<li>y</li>
<li>z</li>
<li>l</li>
<li>m</li>
<li>n</li>
</ul>
</li>
<li class="product-menu"><img class="dropdown-arrow" src="https://s1.postimg.org/211j5w7oqn/products_dropdown_arrow.png" alt="New york">
Template B
<ul class="sub-menu">
<li>3.1
</li>
</ul>
</li>
<li class="product-menu" id="one">Template C
</li>
<li class="product-menu">Template D
</li>
<li class="product-menu">Template E
</li>
<li class="product-menu">Template F
</li>
</ul>
<div class="product-container" />
</div>
The issue is because you're toggling the class in the callback of the animation, so it happens when the animation ends. Simply move that logic in to the outer click event handler.
Also note that you can simplify the whole if condition by just calling toggleClass(). Try this:
$(document).ready(function() {
$(".r-product-page #menu > li > a").click(function() {
var $a = $(this);
$('ul.sub-menu').not($a.siblings()).slideUp("slow").closest('.product-menu').removeClass('active');
$a.closest('.product-menu').toggleClass('active');
$a.siblings("ul.sub-menu").slideToggle("slow");
});
$(".r-product-page #menu #one").click(function() {
$(".product-container").load("productOne.html");
})
});
.r-product-page {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
}
.r-product-page #menu {
height: 100%;
width: 300px;
}
.r-product-page #menu .product-menu {
color: #4d4d49;
font-size: 18px;
}
.r-product-page #menu .product-menu .sub-menu {
display: none;
}
.r-product-page #menu .product-menu .sub-menu li {
color: #898989;
font-family: 18px;
}
ul {
list-style: none;
}
.product-menu .dropdown-arrow {
transition: transform .2s;
}
.product-menu.active .dropdown-arrow {
transform: rotate(180deg)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="r-product-page container">
<ul style="margin-top:5rem;" id="menu">
<li class="product-menu"><img class="dropdown-arrow" src="https://s1.postimg.org/211j5w7oqn/products_dropdown_arrow.png" alt="New york">
template A
<ul class="sub-menu">
<li>x</li>
<li>y</li>
<li>z</li>
<li>l</li>
<li>m</li>
<li>n</li>
</ul>
</li>
<li class="product-menu"><img class="dropdown-arrow" src="https://s1.postimg.org/211j5w7oqn/products_dropdown_arrow.png" alt="New york">
Template B
<ul class="sub-menu">
<li>3.1</li>
</ul>
</li>
<li class="product-menu" id="one">Template C</li>
<li class="product-menu">Template D</li>
<li class="product-menu">Template E</li>
<li class="product-menu">Template F</li>
</ul>
<div class="product-container" />
</div>

jQuery slideToggle jump animation on menu toggle

So my problem is just as simple as the title, when I click the big black "V" to toggle my menu, the animation jumps on the <li> with the sub menu.
I tried multiple things and none seem to work, I had a similar issue with the width which I solved by setting width to 100%. On my search I saw people that jQuery can't figure out the height of the elements but if I try to add height to the elements it totaly breaks the menu.
Here's the codepen so you can experience my problem. CODEPEN
HTML
<nav class="main-menu">
<ul>
<li class="level-1">Item 1
<span class="toggle-1">V</span>
<ul class="sub-menu-1">
<li class="level-2">Item 1.1
<span class="toggle-2">V</span>
<ul class="sub-menu-2">
<li class="level-3">Item 1.1.1</li>
<li class="level-3">Item 1.1.2</li>
<li class="level-3">Item 1.1.3</li>
<li class="level-3">Item 1.1.4</li>
</ul>
</li>
<li class="level-2">Item 1.2
<span class="toggle-2">V</span>
<ul class="sub-menu-2">
<li class="level-3">Item 1.2.1</li>
<li class="level-3">Item 1.2.2</li>
</ul>
</li>
<li class="level-2">Item 1.3</li>
</ul>
</li>
<li class="level-1">Item 2
<span class="toggle-1">V</span>
<ul class="sub-menu-1">
<li class="level-2">Item 2.1</li>
<li class="level-2">Item 2.2</li>
<li class="level-2">Item 2.3</li>
<li class="level-2">Item 2.4</li>
<li class="level-2">Item 2.5</li>
</ul>
</li>
<li class="level-1">Item 3</li>
<li class="level-1">BItem 4
<span class="toggle-1">V</span>
<ul class="sub-menu-1">
<li class="level-2">Item 4.1</li>
<li class="level-2">Item 4.2</li>
</ul>
</li>
</ul>
</nav>
CSS
.main-menu .sub-menu-1, .main-menu .sub-menu-2 {
display: none;
}
.main-menu ul {
width: 100%;
}
.main-menu li {
line-height: 25px;
}
.main-menu li.level-1 {
background-color: red;
}
.main-menu li.level-2 {
background-color: lightblue;
}
.main-menu li.level-3 {
background-color: yellow;
}
.main-menu a {
display: block;
margin-right: 20px;
}
.main-menu .toggle-1, .main-menu .toggle-2 {
display: block;
float: right;;
font-size: 20px;
font-weight: bold;
width: 20px;
transform: translateY(-25px);
}
Javascript/jQuery
$(document).ready(function() {
$('.sub-menu-1, .sub-menu-2').hide();
$('.toggle-1').click( function() {
$(this).next('.sub-menu-1').slideToggle();
});
$('.toggle-2').click( function() {
$(this).next('.sub-menu-2').slideToggle();
});
});
Thank you in advance and hope somenone can help me out.
The issue is arising from the <span> that you have set to display: block; in your css.
Switching .main-menu a and .main-menu .toggle-1, .main-menu .toggle-2 to both be display: inline-block; fixes the issue. You can then also remove some additional unnecessary css hacks that you were previously using to forcibly place these elements outside of their document flow position.
The updated CSS is below, and you can see a fork of the pen with both sub-menus working here
.main-menu a {
display: inline-block;
}
.main-menu .toggle-1, .main-menu .toggle-2 {
display: inline-block;
float: right;
font-size: 20px;
font-weight: bold;
width: 20px;
}
I think the only problem is that you didn't set the clear property to your float. If you set it like:
.main-menu a {
margin-right: 20px;
}
.main-menu .toggle-1, .main-menu .toggle-2 {
float: right;
clear: none;
font-size: 20px;
font-weight: bold;
width: 20px;
}
you are good. Then you also don't need the transform: translate to shift your elements back. Here's a fork of your codepen: http://codepen.io/anon/pen/WwbPLV

Jquery show only current parent childrens. Hide another families

Have 3 level menu:
jQuery("#product_cats_nav li").toggle(
function () {
//var current = jQuery(this).closest('.level1');
//jQuery(current).siblings().addClass("hide");
jQuery(this).children().removeClass("hide").addClass("show");
},
function () {
jQuery(this).find("ul").removeClass("show").addClass("hide");
}
);
.hide {
display: none
};
.show {
display: block
};
#top_menu ul {
border: 1px solid red;
background-color: lime ;
position: absolute;
margin: 0;
width: 100%;
z-index: 100;
}
#top_menu li {
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div class="col-full" id="top_menu">
<ul id="product_cats_nav">
<li class="level1" menu-level="1">Level1 A
<ul class="hide">
<li class="level2" menu-level="2">Level2 A
<ul class="hide">
<li class="level3" menu-level="3">
Level3 A</li>
</ul>
</li>
</ul>
</li>
<li class="level1" menu-level="1">Level1 B
<ul class="hide">
<li class="level2" menu-level="2">Level2 B
<ul class="hide">
<li class="level3" menu-level="3">
Level3 B</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
Goal:
When some submenu(level2) or (level1) is clicked and active (opened) close all another level1 childrens.
Current js just toogle one block with another, but not hide elements of another level1 children fammily
In snippet i had comment out my triyings with sibling..
How to solve that?
Is this what you are looking for?
jQuery("#product_cats_nav li").toggle(
function () {
//var current = jQuery(this).closest('.level1');
//jQuery(current).siblings().addClass("hide");
jQuery(this).closest('#product_cats_nav').find('ul').removeClass("show").addClass("hide");
jQuery(this).children().removeClass("hide").addClass("show");
},
function () {
jQuery(this).find("ul").removeClass("show").addClass("hide");
}
);
.hide {
display: none
};
.show {
display: block
};
#top_menu ul {
border: 1px solid red;
background-color: lime ;
position: absolute;
margin: 0;
width: 100%;
z-index: 100;
}
#top_menu li {
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div class="col-full" id="top_menu">
<ul id="product_cats_nav">
<li class="level1" menu-level="1">Level1 A
<ul class="hide">
<li class="level2" menu-level="2">Level2 A
<ul class="hide">
<li class="level3" menu-level="3">
Level3 A</li>
</ul>
</li>
</ul>
</li>
<li class="level1" menu-level="1">Level1 B
<ul class="hide">
<li class="level2" menu-level="2">Level2 B
<ul class="hide">
<li class="level3" menu-level="3">
Level3 B</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>

Categories

Resources