Javascript dropdown for touch devices - javascript

I am trying to make the submenu open and close by class toggle.
WHy is the class on not toggled on click, to hide the submenu?
var u = document.querySelector('ul');
var l = u.querySelectorAll("li");
var a = u.querySelectorAll('li.hasul > a');
for(var i=0; i<a.length;i++){
a[i].addEventListener('click', function(){
l.forEach(function(i,n){
i.classList.remove('on');
});
event.target.parentNode.classList.toggle('on');
});
}
ul{display:flex; list-style:none;}
li{margin:5px;
position: relative;
font-size: 20px;
}
li ul{
border: 1px solid #ccc;
padding: 10px;
position: absolute;
left: 0;
width: 150px;
top: 40px;
display: none;
}
li.on{
border-bottom: 3px solid red;
}
li.on ul{
display: block;
}
a{text-decoration:none;display:block; padding: 5px;}
<ul>
<li class="hasul">Item 1
<ul>
<li>Level 2</li>
<li>Level 2</li>
<li>Level 2</li>
</ul>
</li>
<li class="hasul">Item 2
<ul>
<li>Level 2</li>
<li>Level 2</li>
<li>Level 2</li>
</ul>
</li>
</ul>
https://codepen.io/felixaj/pen/poyyper

You should use the touchstart event, not click for mobiles (check here)

add display:none; to the on css rule

Related

Submenu dissappears on mouse hover

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>

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>

Is there a way to make a <li> dropdown menu function like a <option> choice menu?

I'm working with this code: http://codepen.io/anon/pen/zxMRYG
I'd like the user to be able to click one of the "sub items", and then have that submenu replace the "starting item" (much like a standard choice dropdown box would work).
Is this achievable with the code that I have? Is it logical? Before, I was using "option" tags to achieve this, but I couldn't figure out how to have sub-options, so I switched to this format instead.
here is the code in case codepen isn't working:
HTML
<div style="vertical-align:top;">
<ul class="navbar cf">
<!-- <li>item 2</li> -->
<li style="width:200px;background:222;">starting item
<ul>
<li>sub item 1</li>
<li>sub item 2</li>
<li>sub item 3
<ul>
<li>google</li>
<li>yahoo!</li>
<li>jQuery
<!--
<ul>
<li>sub sub item 1</li>
<li>sub sub item 2
<ul>
<li>sub sub sub item 1</li>
<li>sub sub sub item 2</li>
<li>sub sub sub item 3
<ul>
<li>sub item 1</li>
<li>sub item 2</li>
<li>sub item 3</li>
</ul>
</li>
</ul>
</li>
<li>sub sub item 3</li>
<li>sub sub item 4</li>
<li>sub sub item 5
</li>
</ul>
</li> -->
</ul>
</li>
<li>item a little longer</li>
</ul>
</li>
<!--
<li>item 4</li>
<li>item 5</li> -->
</ul>
</div>
CSS
/* clearfix */
/**
* For modern browsers
* 1. The space content is one way to avoid an Opera bug when the
* contenteditable attribute is included anywhere else in the document.
* Otherwise it causes space to appear at the top and bottom of elements
* that are clearfixed.
* 2. The use of `table` rather than `block` is only necessary if using
* `:before` to contain the top-margins of child elements.
*/
.cf:before,
.cf:after {
content: " "; /* 1 */
display: table; /* 2 */
}
.cf:after {
clear: both;
}
/**
* For IE 6/7 only
* Include this rule to trigger hasLayout and contain floats.
*/
.cf {
*zoom: 1;
}
ul.navbar {background: #222222; /* Old browsers */
/* IE9 SVG, needs conditional override of 'filter' to 'none' */
background: url();
background: -moz-linear-gradient(top, #222222 0%, #161616 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#222222), color-stop(100%,#161616)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #222222 0%,#161616 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #222222 0%,#161616 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #222222 0%,#161616 100%); /* IE10+ */
background: linear-gradient(to bottom, #222222 0%,#161616 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#222222', endColorstr='#161616',GradientType=0 ); /* IE6-8 */
width: 200px;
margin: auto;
border-radius: 3px;
box-shadow: inset 0 1px 0 #555;
}
ul.navbar li {
float: left;
margin: 0;
position: relative;
}
ul.navbar li a {
display: block;
/*padding: 13px 44px;*/
padding:8px 5px;
color: white !important;
text-decoration: none;
text-transform: none;
transition: all .2s ease-in-out;
}
ul.navbar li a:hover,
ul.navbar li:hover > a {
background: #39bae6;
color: #333 !important;
}
ul.navbar li ul {
margin: 0;
padding:0;
position: absolute;
background: #222;
left: em;
font-size: 14px;
min-width: 200px;
opacity: 0;
visibility: hidden;
z-index: 99;
box-shadow: inset 0 2px 3px rgba(0,0,0,.6),
0 5px 10px rgba(0,0,0,.6);
/* transition: all .2s ease-in-out; */
}
ul.navbar li ul li { border-top: 1px solid #2a2a2a; }
ul.navbar li ul li:first-child { border: 0;}
ul.navbar ul li { float: none; }
ul.navbar li:hover > ul { opacity: 1; visibility: visible; left: 0; }
ul.navbar li > ul ul { top: 0; left: 90%; box-shadow: 0 5px 10px rgba(0,0,0,.6);}
ul.navbar li > ul li:hover ul { left: 100%; }
ol, ul { list-style: outside none none; }
JS
// sub menus identification
$(function() {
// $('ul.navbar li ul').parent('li').css('background', 'red');
});
Thank you.
edit: I'm having a bit of problems trying to implement the solution. Here is my full page of HTML:
<!DOCTYPE html>
<!--
-->
<html lang="en">
<head>
<link type="text/css" rel="stylesheet" href="css/styletime.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="js/init.js"></script>
</head>
<body>
<p>Hello?</p>
<div class="wrap">
<div style="vertical-align:top;">
<ul class="navbar cf">
<!-- <li>item 2</li> -->
<li style="width:200px;background:222;">item 3 oh no?
<ul>
<li>sub item 1</li>
<li>sub item 2</li>
<li>sub item 3
<ul>
<li>google</li>
<li>yahoo!</li>
<li>jQuery
<!--
<ul>
<li>sub sub item 1</li>
<li>sub sub item 2
<ul>
<li>sub sub sub item 1</li>
<li>sub sub sub item 2</li>
<li>sub sub sub item 3
<ul>
<li>sub item 1</li>
<li>sub item 2</li>
<li>sub item 3</li>
</ul>
</li>
</ul>
</li>
<li>sub sub item 3</li>
<li>sub sub item 4</li>
<li>sub sub item 5
</li>
</ul>
</li> -->
</ul>
</li>
<li>item a little longer</li>
</ul>
</li>
<!--
<li>item 4</li>
<li>item 5</li> -->
</ul>
</div>
<div class="adder">
<div id="container">
<section id="taskIOSection">
<div id="formContainer">
<form id="taskEntryForm">
<input id="taskInput" style="font-family: Lucida Sans Unicode, Lucida Grande, sans-serif;" placeholder="Add your interests here..." autocomplete="off"/>
</form>
</div>
<ul id="taskList"></ul>
</section>
</div>
</div>
</div>
</body>
</html>
and here is my full init.js page:
/*Adder*/
$(document).ready(function () {
var i = 0;
for (i = 0; i < localStorage.length; i++) {
var taskID = "task-" + i;
$('#taskList').append("<li id='" + taskID + "'>" + localStorage.getItem(taskID) + "</li>");
}
$('#clear').click(function () {
localStorage.clear();
});
$('#taskEntryForm').submit(function () {
if ($('#taskInput').val() !== "") {
var taskID = "task-" + i;
var taskMessage = $('#taskInput').val();
localStorage.setItem(taskID, taskMessage);
$('#taskList').append("<li class='task' id='" + taskID + "'>" + taskMessage + "</li>");
var task = $('#' + taskID);
task.css('display', 'none');
task.slideDown();
$('#taskInput').val("");
i++;
}
return false;
});
$('#taskList').on("click", "li", function (event) {
self = $(this);
taskID = self.attr('id');
localStorage.removeItem(taskID);
self.slideUp('slow', function () {
self.remove();
});
});
});
/*MenuClick*/
$(function() {
$('.navbar > .start-item li > a').click(function(e) {
e.preventDefault();
$('.navbar > .start-item > a').text($(this).text());
});
}
Try something like this:
$('.navbar > .start-item li > a').click(function(e) {
e.preventDefault();
$('.navbar > .start-item > a').text($(this).text());
});
Demo: http://jsfiddle.net/aaqzzd3b/1/
try this:
Updated
// sub menus identification
$(function () {
$(".navbar").on("click", "li", function (event) {
var liElm = $(event.target).closest("li");
$(".navbar .caption").text(liElm.find("a:first").text());
$(".navbar li").removeClass("active");
liElm.addClass("active");
});
});
DEMO

How to Make a Menu Like Stack Overflow's

I really like the way Stack Overflow has done their dropdown menus on the top. Notice how you must click in order for the dropdown to trigger, but you still must hover to get the dropdown. There is also what seems to be groups - once you click, hover will activate the menus shown in the picture. It is hard to explain, but if you play around for a minute you'll see what I mean. Also, it is important that the last hovered menu will show until a user clicks off again.
Here is what I have so far; note that I almost have the same functionality, except for the last menu hovered doesn't stay dropped (it closes on mouseout when it shouldn't until off-click) and the toggle functionality is sketchy:
$(document).ready(function() {
var depressed = false;
$('.menu').click(function() {
depressed = true;
$('.menu').toggleClass('active');
});
$('.menu').hover(function() {
if (depressed) {
$('.menu').toggleClass('active');
}
});
});
ul {
margin: 0;
padding: 0;
}
ul li {
display: inline-block;
padding: 10px 20px;
background: #333;
color: #eee;
}
ul li.active:hover ul {
display: block;
}
ul li ul {
display: none;
position: absolute;
border: 2px solid #555;
}
ul li ul li {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="menu">button 1
<ul>
<li>sub button 1</li>
<li>sub button 2</li>
</ul>
</li>
<li class="menu">button 2
<ul>
<li>sub button 1</li>
<li>sub button 2</li>
</ul>
</li>
<li class="menu">button 3
<ul>
<li>sub button 1</li>
<li>sub button 2</li>
</ul>
</li>
</ul>
My JS is not cuttin git.
So, what is the best way to go about this?
I haven't peeked into the SO menu, so I don't know how they did it. But this seems to work nicely.
A click on one of the buttons opens the dropdown.
The dropdown is not closed by a 'mouseout', like in your code, but only when another menu is hovered. If you hover outside of the menu area, the lastly hovered menu remains open.
Clicking anywhere closes the menu.
So showing the menu is not directly done by using a :hover pseudo element in CSS, but by adding a class, which remains there even when the menu is unhovered. I think the net result behaves pretty close to Stack Overflow's.
$(function(){
// The event to handle clicks outside of the menu. This will close the menu.
var offEvent =
function(event){
$('.menu-bar').removeClass('active');
$(document).off('click', offEvent);
};
// The click event on the menu buttons, to toggle 'menu mode' as it were.
$(document).on('click', '.menu-bar .menu',
function(event){
event.preventDefault();
$('.menu-bar').addClass('active');
$(this).addClass('active');
// Leave menu mode by clicking anywhere of the menu.
$(document).on('click',
offEvent
);
});
// Hover toggles between the dropdowns of the separate menus.
$('.menu-bar .menu').hover(
function(event){
var $current = $(this);
$('.menu').each(
function(index, element){
var $element = $(this);
if ($element.get(0) == $current.get(0)) {
$element.addClass('active');
} else {
$element.removeClass('active');
}
});
});
});
ul {
margin: 0;
padding: 0;
}
ul li {
display: inline-block;
padding: 10px 20px;
background: #333;
color: #eee;
}
ul li ul {
display: none;
position: absolute;
border: 2px solid #555;
}
ul li ul li {
display: block;
}
.menu .dropdown {
display: none;
}
.menu-bar.active .menu.active .dropdown {
display: block;
}
.menu {
display: inline-block;
position: relative;
border: 1px solid grey;
}
.menu .dropdown {
position: absolute;
top: 100%;
left: 0;
border: 2px solid #555;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="menu-bar">
<li class="menu">button 1
<ul class="dropdown">
<li>sub button 1</li>
<li>sub button 2</li>
</ul>
</li>
<li class="menu">button 2
<ul class="dropdown">
<li>sub button 1</li>
<li>sub button 2</li>
</ul>
</li>
<li class="menu">button 3
<ul class="dropdown">
<li>sub button 1</li>
<li>sub button 2</li>
</ul>
</li>
</ul>
$(document).ready(function() {
$('#M1').click(function() {
$('#M1').toggleClass('active');
$('#M2').removeClass('active');
$('#M3').removeClass('active');
});
$('#M2').click(function() {
$('#M2').toggleClass('active');
$('#M1').removeClass('active');
$('#M3').removeClass('active');
});
$('#M3').click(function() {
$('#M3').toggleClass('active');
$('#M1').removeClass('active');
$('#M2').removeClass('active');
});
});
ul {
margin: 0;
padding: 0;
}
ul li {
display: inline-block;
padding: 10px 20px;
background: #333;
color: #eee;
}
ul li.active ul {
display: block;
}
ul li ul {
display: none;
position: absolute;
border: 2px solid #555;
}
ul li ul li {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="menu" id='M1'>button 1
<ul>
<li>sub button 1</li>
<li>sub button 2</li>
</ul>
</li>
<li class="menu" id='M2'>button 2
<ul>
<li>sub button 1</li>
<li>sub button 2</li>
</ul>
</li>
<li class="menu" id='M3'>button 3
<ul>
<li>sub button 1</li>
<li>sub button 2</li>
</ul>
</li>
</ul>
This works for me.
I've just removed :hover from the end of the .active class and made an individual function for each button.

Drop down menu issues

I have a main menu with few sub pages that I want to show in a drop down menu.
I am using CSS to hide all the "ul" that are inside the Main Menu "ul", and show the nested "ul" when hover over the main "ul (li's)"
It is not really working, I simply want to make it that when you hover over a tab from the main menu the sub menu just inside it will show as a drop down menu, and then when you hover out of the drop down menu or hover over anther main menu tab the drop down menu will go away.
Any ideas of how I would do that?
Here is the HTML:
<div id="headerLogo">
<?php include ("assets/templates/header-logo.inc"); ?>
</div>
<nav><ul id="mainMenu"><!--Main Menu-->
<li>Home
<ul>
<li>Intro 1</li>
<li>Intro 2</li>
<li>Intro 3</li>
<li>Vision</li>
<li>Contacts</li>
<li>Staff</li>
<li>Use</li><li>
<li>Crisis</li>
</ul></li>
<li>Basics
<ul>
<li>Definition 1</li>
<li>Definition 2</li>
<li>Definition 3</li>
<li>Assess 1</li>
<li>Assess 2</li>
<li>Assess 3</li>
</ul></li>
<li>Need
<ul>
<li>World 1</li>
<li>World 2</li>
<li>World 3</li>
<li>Polar 1</li>
<li>Polar 2</li>
<li>Polar 3</li>
<li>National 1</li>
<li>National 2</li>
<li>National 3</li>
<li>Alaska 1</li>
<li>Alaska 2</li>
<li>Alaska 3</li>
<li>Alaska 4</li>
<li>Fairbanks</li>
</ul></li>
<li>Models
<ul>
<li>Durkheim</li>
<li>Joiner</li>
<li>NAMI</li>
<li>Mental</li>
<li>Church</li>
<li>Menninger</li>
<li>Weaver/Wright</li>
</ul></li>
<li>Approach
<ul>
<li>Trees 1</li>
<li>Tress 2</li>
<li>Goals 1</li>
<li>Goals 2</li>
<li>Training 1</li>
<li>Training 2</li>
<li>Gas 1</li>
<li>Gas 2</li>
<li>Boat 1</li>
<li>Boat 2</li>
</ul></li>
<li>Library
<ul>
<li>Stories</li>
<li>Books</li>
<li>Plays</li>
<li>Epics</li>
<li>Movies</li>
<li>Articles</li>
</ul></li>
<li>Web
<ul>
<li>Arctic</li>
<li>National</li>
<li>Supports</li>
<li>Reference</li>
</ul></li>
</ul></nav>
</div>
</header>
CSS:
/*Main Menu*/#mainMenu {
margin-top: 10px;
float: right;
}
ul#mainMenu ul {
display: none;
}
ul#mainMenu li:hover > ul {
display: block;
background-color: #F7F7F7;
width: 145px;
position: absolute; top: 100%;
}
ul#mainMenu li ul li {
float: none;
width: 100%;
}
#mainMenu li {
float: left;
}
#mainMenu a {
color: #595959;
width: 100%;
padding: 10px 15px;
margin-left: 5px;
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-webkit-transition: background 0.1s linear;
-moz-transition: background 0.1s linear;
-ms-transition: background 0.1s linear;
-o-transition: background 0.1s linear;
transition: background 0.1s linear;
}
#mainMenu a:hover {
color: #4E6C98;
}
#mainMenu a.active {
color: #ffffff;
background-color: #4E6C98;
cursor: default;
}
Try adding position: relative; on #mainMenu li. Your dropdowns are positioned absolutely but have nothing to be relative to.

Categories

Resources