So I want to make a cool type of drop down menu using jquery, but I dont know how to add anything to the place were I want it.
Basically, there is a button that you press which expands this other div, and then on double click it goes back up. I want the other div to have other div links in it but I don't know how.
Here's my html:
<div id = "one"></div>
<div id = "two"></div>
<div id = "three"></div>
<div id = "four"></div>
<div id = "five"></div>
<div id = "six"></div>
<div id = "one1"></div>
<div id = "two2"></div>
<div id = "three3"></div>
<div id = "four4"></div>
<div id = "five5"></div>
<div id = "six6"></div>
Here's my jquery (ignore the comments and arrows):
$('#one1').click(function(){
$('#one').animate({height: '200px'}, "fast");
$('body').append('<div id = "tester"></div>');
});
$('#two2').click(function(){
$('#two').animate({height: '200px'}, "fast");
});
$('#three3').click(function(){
$('#three').animate({height: '200px'}, "fast");
});
$('#four4').click(function(){
$('#four').animate({height: '200px'}, "fast");
});
$('#five5').click(function(){
$('#five').animate({height: '200px'}, "fast");
});
$('#six6').click(function(){
$('#six').animate({height: '200px'}, "fast");
});
I created a plain navBar which I think it is what you are trying to do.
This may help as a jumpstart to add the animation you want: check JsFiddle here
Html
<nav>
<ul>
<li>Home</li>
<li class="dropdown">About
<ul>
<li>About us</li>
<li>About the company</li>
<li>More</li>
</ul>
</li>
<li>Contact</li>
</ul>
</nav>
CSS
nav > ul {
padding: 0;
margin: 0;
float: left;
}
nav > ul > li {
padding: 0;
margin: 0;
list-style: none;
float: left;
position: relative;
}
nav > ul > li.dropdown > ul {
display: none;
position: absolute;
top: 100%;
width: 200px;
background: #BF0A64;
margin: 0;
padding: 0;
}
nav > ul > li.dropdown > ul > li {
margin: 0;
padding: 0;
list-style: none;
}
nav > ul > li.dropdown > ul > li > a {
display: block;
padding: 10px;
color: #FFF;
text-decoration: none;
}
nav > ul > li.dropdown > ul > li > a:hover {
background: #FFF;
color: #BF0A64;
}
nav > ul > li.dropdown.active a {
background: #BF0A64;
}
nav > ul > li.dropdown.active > ul {
display: block;
}
nav > ul > li > a {
padding: 20px;
color: #FFF;
background: #E80C7A;
text-decoration: none;
display: block;
}
nav > ul > li > a:hover {
background: #BF0A64;
}
nav:after,
div:after {
clear: both;
}
Javascript
(function() {
var dropdowns = document.getElementsByClassName('dropdown');
function init() {
for (var i = 0; i < dropdowns.length; i++) {
var item = dropdowns[i];
item.onclick = showOrHideSubmenu;
}
}
function showOrHideSubmenu() {
// hideAllActives(this);
this.classList.toggle('active');
}
function hideAllActives() {
for (var i = 0; i < dropdowns.length; i++) {
var item = dropdowns[i];
if (hasClass(item, 'active')) {
item.classList.toggle('active');
}
}
}
function hasClass(element, cls) {
return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
init();
}());
You need something like this :
$('div').click(function(){
$(this).animate({height: '200px'}, "fast");
}).dblclick(function(){
$(this).animate({height: '0px'}, "fast");
});
Example : https://jsfiddle.net/DinoMyte/vxn3ozzb/6/
Related
I created a multi level basic navigation menu using pure JS and trying to find a logic to collapse a submenu when other submenu is opened. I used foreach to loop all menus which has submenu. But don't know how to detect other menu while a menu is clicked. Can anyone help me on this. Thanks in Advance!
/* toggle click function for submenus */
slideToggle=(el)=> {
let cs = window.getComputedStyle(el).display;
if(cs==="none") {
el.style.display="block";
}
else {
el.style.display="none";
}
}
/* detecting menus which has submenus */
submenuDetect=()=> {
let li = document.querySelectorAll(".main-navigation-content > ul li");
/* adding a class "has-submenu" for menu which has sublevel menu */
li.forEach((item)=>{
let ul = item.querySelector("ul");
if(ul){
item.classList.add("has-submenu");
ul.classList.add("submenu-content");
/* adding icon */
let iconElement = document.createElement("span");
iconElement.setAttribute("class","down-arrow-icon submenu-trigger");
item.querySelector("a").insertAdjacentElement("afterend", iconElement);
}
});
}
/* assign toggle function to menu which has submenus */
submenuToggle=()=>{
/* find all menu which has submenus and making toggle */
let submenuTrigger = document.querySelectorAll(".has-submenu > a");
submenuTrigger.forEach((item)=>{
item.addEventListener("click",(e)=>{
e.preventDefault();
let submenuContent = e.target.parentElement.querySelector('.submenu-content');
slideToggle(submenuContent);
})
});
}
/* calling submenu detect function and slidetoggle function */
submenuDetect();
submenuToggle();
body {font-family: Arial, Helvetica, sans-serif;;}
.main-navigation-content ul {list-style: none;margin:0;padding:0;transition:all 0.35s ease;}
.main-navigation-content ul li {border:1px solid #cdcdcd;margin-bottom: -1px;/* margin-left: -1px; *//* margin-right: -1px; */background: #f5f5f5;/* margin: -1px; *//* height: 2.5rem; */}
.main-navigation-content ul li a {text-decoration: none;line-height: 2.5rem;padding-left: .5rem;color: #555;display: flex;align-items: center;justify-content: space-between;position: relative;z-index: 1;padding-right: .5rem;transition:all 0.35s ease;/* width: 100%; */height: 2.5rem;flex-grow: 1;}
.main-navigation-content ul li ul li {margin-left: -1px;margin-right: -1px;}
.down-arrow-icon {width: 2.5rem;display: flex;height: 2.5rem;align-items: center;justify-content: center;position: absolute;z-index: 0;right: 0;top: 0;cursor: pointer;margin-right: 0;line-height: 2.5rem;/* background: red; */}
.down-arrow-icon:after { content:""; width: .03rem; height: .03rem; background-color: transparent; border: solid black; border-width: 0 2px 2px 0; display: inline-block; padding: 3px; transform: rotate(45deg); -webkit-transform: rotate(45deg); position: absolute; top: 35%;}
.navigation-master-wrapper {border: 1px solid #cdcdcd; width: auto;background: #f9f9f9;height: 500px;overflow-y: auto;}
.main-navigation {position: relative; height: auto;}
.main-navigation-trigger {margin-left: auto;position: relative;cursor: pointer;left: auto;right: .25rem;display: inline-block;padding: 0;font-size: 12px;top: 0;z-index: 100;margin-bottom: .5rem;display: none;}
.main-navigation-content { display:none;}
.main-navigation-content > ul { list-style: none;padding: 0;margin: 0;}
.main-navigation-content > ul li { position: relative;}
.main-navigation-content .submenu-content {display: none;}
#media only screen and (min-width:800px) {
.main-navigation-content > ul li .submenu-content li a {padding-left:2rem;}
.main-navigation-content > ul li .submenu-content li ul li a {padding-left:3rem}
.main-navigation-content > ul li .submenu-content {margin-top:1px;background: #fff;}
.main-navigation-content > ul li .submenu-content li ul {margin-top:0;}
.main-navigation-content {display:block !important;width: 20rem;}
.main-navigation-content > ul li > ul {top:100%;}
.main-navigation-content > ul li {position: initial;}
.main-navigation-content > ul > li {position: relative;}
.main-navigation-content > ul > li a {/* padding-left: 1rem; *//* padding-right: 1rem; */}
.main-navigation-content > ul li > ul li {position:relative;background: #fff;}
.main-navigation-content > ul li ul {transition:all 0.35s ease;}
}
<div class="main-navigation">
<div class="main-navigation-trigger">
<div class="main-navigation-trigger-inner"></div>
</div>
<div class="main-navigation-content">
<ul>
<li>Home</li>
<li>About Us
<ul>
<li>History and Foundation</li>
<li>Company Overview</li>
<li>Working Strategy
<ul>
<li>Employer Profile</li>
<li>Manpower Allocation</li>
<li>Marketing Strategy</li>
</ul>
</li>
</ul>
</li>
<li>Services
<ul>
<li>Graphic Designing</li>
<li>Web Designing</li>
<li>App Development
<ul>
<li>Android</li>
<li>IOS</li>
<li>Hybrid</li>
</ul>
</li>
</ul>
</li>
<li>Contact</li>
</ul>
</div>
</div>
I tried to understand your code to improve it, but gave up on the idea after several hours. However, in order not to give up on yourself, here is a workaround you can use...
I hope at least that my code will help you in the future to simplify yours.
const menu =
[ { lib: 'Home', link: '#Home' }
, { lib: 'About Us', link: '#About', sub:
[ { lib: 'History and Foundation', link: '#History' }
, { lib: 'Company Overview', link: '#Company' }
, { lib: 'Working Strategy', link: '#Working', sub:
[ { lib: 'Employer Profile', link: '#Employer' }
, { lib: 'Manpower Allocation', link: '#Manpower' }
, { lib: 'Marketing Strategy', link: '#Marketing' }
] } ] }
, { lib: 'Services', link: '#Services', sub:
[ { lib: 'Graphic Designing', link: '#Graphic' }
, { lib: 'Web Designing', link: '#Web' }
, { lib: 'App Development', link: '#App', sub:
[ { lib: 'Android', link: '#Android' }
, { lib: 'IOS', link: '#IOS' }
, { lib: 'Hybrid', link: '#Hybrid' }
] } ] }
, { lib: 'Contact', link: '#Contact' }
]
const navMenu = document.querySelector('div.main-nav')
const OpenMenus = [] // to memorize DOM (li.show) menus opened
function makeMenu( nav, jso )
{
let eUL = nav.appendChild( document.createElement('ul') )
for (const row of jso)
{
let eLI = eUL.appendChild( document.createElement('li') )
, lnk = eLI.appendChild( document.createElement('a') )
;
lnk.textContent = row.lib
lnk.href = row.link
if (!!row.sub)
{
eLI.className = 'submenu'
makeMenu(eLI,row.sub)
}
}
}
makeMenu( navMenu, menu )
navMenu.addEventListener('click', (e)=>
{
if (!e.target.matches('li.submenu > a')) return
e.preventDefault()
let level = 0
, eLI = e.target.closest('li')
, eUL = e.target.closest('ul')
, mOpen = eLI.classList.toggle('show')
;
for(;;level++) // get menu Level
{
eUL = eUL.parentElement.closest('ul')
if (!eUL || !eUL.matches('div.main-nav ul')) break
}
for(let i = OpenMenus.length; (--i) > level;) // close all < sub levels
{
OpenMenus.pop().classList.remove('show')
}
if (OpenMenus[level] && OpenMenus[level] != eLI )
OpenMenus.pop().classList.remove('show')
if (mOpen) OpenMenus.push(eLI) // memorize adding menu opened
else OpenMenus.pop() // or remove it.
})
body { background: steelblue; font-family: Arial, Helvetica, sans-serif; }
.main-nav * {
box-sizing : border-box;
}
.main-nav {
width : 20rem;
border-bottom : 1px solid #fbfbfb;
}
.main-nav ul {
list-style : none;
margin : 0;
padding : 0;
}
.main-nav a {
display : block;
width : 100%;
border : 1px solid #fbfbfb;
border-bottom : none;
background : #c7c7c7;
text-decoration : none;
line-height : 2.5rem;
padding : 0 .5rem;
color : #2a2a2a;
}
.main-nav a:hover {
background: #ebebeb;
}
.main-nav ul ul a { padding-left:2rem; background: #d5d5d5; }
.main-nav ul ul ul a { padding-left:3rem; background: #e1e1e1; }
.main-nav li.submenu > ul {
max-height : 0;
transition : max-height 0.25s ease-out;
overflow : hidden;
}
.main-nav li.submenu > a::after {
display : block;
float : right;
content : '\276F'; /*'\1405'; */
transition : 180ms;
transform : rotate(90deg);
}
.main-nav li.submenu.show > ul {
max-height : 500px;
transition : max-height 0.35s ease-in;
}
.main-nav li.submenu.show > a {
padding-right : .7rem; /* because '\276F' is not symetric ! */
}
.main-nav li.submenu.show > a::after {
transform : rotate(-90deg);
}
<div class="main-nav"></div>
Hello Friends Bitski and Mister Jojo, at last i found a solution and it is as follows. Please take a look and let me know your comments on how can i improve it. Thank You for both of your valuable time to spend for me. Thank You Guys!!!
/* toggle click function for submenus */
slideToggle = (el) => {
let cs = window.getComputedStyle(el).display;
if (cs === "none") {
el.style.display = "block";
}
else {
el.style.display = "none";
}
}
/* detecting menus which has submenus */
submenuDetect=()=> {
let li = document.querySelectorAll(".main-navigation-content > ul li");
/* adding a class "has-submenu" for menu which has sublevel menu */
li.forEach((item)=>{
let ul = item.querySelector("ul");
if(ul){
item.classList.add("has-submenu");
ul.classList.add("submenu-content");
/* adding icon */
let iconElement = document.createElement("span");
iconElement.setAttribute("class","down-arrow-icon");
item.querySelector("a").insertAdjacentElement("afterend", iconElement);
}
});
}
let secondlevelToggle=()=>{
let secondlevelSubmenus = document.querySelectorAll(".submenu-content .has-submenu > a");
secondlevelSubmenus.forEach((el)=>{
el.addEventListener("click",(e)=>{
e.preventDefault();
e.stopPropagation();
let submenuContent = e.target.parentElement.querySelector(".submenu-content");
let submenuContentCS = window.getComputedStyle(submenuContent).display;
if(submenuContentCS==="none") {
submenuContent.style.display="block";
}
else {
submenuContent.style.display="none";
}
});
});
}
/* assign toggle function to menu which has submenus */
submenuToggle = () => {
/* find all menu which has submenus and making toggle */
let submenuTrigger = document.querySelectorAll(".has-submenu > a");
submenuTrigger.forEach((item) => {
item.addEventListener("click", (e) => {
e.stopPropagation();
e.preventDefault();
let allSubmenuContent = document.querySelectorAll(".main-navigation-content > ul > li > .submenu-content");
allSubmenuContent.forEach((el) => {
/* Current Submenu */
let referingSubmenu = e.currentTarget.parentElement.querySelector(".main-navigation-content > ul > .has-submenu > .submenu-content");
let referingSubmenuCS = window.getComputedStyle(referingSubmenu).display;
console.log(referingSubmenuCS);
if (referingSubmenuCS === "none") {
allSubmenuContent.forEach((elem) => {
if (window.getComputedStyle(elem).display === "block") {
elem.style.display = "none";
}
})
referingSubmenu.style.display = "block";
}
else {
referingSubmenu.style.display = "none";
}
});
});
});
}
submenuDetect();
submenuToggle();
secondlevelToggle();
body {font-family: Arial, Helvetica, sans-serif;;}
.main-navigation-content ul {list-style: none;margin:0;padding:0;transition:all 0.35s ease;}
.main-navigation-content ul li {border:1px solid #cdcdcd;margin-bottom: -1px;/* margin-left: -1px; *//* margin-right: -1px; */background: #f5f5f5;/* margin: -1px; *//* height: 2.5rem; */}
.main-navigation-content ul li a {text-decoration: none;line-height: 2.5rem;padding-left: .5rem;color: #555;display: flex;align-items: center;justify-content: space-between;position: relative;z-index: 1;padding-right: .5rem;transition:all 0.35s ease;/* width: 100%; */height: 2.5rem;flex-grow: 1;}
.main-navigation-content ul li ul li {margin-left: -1px;margin-right: -1px;}
.down-arrow-icon {width: 2.5rem;display: flex;height: 2.5rem;align-items: center;justify-content: center;position: absolute;z-index: 0;right: 0;top: 0;cursor: pointer;margin-right: 0;line-height: 2.5rem;/* background: red; */}
.down-arrow-icon:after { content:""; width: .03rem; height: .03rem; background-color: transparent; border: solid black; border-width: 0 2px 2px 0; display: inline-block; padding: 3px; transform: rotate(45deg); -webkit-transform: rotate(45deg); position: absolute; top: 35%;}
.navigation-master-wrapper {border: 1px solid #cdcdcd; width: auto;background: #f9f9f9;height: 500px;overflow-y: auto;}
.main-navigation {position: relative; height: auto;}
.main-navigation-trigger {margin-left: auto;position: relative;cursor: pointer;left: auto;right: .25rem;display: inline-block;padding: 0;font-size: 12px;top: 0;z-index: 100;margin-bottom: .5rem;display: none;}
.main-navigation-content { display:none;}
.main-navigation-content > ul { list-style: none;padding: 0;margin: 0;}
.main-navigation-content > ul li { position: relative;}
.main-navigation-content .submenu-content {display: none;}
#media only screen and (min-width:800px) {
.main-navigation-content > ul li .submenu-content li a {padding-left:2rem;}
.main-navigation-content > ul li .submenu-content li ul li a {padding-left:3rem}
.main-navigation-content > ul li .submenu-content {margin-top:1px;background: #fff;}
.main-navigation-content > ul li .submenu-content li ul {margin-top:0;}
.main-navigation-content {display:block !important;width: 20rem;}
.main-navigation-content > ul li > ul {top:100%;}
.main-navigation-content > ul li {position: initial;}
.main-navigation-content > ul > li {position: relative;}
.main-navigation-content > ul > li a {/* padding-left: 1rem; *//* padding-right: 1rem; */}
.main-navigation-content > ul li > ul li {position:relative;background: #fff;}
.main-navigation-content > ul li ul {transition:all 0.35s ease;}
}
<div class="main-navigation">
<div class="main-navigation-trigger">
<div class="main-navigation-trigger-inner"></div>
</div>
<div class="main-navigation-content">
<ul>
<li>Home</li>
<li>Features
<ul>
<li>Graphic Designing</li>
<li>Web Designing</li>
<li>App Development
<ul>
<li>Android</li>
<li>IOS</li>
<li>Hybrid</li>
</ul>
</li>
</ul>
</li>
<li>About Us
<ul>
<li>History and Foundation</li>
<li>Company Overview</li>
<li>Working Strategy
<ul>
<li>Employer Profile</li>
<li>Manpower Allocation</li>
<li>Marketing Strategy</li>
</ul>
</li>
</ul>
</li>
<li>Services
<ul>
<li>Graphic Designing</li>
<li>Web Designing</li>
<li>App Development
<ul>
<li>Android</li>
<li>IOS</li>
<li>Hybrid</li>
</ul>
</li>
</ul>
</li>
<li>Contact</li>
</ul>
</div>
</div>
You need to loop over your menus 2 times to:
set click-eventListeners (you did that ok it seems with submenuToggle()), but the callback of the click event listeners needs a fix. It needs the clicked link's parent <li> element set as argument.
Argument:
<li> // submenu's parent list element, set as argument
Working Strategy // link with set click
<ul> // submenu to display or hide
Edited event listener:
item.addEventListener("click",(e)=>{
e.preventDefault();
let linkParentListElement = e.parentElement;
slideToggle(linkParentListElement);
});
set every submenus display-property according to if its sibling <a> got clicked or not. I would do the 2. loop within a dedicated method such as your initial slideToggle(linkParentListElement). Make it loop over the <li> with submenu children with the method forEach().
Within the callback of that method, compare each item if it is the one with the clicked link inside aka if it is linkParentListElement:
if (true): set style of its direct child <ul> to display: block;,
if (false): set style of its direct child <ul> to display: none;.
/* toggle click function for submenus */
slideToggle=(el)=> {
let submenuParentListElement = el,
listItems = document.querySelectorAll('div > ul > li > ul > li');
listItems.forEach(function(el) {
if (el === linkParentListElement) {
// set display: block to its direct child <ul>
} else {
// set display: block to its direct child <ul>
}
});
}
I have a sticky sidebar like this:
<ul class = "cars">
<li class=""> BMW </li>
......
<li class=""> Mersedes </li>
</ul>
And table like this:
<div class="element-title" id="car-category-1">BMW</div>
.....
<div class="element-title" id="car-category-2">Mersedes</div>
Now what I am trying to do:
Scrolling through the <div id="car-category-1> should change the class of <li> of BMW to .active
Same for Mersedes, if scroll through <div id="car-category-2> then change <li> with Mersedes to active.
this is jquery for click scroll
$(document).on('click', '.model', function () {
var this_id = $(this).data('id');
var gotom = setInterval(function () {
cars_go_to_navtab(this_id);
clearInterval(gotom);
}, 400);
$('.cars li').removeClass('active');
$(this).parent().addClass('active');
});
function cars_go_to_navtab(id) {
var scrolling_div = $('#car-category-' + id);
$('html, body').animate({
scrollTop: scrolling_div.offset().top - 70
}, 500);
}
There is a great article of CSS-Tricks for a pure CSS solution (not sure that it is suitable to your use-case) which also has a link to another great article that uses Intersection Observer. In short, place something like this in your code:
const observer = new IntersectionObserver(entries =>
{
for (const entry of entries) {
if (entry.isIntersecting) {
// add css style here
}
else {
// remove css style here
}
});
observer.observe(document.querySelector('#your-element-selector'));
Also, please mind support table over different browsers (canIuse to the rescue)
A simple implementation using Jquery. Also, explore the possibilities of Intersection Observer API
$(document).on("scroll", function() {
var scrollPos = $(document).scrollTop();
$('#menu a').each(function() {
var currLink = $(this);
var refElement = $(currLink.attr("href"));
if (refElement.position().top <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
$('#menu ul li a').removeClass("active");
currLink.addClass("active");
} else {
currLink.removeClass("active");
}
});
});
* {
margin: 0;
padding: 0;
}
.container {
display: flex;
font-family: helvetica, sans-serif;
}
.content {
flex: 1;
padding-left: 200px;
}
.section {
background-color: grey;
height: 100vh;
width: 100%;
overflow: hidden;
padding: 20px;
box-sizing: border-box;
}
#menu {
position: fixed;
top: 0;
background: #444;
width: 200px;
}
#menu a {
padding: 10px;
display: flex;
color: #FFF;
text-decoration: none;
}
h1 {
font-size: 30px;
color: #FFF;
}
.active {
background: #4CAF50;
color: #FFF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="container">
<div id="menu">
<ul>
<li><a class="active" href="#bmw">BMW</a>
</li>
<li>Mercedes</li>
</ul>
</div>
<div class="content">
<div class="section" id="bmw">
<h1>
BMW
</h1>
</div>
<div class="section" id="mercedes">
<h1>
Mercedes
</h1>
</div>
</div>
</div>
I have a navigation of lets say 12 items, and when resolution gets smaller items drop in a new line. I need to make that when an item doesn't fit on a navigation anymore it should put a "MORE" dropdown button on the right side of nav. and put that item that doesn't fit in a dropdown.
If you don't understand me there is image below.
But the problem is that navigation items aren't always the same width because navigation items are generated from REST api.
I tryed to make jQuery script for calculating items width and adding them to navigation.
Here is the script I created, I made it in a hurry so it's really bad.
I need to help on how to properly calculate items witdh and navigation width and calculating when to add items to navigation or remove items from navigation.
Here is image if you don't get it: http://img.hr/aagV
/*
* Here we check how many items can we put on the navigation bar
* If item doesn't fit we clone it on the more dropdown button
*/
function removeMany() {
var i = $items.length - 1;
if (itemsWidth > navWidth) {
while (itemsWidth > navWidth) {
$($items[i]).removeClass('first-level-item').addClass('second-level-item');
dropdownItems.push($items[i]);
$($items[i]).removeClass('showed');
$items.pop();
i--;
getItemsWidth();
}
$nav.append($navMore);
dropdownItems.reverse().forEach(function (element, index, array) {
$('ul.second-level').append(element);
});
getItems();
}
}
//If window is resized to bigger resolution we need to put back items on the navbar
function addMany() {
var i = dropdownItems.length - 1;
if (dropdownItems.length != 0) {
do {
$('ul.first-level').append(dropdownItems.reverse()[i]);
$items.push(dropdownItems[i]);
dropdownItems.pop();
i--;
getItemsWidth();
} while (itemsWidth < navWidth);
$navMore.remove();
$items.each(function (i) {
$(this).addClass('first-level-item showed').removeClass('second-level-item');
});
if (!(dropdownItems != 0)) {
return;
} else {
$nav.append($navMore);
}
}
}
body {
margin: 0;
padding: 0;
border: 0; }
ul, li {
margin: 0;
padding: 0;
list-style: none; }
ul.second-level li {
display: block !important; }
ul.second-level li > a {
color: black; }
a {
color: #fff;
text-decoration: none;
text-transform: uppercase; }
.second-level-item a {
color: #333 !important; }
.navigation {
width: 960px;
max-width: 100%;
background: #211;
color: #aaa;
margin: 0 auto; }
.first-level .first-level-item {
display: inline-block;
padding: 10px; }
.first-level .item-more {
display: inline-block; }
.first-level .item-more .second-level-item {
display: inline-block; }
.second-level {
position: absolute;
top: 100%;
right: 0;
width: 200px;
background: #fff;
padding: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4); }
.has-second-level {
position: relative; }
.has-second-level .second-level {
display: none; }
.has-second-level:hover {
background: #fff;
color: #000; }
.has-second-level:hover .second-level {
display: block; }
/*# sourceMappingURL=style.css.map */
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DropDown</title>
<link rel="stylesheet" href="css/reset.css"/>
<link rel="stylesheet" href="css/style.css"/>
</head>
<body>
<nav class="navigation">
<ul class="first-level">
<li class="first-level-item showed">Introduction to Irish Culture</li>
<li class="first-level-item showed">Cellular and Molecular Neurobiology</li>
<li class="first-level-item showed">Guitar foundations</li>
<li class="first-level-item showed">Startup Inovation</li>
<li class="first-level-item showed">Astrophysics</li>
<li class="first-level-item item-more has-second-level">
<span> More </span>
<ul class="second-level">
</ul>
</li>
</ul>
</nav>
<script src="https://code.jquery.com/jquery-2.1.1.js"></script>
</body>
</html>
If you have fixed-width list-items, then it is simple to collect extra list-items and push them into a separate list. Here is a simple example. Explanation is in the code comments.
View the snippet in full-screen and try changing the window width.
Also a Fiddle: http://jsfiddle.net/abhitalks/860LzgLL/
Full Screen: http://jsfiddle.net/abhitalks/860LzgLL/embedded/result/
Snippet:
var elemWidth, fitCount, fixedWidth = 120,
$menu = $("ul#menu"), $collectedSet;
// Assuming that the list-items are of fixed-width.
collect();
$(window).resize(collect);
function collect() {
// Get the container width
elemWidth = $menu.width();
// Calculate how many list-items can be accomodated in that width
fitCount = Math.floor(elemWidth / fixedWidth) - 1;
// Create a new set of list-items more than the fit count
$collectedSet = $menu.children(":gt(" + fitCount + ")");
// Empty the collection submenu and add the cloned collection set
$("#submenu").empty().append($collectedSet.clone());
}
* { box-sizing: border-box; margin: 0; padding: 0; }
div { position: relative; background-color: #ccc; height: 32px; overflow: visible; }
ul#menu, ol { height: 32px; max-width: 80%; overflow: hidden; }
ul#menu > li, ol > li { display: block; float: left; height: 32px; width: 120px; padding: 4px 8px; }
ol { position: absolute; right: 0; top: 0; overflow: visible; }
ol > li { min-width: 120px; }
ol ul { position: absolute; top: 120%; right: 10%; }
ol li ul > li { list-style: none; background-color: #eee; border: 1px solid gray; padding: 4px 8px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul id="menu">
<li>Option One</li><li>Option Two</li><li>Option Three</li>
<li>Option Four</li><li>Option Five</li><li>Option Six</li>
</ul>
<ol><li>Collected<ul id="submenu"></ul></li></ol>
</div>
Update:
This is regarding your query on differing / variable widths of list-items. There would be a minor change.
Also a Fiddle: http://jsfiddle.net/abhitalks/tkbmcupt/1/
Full Screen: http://jsfiddle.net/abhitalks/tkbmcupt/1/embedded/result/
Snippet:
var elemWidth, fitCount, varWidth = 0, ctr, $menu = $("ul#menu"), $collectedSet;
// Get static values here first
ctr = $menu.children().length; // number of children will not change
$menu.children().each(function() {
varWidth += $(this).outerWidth(); // widths will not change, so just a total
});
collect(); // fire first collection on page load
$(window).resize(collect); // fire collection on window resize
function collect() {
elemWidth = $menu.width(); // width of menu
// Calculate fitCount on the total width this time
fitCount = Math.floor((elemWidth / varWidth) * ctr) - 1;
// Reset display and width on all list-items
$menu.children().css({"display": "block", "width": "auto"});
// Make a set of collected list-items based on fitCount
$collectedSet = $menu.children(":gt(" + fitCount + ")");
// Empty the more menu and add the collected items
$("#submenu").empty().append($collectedSet.clone());
// Set display to none and width to 0 on collection,
// because they are not visible anyway.
$collectedSet.css({"display": "none", "width": "0"});
}
* { box-sizing: border-box; margin: 0; padding: 0; }
div { position: relative; background-color: #ccc; height: 32px; overflow: visible; }
ul#menu, ol { height: 32px; max-width: 80%; overflow: hidden; }
ul#menu > li, ol > li { display: block; float: left; height: 32px; white-space: nowrap; padding: 4px 8px; }
ol { position: absolute; right: 0; top: 0; overflow: visible; }
ol > li { min-width: 120px; }
ol ul { position: absolute; top: 120%; right: 10%; }
ol li ul > li { list-style: none; background-color: #eee; border: 1px solid gray; padding: 4px 8px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul id="menu">
<li>Option One</li><li>Option Two</li><li>Option Three</li>
<li>Option Four</li><li>Option Five</li><li>Option Six</li>
</ul>
<ol><li>Collected<ul id="submenu"></ul></li></ol>
</div>
Can and SHOULD be optimised (as it is quite inefficient from what i've tested), but that's up to you.
$(document).ready(function(){
var moreW = $(".more").outerWidth(), //width of your "more" element
totalW = -moreW, //cumulated width of list elements
totalN = $('.nav li').length - 1, //number of elements minus the "more" element
dw = document.documentElement.clientWidth;
$('.nav li').each(function(){
totalW += $(this).outerWidth();
});
function moveToDropdown(){
dw = document.documentElement.clientWidth;
//moves elements into the list
while(totalW > (dw - moreW)){
var temp = $(".nav li:nth-last-child(2)"); //element to be moved
totalW = totalW - temp.outerWidth();
$(".dropdown").append(temp.clone());
temp.remove();
}
//moves elements out of the list
var newList = $('.dropdown li').length; //check if we have elements
if(newList > 0){
var element = $('.dropdown li:last-child'), //element to be moved
elementW = $('.dropdown li:last-child').outerWidth(); //width of element to be moved
if(totalW + elementW < dw - moreW){
while(totalW + elementW < dw - moreW ){
var element = $('.dropdown li:last-child'),
elementW = $('.dropdown li:last-child').outerWidth();
totalW = totalW + elementW;
$(".nav > li:last-child").before(element.clone());
element.remove();
}
}
}
}
moveToDropdown();
$(window).resize(moveToDropdown)
});
.clearfix:after{
display:block;
content:'';
clear:both;
}
body,html{
width:100%;
height:100%;
margin:0;
padding:0;
}
ul{
list-style:none;
width:100%;
padding:0;
margin:0;
}
ul li{
float:left;
padding:5px;
}
.nav > li {
position:relative;
}
.nav ul{
position:absolute;
top:25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav clearfix">
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li class="more">
more
<ul class="dropdown">
<!-- we'll add elements here -->
</ul>
</li>
</ul>
This question is too old, but i want to post my answer too. Maybe this is more cleaner and easier way. I have created a pen: https://codepen.io/sergi95/pen/bmNoML
<div id="mainMenu" class="main-menu">
<ul id="autoNav" class="main-nav">
<li>
home
</li>
<li>
about us
</li>
<li>
portfolio
</li>
<li>
team
</li>
<li>
blog
</li>
<li>
contact
</li>
<li id="autoNavMore" class="auto-nav-more">
more
<ul id="autoNavMoreList" class="auto-nav-more-list">
<li>
policy
</li>
</ul>
</li>
</ul>
const $mainMenu = $("#mainMenu");
const $autoNav = $("#autoNav");
const $autoNavMore = $("#autoNavMore");
const $autoNavMoreList = $("#autoNavMoreList");
autoNavMore = () => {
let childNumber = 2;
if($(window).width() >= 320) {
// GET MENU AND NAV WIDTH
const $menuWidth = $mainMenu.width();
const $autoNavWidth = $autoNav.width();
if($autoNavWidth > $menuWidth) {
// CODE FIRES WHEN WINDOW SIZE GOES DOWN
$autoNav.children(`li:nth-last-child(${childNumber})`).prependTo($autoNavMoreList);
autoNavMore();
} else {
// CODE FIRES WHEN WINDOW SIZE GOES UP
const $autoNavMoreFirst = $autoNavMoreList.children('li:first-child').width();
// CHECK IF ITEM HAS ENOUGH SPACE TO PLACE IN MENU
if(($autoNavWidth + $autoNavMoreFirst) < $menuWidth) {
$autoNavMoreList.children('li:first-child').insertBefore($autoNavMore);
}
}
if($autoNavMoreList.children().length > 0) {
$autoNavMore.show();
childNumber = 2;
} else {
$autoNavMore.hide();
childNumber = 1;
}
}
}
// INIT
autoNavMore();
$(window).resize(autoNavMore);
.main-menu {
max-width: 800px;
}
.main-nav {
display: inline-flex;
padding: 0;
list-style: none;
}
.main-nav li a {
padding: 10px;
text-transform: capitalize;
white-space: nowrap;
font-size: 30px;
font-family: sans-serif;
text-decoration: none;
}
.more-btn {
color: red;
}
.auto-nav-more {
position: relative;
}
.auto-nav-more-list {
position: absolute;
right: 0;
opacity: 0;
visibility: hidden;
transition: 0.2s;
text-align: right;
padding: 0;
list-style: none;
background: grey;
border-radius: 4px;
}
.auto-nav-more:hover .auto-nav-more-list {
opacity: 1;
visibility: visible;
}
The script that Abhitalks made did not work properly for different element sizes. I modified the code a little bit do that it does:
$(function() {
function makeMenuFit() {
//Get data
var menuSize = menu.width();
//Determine how many items that fit
var menuTotalWidth = 0;
var itemThatFit = 0;
for(var i = 0; i < menuItems.length; i++) {
menuTotalWidth += menuItems[i];
if(menuTotalWidth <= menuSize) {
itemThatFit++;
continue;
}
break;
}
menu.children().css({"display": "block", "width": "auto"});
var collectedSet = menu.children(":gt(" + (itemThatFit - 1) + ")");
$("#submenu").empty().append(collectedSet.clone());
collectedSet.css({"display": "none", "width": "0"});
}
var menu = $(".tabletNavigation > ul");
var menuItems = [];
menu.children().each(function() {
menuItems.push($(this).outerWidth());
});
$(window).resize(makeMenuFit);
makeMenuFit();
});
I want to check when i click on the Download Drivers, the other li shold open, and when i click again on Download Drivers, it should close again. No hovers just onclick. I also dont want it to close when i click on some of the li underneath the Download drivers
Here's my HMTL:
<ul class="dropdown">
<li><a id="drivers" onclick="dropdown(this); return false;" class="dir">Download Drivers</a>
<ul id="driversmenu" class="sub">
<li><a>Download Drivers</a></li>
<li><a>Driver Widget</a></li>
<li><a>NVIDIA Software</a></li>
</ul>
</li>
</ul>
Here's the Javascript code:
function dropdown(obj)
{
alert("klik");
var elements = document.getElementsByClassName("sub");
var ids = '';
for (var i = 0; i < elements.length; i++)
{
document.getElementById(elements[i].id).style.display = 'none';
}
if (document.getElementById(obj.id + 'menu').style.display == 'block')
{
alert("al open");
document.getElementById(obj.id + 'menu').style.display = 'hidden';
}
else if (document.getElementById(obj.id + 'menu').style.display = 'hidden')
{
alert("niet open");
document.getElementById(obj.id + 'menu').style.display = 'block';
}
return false;
};
And the css, but i don't know if it is relevant:
ul.dropdown { list-style-type: none; width: 300px;float: left; height: 0px; margin-top: 0px; padding-left: 0px; }
ul.dropdown a { display: block; color: white; text-decoration: none; list-style-type: none; }
ul.dropdown li { float: left; padding: 0 0px; border: 1px dotted #d0d0d0; list-style-type: none;}
ul.dropdown li ul { display: none; position: absolute; z-index: 99; }
ul.dropdown li ul li { clear: both; margin-left: 0px; padding-left: 0px; border: 0; min-width: 150px; }
ul.dropdown li ul li:hover { background-color: #d1d1d1; }
ul.dropdown li ul li:hover a { color: red; }
I only get the the alert from "Klik" and "Niet open",
so this one never calls:
if (document.getElementById(obj.id + 'menu').style.display == 'block')
{
alert("al open");
document.getElementById(obj.id + 'menu').style.display = 'hidden';
}
Does someone know what i am doing wrong?
Thanks in advance
Try
function dropdown(obj)
{
var elements = document.getElementsByClassName("sub");
var ids = '', display = document.getElementById(obj.id+'menu').style.display;
for(var i=0; i < elements.length; i++) {
elements[i].style.display='none';
}
if(!display || display=='none'){
document.getElementById(obj.id+'menu').style.display='block';
}
return false;
};
Demo: Fiddle
i try to add dynamic content to tabs and hide content if tab is empty
html code
<ul id="tabs">
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
</ul>
<div id="content_tabs">
<div id="tab1">content 1</div>
<div id="tab2">content 2</div>
<div id="tab3">content 3</div>
<div id="tab4">content 4</div>
</div>
js code
function resetTabs(){
jQuery("#content_tabs > div").hide(); //Hide all content
jQuery("#tabs a").attr("id",""); //Reset id's
}
var myUrl = window.location.href; //get URL
var myUrlTab = myUrl.substring(myUrl.indexOf("#")); // For mywebsite. com/tabs.html#tab2, myUrlTab = #tab2
var myUrlTabName = myUrlTab.substring(0,4); // For the above example, myUrlTabName = #tab
jQuery(function(){
jQuery("#content_tabs > div").hide(); // Initially hide all content
jQuery("#tabs li:first a").attr("id","current"); // Activate first tab
jQuery("#content_tabs > div:first").fadeIn(); // Show first tab content
jQuery("#tabs a").on("click",function(e) {
e.preventDefault();
if (jQuery(this).attr("id") == "current"){ //detection for current tab
return
}
else{
resetTabs();
jQuery(this).attr("id","current"); // Activate this
jQuery(jQuery(this).attr('name')).fadeIn(); // Show content for current tab
}
});
for (i = 1; i <= $("#tabs li").length; i++) {
if (myUrlTab == myUrlTabName + i) {
resetTabs();
jQuery("a[name='"+myUrlTab+"']").attr("id","current"); // Activate url tab
jQuery(myUrlTab).fadeIn(); // Show url tab content
}
}
});
beauty css
#tabs {
overflow: hidden;
width: 100%;
margin: 0;
padding: 0;
list-style: none;
}
#tabs li {
float: left;
margin: 0 -15px 0 0;
}
#tabs a {
float: left;
position: relative;
padding: 0 40px;
height: 0;
line-height: 30px;
text-transform: uppercase;
text-decoration: none;
color: #fff;
border-right: 30px solid transparent;
border-bottom: 30px solid #3D3D3D;
border-bottom-color: #777\9;
opacity: .3;
filter: alpha(opacity=30);
}
#tabs a:hover,
#tabs a:focus {
border-bottom-color: #2ac7e1;
opacity: 1;
filter: alpha(opacity=100);
}
#tabs a:focus {
outline: 0;
}
#tabs #current {
z-index: 3;
border-bottom-color: #3d3d3d;
opacity: 1;
filter: alpha(opacity=100);
}
here demo
http://jsfiddle.net/uVNFp/95/
appreciate if someone know how I do to hide content if tab is empty
Thanks
http://jsfiddle.net/tdf22/1/
Changes from your original fiddle:
Removed contents of <div id="tab2">.
Added the following.
$("#content_tabs > div:empty").each(function() {
$("#tabs > li").eq($(this).index()).hide();
});
EDIT:
In response to your comment about blank space, I created this fiddle:
http://jsfiddle.net/tdf22/3/
In this one, I:
added the following jQuery custom expression
$.expr[":"].emptyOrWhiteSpace = function(obj){
var $this = $(obj);
return ($.trim($this.html()) === "");
};
and changed this line
$("#content_tabs > div:empty").each(function() {
to this
$("#content_tabs > div:emptyOrWhiteSpace").each(function() {
Gustavo, this is just a quick answer I put together so that you have something working. This can be accomplished in a more professional manner. http://jsfiddle.net/tdf22/8/
I simply added this at the bottom of your javascript:
var tabs = $('#tabs li');
for (var i=0; i<tabs.length; ++i) {
if (tabs[i].style.display !== 'none') {
tabs[i].firstChild.id = 'current';
$('#tab'+(i+1)).show();
return false;
}
}
var El = document.getElementById("El"); //replace
If(El.hasChildNodes()) {
El.style.display = "block";
} else {
El.style.display = "none";
}