Simplest JQuery animated navbar with multi-level dropdowns - javascript

I'm creating a navbar for a website and I need a very simple way of creating the drop-downs for 2 levels going from the main bar to a drop-down list with a further drop-down level.
I'm using JQuery with no extra plugins.
By "Simplest", I mean with the fewest lines of code and the fewest variables and so the fastest loading time.
I have tried using the hover() event but this does not seem to work.
Here is an example of the HTML:
<div class="menu">
<ul>
<li>Link 1</li>
<li>Link 2
<ul class="sub">
<li>Sub 1
<ul class="sub2">
<li>Sub 2</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
Ideally, hovering over "Link 2" will have the child list slide down, and hovering over "Sub 1" will have the child list slide down next to it.
Also, I'm using percentages for most of the dimensions so it would be really useful if this scaled the same way.
If any more information is needed then ask before down-voting please.
Thanks.

The best jQuery is no jQuery.
.menu input {
position: absolute;
left: -9999px;
}
.menu label {
cursor: pointer;
display: block;
}
.menu label:after {
content: '...';
}
.sub {
display: none;
}
.menu label:hover+input+.sub,
.menu input:checked+.sub,
.sub:hover {
display: block;
}
<div class="menu">
<ul>
<li>Link 1</li>
<li>
<label for="menu-2">Link 2</label>
<input type="checkbox" id="menu-2" />
<ul class="sub">
<li>
<label for="menu-2-1">Sub 1</label>
<input type="checkbox" id="menu-2-1" />
<ul class="sub">
<li>Sub 2</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
Add further CSS as necessary.

Related

how to create "see more" button [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I want to add "See more"button as below image:
here is my code :
<div class="main">
<ul class="list">
<li class="items">Friends </li>
<li class="items">Saved </li>
<li class="items">Pages </li>
<li class="items">Gruop </li>
<li class="items">Ad center</li>
<li class="items">Campus</li>
</ul>
</div>
I want when the length of the li tag document.querySelectorAll('.items').length > 4 then a button "See more" will appear to see the rest of the li card:
So are there any ways to do it, someone please help me. Thanks
Doing it with just CSS
.seeMoreCB,
.seeMoreCB + .list > .items:nth-child(n + 5) {
display: none;
}
.seeMoreCB:checked + .list > .seeMoreLi {
display: none;
}
.seeMoreCB:checked + .list > .items:nth-child(n + 5) {
display: list-item;
}
<div class="main">
<input type="checkbox" id="seeMoreCB" class="seeMoreCB" />
<ul class="list">
<li class="items">Friends </li>
<li class="items">Saved </li>
<li class="items">Pages </li>
<li class="items">Gruop </li>
<li class="seeMoreLi"><label for="seeMoreCB">See More</label></li>
<li class="items">Ad center</li>
<li class="items">Campus</li>
</ul>
</div>
When using a framework like react or angular that generates your html you would probably do the filtering on the list. However it looks like you want to use plain javascript. You could create the entire list and use classes on the ul tag to hide or show the extra elements.
Here the elements that are initially hidden have the class 'extra'. The ul element has the 'collapsed' class to start with. Clicking 'more' and 'less' toggle the collapsed and expanded classes on the ul element.
const ul = document.querySelector('ul.list');
const more = document.querySelector('ul.list > li.more');
const less = document.querySelector('ul.list > li.less');
more.addEventListener('click', event => {
ul.classList.remove('collapsed');
ul.classList.add('expanded');
});
less.addEventListener('click', event => {
ul.classList.add('collapsed');
ul.classList.remove('expanded');
});
.list.collapsed > .extra {
display: none;
}
.list.expanded > .more {
display: none;
}
.list > .more {
cursor: pointer;
}
.list > .less {
cursor: pointer;
}
<ul class="list collapsed">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li class="more">< more ></li>
<li class="extra">Item 5</li>
<li class="extra">Item 6</li>
<li class="extra">Item 7</li>
<li class="extra">Item 8</li>
<li class="extra">Item 9</li>
<li class="extra less">< less ></li>
</ul>

jQuery create an expandable unordered list with ul li with extra span tag

I would like to create an expandable tree with unordered list. The deepness is not limited in my case.
I have to keep the text in the list elements as it is, this way I need to add an extra span element to every parent to have a clickable item.
I have tried to add this span tag with jQuery, and this finds the li objects, but in the result only the first occurrance is visible.
The HTML code is this.
<ul class="list">
<li>
Categories
<ul>
<li>
Parent
<ul>
<li>link 1 link 2 link 3</li>
<li>link 1 link 2 link 3</li>
</ul>
</li>
<li>
Parent
<ul>
<li><a>Child 1</a></li>
<li><a>Child 2</a></li>
<li><a>Child 3</a></li>
</ul>
</li>
</ul>
</li>
</ul>
My jQuery script is below.
$(document).ready(function(){
$(".list").each(function () {
$(this).find('li').each(function(index, element){
var text = $(this).html();
text = "<span class=\"trigger\">+</span> " + text;
$(element).html(text);
});
});
$('.list > li span').click(function(){
$(this).parent().children('ul').toggle();
if($(this).text() == '+') {
$(this).text('-');
}
else {
$(this).text('+');
}
});
});
jsFiddle: https://jsfiddle.net/pegapega/2f20s90v/
My expected result would be for every li element:
<li><span class="trigger">+</span>[original content]</li>
Why the span element is not added to all of the li elements?
I'm unsure exactly why your code example didn't work, but here is an example that does work based on you original.
$('li').each(function(i, e){
$(e).prepend('<span class="trigger">+</span>');
});
$('span').on('click', function(e){
$(e.target).next('ul').toggleClass('show');
if( $(e.target).text() == '+') {
$(e.target).text('-');
} else {
$(e.target).text('+');
}
});
span.trigger {
cursor: pointer;
}
ul {
display: none;
list-style-type: none;
padding-left: 30px;
font-size: 18px;
font-family: "Open Sans", sans-serif;
}
ul.show {
display: block;
}
ul.list {
display: inline;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list">
<li>
Root
<ul>
<li>
Parent
<ul>
<li>link 1 link 2 link 3</li>
<li>link 1 link 2 link 3</li>
</ul>
</li>
<li>
Parent
<ul>
<li><a>Child 1</a></li>
<li><a>Child 2</a></li>
<li><a>Child 3</a></li>
</ul>
</li>
</ul>
</li>
</ul>
Stackoverflows snippet editor seemed to have some problem with toggle() so I just replaced it with toggleClass() just so the example would work.

Multiple level selection bar

I am trying to do a multilevel selection bar. But I am not sure how to create this type of bar. I have tried to use the common navigation bar method, but is doesn't work out the way i wanted.
I want to do something like this, and here is the photo for references:
Any suggestion on how to do it? Or any similar examples? (Please show in fiddle example.)
Thank you!
You want to create a multi-level unordered list, with each list item that has children, containing another unordered list. E.G.
<ul class="parent">
<li>
Category
<ul class="child">
<li>
Sub-category
<ul class="grandchild">
<li>
Sub-sub-category
<ul class="great-grandchild">
<li>
sub-sub-sub category
</li>
</ul>
</li>
</ul>
</li>
<li>
Sub-category 2
</li>
</ul>
</li>
<li>Category 2</li>
<li>Category 3</li>
<li>Category 4</li>
<li>Category 5</li>
</ul>
then you would hide all of the children/grandchildren etc with css, and show them on parent:hover/active
ul:not('.parent') {
display: none;
}
ul.parent > li:hover > ul,
ul.child > li:hover > ul,
ul.grandchild > li:hover > ul,
ul.great-grandchild > li:hover > ul {
display: block;
}

DropDown list disappearing before user can the move mouse pointer to it

I have a menu with list items Home and Home 2. When I hover my mouse over "Home"/"Home 2", the dropdown list appears for the item as expected. However, when I am moving my mouse down to the dropdown list, the list disappears immediately and I cant get access to the dropdown menu.
I want the drop down list to be visible while moving my mouse down to the dropdown list preferably using jQuery. However, I cant get it to work.
The HTML Layout for the design is:
<ul class="mega">
<li class="grid">Home
<ul>
<li>DD Item 1</li>
<li>DD Item 2</li>
<li>DD Item 3</li>
</ul>
</li>
<li class="grid">Home2
<div class="dropDownClass"">
<ul>
<li>DD Item 4</li>
<li>DD Item 5</li>
<li>DD Item 6</li>
</ul>
</div>
</li> </ul>
Any help will be much appreciated.
Thanks
I would do something like this.
HTML:
<ul class="mega">
<li class="grid">Home
<ul>
<li>DD Item 1</li>
<li>DD Item 2</li>
<li>DD Item 3</li>
</ul>
</li>
<li class="grid">Home2
<ul>
<li>DD Item 4</li>
<li>DD Item 5</li>
<li>DD Item 6</li>
</ul>
</li>
CSS:
ul{
list-style-type: none;
}
.mega{
width: 200px;
}
.grid{
padding: 10px 15px;
background-color:gray;
color: white;
border: 1px solid black;
}
.grid ul{
display: none;
}
.grid:hover > ul{
display: inline;
}
Check out this fiddle to see it in action.
You need to setup your CSS to resemble this:
ul{list-style: none; padding: 3px; margin:0}
li ul{display:none;}
li.grid:hover ul{display:block}
This will hide the second ul until the li is hovered.
Add this in your document.ready function:
$('.grid1 ul').hide();
$('.grid2 ul').hide();
$('.grid1').on('mouseover', function() {
$('.grid1 ul').show();
$('.grid1').on('mouseout', function() {
$('.grid1 ul').hide();
});
});
$('.grid2').on('mouseover', function() {
$('.grid2 ul').show();
$('.grid2').on('mouseout', function() {
$('.grid2 ul').hide();
});
});
and change the value of the class attributes of the two <li> elements from both being grid to one of them being grid1 and the other being grid2.

HTML/CSS: what's a better option for layout of a tree of nested elements than nested tables?

Ok, I have a set of checkboxes for selecting criteria. For argument's sake, we'll say the data looks like this:
[] Vehicles
[] Unpowered
[] Bicycle
[] Skateboard
[] Powered
[] Two-wheeled
[] Motorcycle
[] Scooter
[] Four-wheeled
etc
The []s represent checkboxes.
Ignoring the obviously contrived nature of this example, the idea is this:
To start with, only the Vehicle checkbox is visible;
If the user clicks on the Vehicle checkbox is opsn up the next level (Powered, Unpowered);
If the user selects Powered it opens up the next level (Two-wheeled, Four-wheeled);
If the user then unchecks Powered, that level disappears.
Now this is relatively easy to set up with onclick's toggling the display CSS attribute between block and none.
This is currently structured on the page as:
<table>
<tr>
<td><input type="checkbox" onclick="toggle('__Vehicles');"></td>
<td>Vehicles
<table id="__Vehicles">
<tr>
<td><input type="checkbox"></td>
<td>Unpowered
etc
I should point out before someone asks: the reason the checkbox was put in table cell was to control formatting. It made it easy to effectively indent since everything in the next table cell would line up.
It all works fine but the table nesting gets pretty deep. I keep thinking there has to be a better way than this. It has to be able to be easily built dynamically and have good cross-browser support for formatting of the "tree".
I should also mention that jQuery is available. I'm using it for other things.
Suggestions?
Edit: Yes the checkbox styling is important as a couple of comments have noted. Also, I have posted a solution to this, based on the responses I've gotten, as an answer below (too big to add here), just for those curious to see an example.
<ul>
<li><input type="checkbox" />Vehicles <ul>
<li><input type="checkbox" />Unpowered</li>
<li><input type="checkbox" />Bicycle</li>
<li><input type="checkbox" />Skateboard</li>
</ul></li>
<li><input type="checkbox" />Powered <ul>
<li><input type="checkbox" />Two-wheeled <ul>
<li><input type="checkbox" />Motorcycle</li>
<li><input type="checkbox" />Scooter</li>
</ul></li>
<li><input type="checkbox" />Four-wheeled</li>
</ul></li>
</ul>
Edit: a little css & js to show & hide nested elements (no checkboxes)
li.opened ul {
display: block;
}
li.closed ul {
display: none;
}
and js...
$(document).ready(function() {
$('li input:checkbox').click(function () {
$(this).parent().toggleClass('opened');
$(this).parent().toggleClass('closed');
});
$('li').addClass('closed');
});
edit, again, because Sparr wants some better styles (assuming that the checkboxes have a style of "checkbox"
li input.checkbox { /* input:checkbox is not 100% compatible */
width: 6px;
margin: 0 2px;
/* This makes 10px be the total "width" ofh the checkbox */
}
ul {
margin: 0 0 0 10px; /* Or whatever your total checkbox width is */
padding: 0;
}
li {
padding: 0;
}
You could do this:
<ul>
<li>
<input type="checkbox" /> Option 1
<ul>
<li><input type="checkbox" /> Option 1 Sub Option A</li>
</ul>
</li>
</ul>
You'd then set the padding/margin of the UL's to 0 and 0. Then set the padding-left of the LI's to 10px.
ul {
margin:0;
padding:0;
}
li {
margin:0;
padding:0 0 0 20px; /* Each nested li will be padded incrementally */
}
For the javascript, attach an event to each checkbox that determines whether the sibling UL (if any exists) should be visible. If the box is checked, show it, else, hide it.
Nested unordered lists are best practice for this sort of thing.
<ul>
<li>Item 1</li>
<li>Item 2
<ul>
<li>Sub Item 1</li>
<li>Sub Item 2</li>
<li>Sub Item 3</li>
</ul>
</li>
<li>Item 3</li>
<li>Item 4
<ul>
<li>Sub Item 1</li>
<li>Sub Item 2</li>
<li>Sub Item 3</li>
</ul>
</li>
</ul>
Wanna see some deep jQuery magic?
<ul class="tree">
<li><input type="checkbox" name="Vehicles" checked>Vehicles
<ul>
<li<input type="checkbox" name="Unpowered">Unpowered
<ul>
<li><input type="checkbox" name="Bicycle">Bicycle</li>
<li><input type="checkbox" name="Skateboard">Skateboard</li>
</ul>
</li>
<li><input type="checkbox" name="Powered" checked>Powered
<ul>
<li><input type="checkbox" name="Two-wheeled">Two-wheeled
<ul>
<li><input type="checkbox" name="Motorcycle" checked>Motorcycle</li>
<li><input type="checkbox" name="Scooter">Scooter</li>
</ul>
</li>
<li><input type="checkbox" name="Two-Wheeled">Four-wheeled</li>
</ul>
</ul>
</li>
</ul>
Note: the only decoration here is the tree class.
ul.tree {
list-style-type: none;
margin: 0 0 0 -22px;
padding: 0;
}
ul.tree ul {
list-style-type: none;
margin: 0;
padding: 0;
}
ul.tree input {
margin-right: 6px;
}
ul.tree li {
padding: 0 0 0 22px;
margin: 1px;
}
.closed ul {
display: none;
}
and the magic:
$(function() {
$("ul.tree li:has(ul) > :checkbox").click(function() {
jQuery(this).parent().toggleClass('closed');
}).not(":checked").parent().addClass("closed");
});
That turns the entire thing into a working opening and closing tree as you click on checkboxes. Awesome.
Thanks to davethegr8, Jonathon Sampson and others for advice.
I have to chime in to suggest that you extract the javascript out from your markup, in addition to the suggestions above. Using a library such as lowpro (a favorite of mine), you can create 1 object to handle your nested checkbox behavior, and have it automatically applied, unobtrusively. Packaging up your code like this makes your markup easier to maintain, and your code easier and quicker to write, more powerful, and more easily maintained.
Tables are for tabular data. Use nested lists instead and CSS for formatting.
If you're looking for a complete solution, here's one using pure CSS for modern browsers and JavaScript for IE:
<style>
ul.tree, ul.tree ul {
position: relative;
list-style: none;
margin: 0 0 0 20px;
padding: 0;
}
ul.tree input {
position: absolute;
margin-left: -20px;
}
ul.tree ul {
display: none;
}
ul.tree input:checked ~ ul {
display: block;
}
ul.tree label:hover {
text-decoration: underline;
}
</style>
<ul class="tree">
<li>
<input type="checkbox" id="option1">
<label for="option1">Option 1</label>
<ul>
<li>
<input type="checkbox" id="option1a">
<label for="option1a">Option 1 Sub Option A</label>
</li>
<li>
<input type="checkbox" id="option1b">
<label for="option1b">Option 1 Sub Option B</label>
</li>
</ul>
</li>
<li>
<input type="checkbox" id="option2">
<label for="option2">Option 2</label>
</li>
</ul>
<!--[if lte IE 7]>
<script>
var tree = document.getElementsByTagName('ul')[0];
tree.attachEvent('onclick', function() {
var src = event.srcElement;
if(src.nodeName.toLowerCase() === 'label')
var box = document.getElementById(src.htmlFor);
else if(src.nodeName.toLowerCase() === 'input')
var box = src;
else return;
for(var current = src.nextSibling;
current && current.nodeName.toLowerCase() !== 'ul';
current = current.nextSibling);
if(current)
current.style.display = box.checked ? 'block' : 'none';
});
</script>
<![endif]-->
Assumes that a checkbox is not wider that 20px.
While the jQuery plugin mcDropdown approaches the nested list problem in a different way (no checkboxes), it may be suitable for your needs.
when creating cb's give them a css class depending on the level
<input class="LevelXcb" type="checkbox" />
CSS:
.Level0cb{left:4px;}
.Level1cb{left:16px;}
.Level2cb{left:28px;}
if "left" does not work, try setting "margin-left".
I know this isn't much related to the question, so pls don't up vote is just a sugestion.
In this example from davethegr8:
<ul>
<li>Vehicles <ul>
<li>Unpowered</li>
<li>Bicycle</li>
<li>Skateboard</li>
</ul></li>
<li>Powered <ul>
<li>Two-wheeled <ul>
<li>Motorcycle</li>
<li>Scooter</li>
</ul></li>
<li>Four-wheeled</li>
</ul></li>
</ul>
If you give each step a class, you can use jquery to make some cool drop down efects with on click:
Like
$("li.Two-wheeled").click(function(event){
$("div.main_wrapper ul.Moto_or_scooter:hidden").slideDown("slow");
}
Just a small sugestion though :)
If the width of the checkboxes is still an issue (after all previous answers...) you can either:
Put all checkboxes in a fixed with box so you know exactly where the text is beginning (and the next level checkbox)
Use some jquery calculations to get the width and set the margins of the other elements dynamically (seems a bit much though...)
Using the suggested nested list structure obviously.

Categories

Resources