Show all child ULs on hover of any parent LI - css

got a nested LI menu - what I want to be able to do is show all child ULs when any parent LI is hovered over. Ideally in just CSS? but jQuery is OK if not poss in CSS.
Menu code is:
<ul>
<li>Item 1
<ul>
<li>Sub Item 1</li>
<li>Sub Item 2</li>
<li>Sub Item 3</li>
</ul>
</li>
<li>Item 2
<ul>
<li>Sub Item 1</li>
<li>Sub Item 2</li>
<li>Sub Item 3</li>
</ul>
</li>
</ul>
So for example - when Item 1 is hovered over - the submenu ULs for Item 1 AND Item 2 should show... easy? I cant seem to work it out.... :(

Under your current requirements, that the hover of the <li> should show the <ul> child elements of all sibling <li> elements this isn't possible without JavaScript (with or without a library, as CSS lacks the ability to select elements appearing previously in the DOM, including both ancestor-elements and previous siblings); however if you're willing to allow for the hover to take place on the parent <ul> element this becomes possible with simple CSS:
ul > li {
display: list-item;
}
li > ul {
display: none;
}
ul:hover > li > ul {
display: block;
}
JS Fiddle demo.
In the above the use of the child combinator (>) means this will show only the first level of <ul> elements, if that last rule is amended then all <ul> children can be shown:
ul:hover > li ul {
display: block;
}
JS Fiddle demo.

Related

Why does the child selector select all descendants?

The child selector should select the immediate children contained by an element. But in the following code, the selector div > ul > li select all descendant <li> of <div>. I have no idea why the child selector expands its scope?
div>ul>li {
text-decoration: underline;
color: blue;
}
<div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3
<ul>
<li>Item 31</li>
<li>Item 32</li>
</ul>
</li>
</ul>
</div>
If you take a look at the page in Chrome or Firefox's developer tools, you'll see what's happening. The selector isn't applying to the further descendants—instead, they're inheriting the color from their parent.
By default, the color property isn't set. This is equivalent to setting color: inherit;—in other words, it means "since I have no special instructions, I'll do whatever my parent is doing". So when you set a color for an element, it'll also apply to all that element's descendants, unless any of them specify a color of their own.
#Draconis' answer is off to a good start, but the comments suggest there is no solution to the underlining. So here is a solution.
/* Set all list elements to a default value. change this to what you need it to be */
li {
color: black;
text-decoration: none;
}
/* Then set the inner ULs to full width inline-block; which will prevent the
text-decoration from inheriting into them */
div>ul ul {
display:inline-block;
width: calc(100% - 40px);
}
div>ul>li {
text-decoration: underline;
color: blue;
}
<div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3
<ul>
<li>Item 31</li>
<li>Item 32</li>
</ul>
</li>
</ul>
</div>

Ignoring CSS nth-child for submenu li?

I am trying to hide several menu items from my mobile menu using the nth-child selector in CSS.
Here is the source code HTML and CSS: https://jsfiddle.net/jf1r12wh/
The HTML is something like this:
<ul class="mobile">
<li>Item 1</l1>
<li>Item 2</li>
<li>Item 3</li>
<ul><li>Submenu item 1</li>
<li>Submenu item 2</li>
<li>Submenu item 3</li></ul></ul>
I want to use the nth-child (or similar) to hide Item 1 and 2 on the mobile menu, but I don't want it to hide Submenu item 1 and Submenu Item 2, which it's doing.
I'm using this:
.mobile li:nth-child(1){
display: none !important;
}
.mobile li:nth-child(2) {
display: none !important;
}
The problem is that it's applying this to the submenu as well. How can I make it not to do that, and only apply to the main menu items?
All you have to do is show that the rule should only apply to direct children via the use of >
Like this:
.mobile > li:nth-child(2) {
display: none !important;
}
As Paulie_D mentioned in his comment, this is a part of specificity.
EDIT:
Here is a working snippet:
.mobile li:nth-child(1){
color: red;
}
.mobile > li:nth-child(2) {
color: red;
}
<ul class="mobile">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>
<ul>
<li>Submenu item 1</li>
<li>Submenu item 2</li>
<li>Submenu item 3</li>
</ul>
</li>
</ul>
For future reference, I would also like to point out that the correct semantic for a ul inside a ul is for the second ul to be inside it's own li
"The children (direct descendants) of a ul element must all be li elements". I've made sure that my code snippet reflects this for you.

Drop-down list that stays upon click without JS

I want to make my drop down menu stay when user clicks on element. Currently, it displays when user hover over element, like this:
div.nav ul li:hover ul {
display: list-item;
position: absolute;
}
I can change hover selector to active but that will not make the drop-down list stay upon click (releasing click will hide it).
My question is, is it possible to have the drop down stay upon click without javascript?
Yes, this is perfectly possible- you can determine visibility of a sibling list from the checked state of a hidden input:
Option 1, :checked
li,
input:checked + ul {
display: block
}
ul ul,
input {
display: none;
}
<ul>
<li>
<label for="menuTrigger">Item</label>
<input id="menuTrigger" type="checkbox" />
<ul>
<li>Sub item</li>
<li>Sub item</li>
<li>Sub item</li>
</ul>
</li>
</ul>
Option 2, :target
Or alternatively, using the :target pseudo, although depending on your architecture, this may not place nicely with route configuration. Additionally, the list cannot be toggled once shown (except if an alternate :target is initiated).
li,
ul:target {
display: block
}
ul ul,
input {
display: none;
}
<ul>
<li>
Item
<ul id="show">
<li>Sub item</li>
<li>Sub item</li>
<li>Sub item</li>
</ul>
</li>
</ul>

Select Last of Type with CSS

Given the following HTML, what CSS rule would select and ONLY select the line that says TWO?
<ul class="menu">
<li><a>void</a></li>
<li class="active">
<a>one</a>
<ul class="sub-menu">
<li class="active"><a>two</a></li>
<li><a>three</a></li>
</ul>
</li>
</ul>
The following selector doesn't work:
.active:last-of-type {...}
Also, I must clarify that if there is no sub-menu or rather the link in the sub-menu is NOT active, then the parent menu must be selected by the same rule. In other words, given the following HTML, the same rule would highlight the line that says ONE:
<ul class="menu">
<li><a>void</a></li>
<li class="active">
<a>one</a>
<ul class="sub-menu">
<li><a>two</a></li>
<li><a>three</a></li>
</ul>
</li>
</ul>
No single selector statement will match both of your use cases (not until parent selectors are supported, anyway). You would have to include, for example, an additional class in one of those use cases in order to fulfill your requirements without your selector matching all .active elements.
Assuming the following use cases:
Active sub-menu element
<ul class="menu">
<li class="active"><a>one</a></li>
<li>
<ul class="sub-menu">
<li class="active"><a>two</a></li>
<li><a>three</a></li>
</ul>
</li>
</ul>
No active sub-menu element
<ul class="menu no-active-sub-menu">
<li class="active"><a>one</a></li>
<li>
<ul class="sub-menu">
<li><a>two</a></li>
<li><a>three</a></li>
</ul>
</li>
</ul>
The following selectors would work:
.menu .sub-menu > .active,
.menu.no-active-sub-menu > .active {
...
}
ul > ul > li:first-child
but you should nest the child UL inside the li in which case:
ul > li > ul > li:first-child
You can use this
ul ul .active {...}
Going from the code provided
Just use :last-child
ul .active:last-child {
color: green;
}
As was suggested by one of the contributors, the parent required another class to set it apart from the child(ren) menu items for this to work. I am posting my solution in case others are faced with something similar.
This is the HTML when the parent is the active page:
<ul class="menu">
<li><a>void</a></li>
<li class="active">
<a>one (parent, active page)</a>
<ul class="sub-menu">
<li><a>two (child)</a></li>
<li><a>three (child)</a></li>
</ul>
</li>
</ul>
This is the HTML when a child menu item of the parent is the active page:
<ul class="menu">
<li><a>void</a></li>
<li class="active page-parent">
<a>one (parent)</a>
<ul class="sub-menu">
<li class="active"><a>two (child, active page)</a></li>
<li><a>three (child)</a></li>
</ul>
</li>
</ul>
These are the rules I used:
/* Highlights the parent and any child
menu item under the parent when the
parent is the active page. */
ul.menu li.active a {
color: red;
}
/* Keeps the children menu items normal
when the parent is the active page.
Also keeps the parent normal when a
child menu item is the active page. */
ul.menu li.active ul.sub-menu li a,
ul.menu li.active.page-parent a {
color: black;
}
/* Highlights the child menu item that
is active */
ul.menu li.active.page-parent ul.sub-menu li.active a {
color: red;
}
It definitely is straightforward once you identify the parent state with a unique rule when one of its children menu items is active. Obviously, this would be easier if the child items didn't inherit the "active" state from the parent, but the menu system I am using behaves as described here. Thanks to everyone for their contributions.
Note: I have not tested this with a menu containing more than 1 sub-menu level deep.

Simple vertical multilevel menu

I am looking for some really simple vertical multilevel menu, but I did not find anything. My idea of menu is for example like this:
<ul id="menu">
<li>Item 1</li>
<li class="parent">Item 2
<ul>
<li> Sub 1</li>
<li> Sub 2</li>
</ul>
</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5
<ul>
<li> Sub 1</li>
<li> Sub 2</li>
</ul>
</li>
<li>Item 6</li>
And I would like to at first hide all sub categories. And if I click on the some category, the page will load and one the category with class="parent" will show its category. My question is, how can I reach this only with css?
This is basically how a hover menu works; hide the <ul> by default and show it when being hovered.
jsFiddle
#menu li > ul {
display:none;
}
#menu li:hover > ul {
display:block;
}
If you want .parent to show as well just put it in with the hover rule:
jsFiddle
#menu li:hover > ul,
#menu li.parent > ul{
display:block;
}
to hide the sub categories you need to add these to css file
#menu li > ul { display:none;}
#menu ul li ul {display: none;}
#menu ul li.parent ul {display: block;}

Resources