I have some lists on my page that are nested, and I’m having an issue with styling them the way I want. When each list item is hovered, I want the background of the item to be a colour and for the text the change from black to white, or blue to white depending on if it’s a link or not. I can get this to work fine, but what I DON’T want is for the parent to a submenu to highlight ALL the links inside of it when the parent is hovered over. For instance, say I have a list-item called ‘home’ that opens a sublist inside of it. I would only want ‘home’ the change it’s text and background-color on hover, but what’s happening is every single link in the submenu is changed when ‘home’ is hovered over. I know why this happens, but I want to know how to stop it. I’ve tried it with closing the initial lists tag, but that’s not the right way to do it and it screws up the styling of the lists anyways. Is there anyway I can achieve what I want? I have noticed this seems to only happen if the start of the nested link is a link. Below is a snippet of the lists I’m trying to work with. (I’ve changed the link hover to grey so you can hopefully see what I’m talking about.)
.filesubmenu {
display: block;
position: absolute;
width: 164px;
top: 0;
left: 0;
background-color: #bdbebd;
border-top: 1px #dedfde solid;
border-right: 1px #000 solid;
border-bottom: 1px #000 solid;
border-left: 1px #dedfde solid;
outline: 1px #fff outset;
outline-offset: -2px;
}
.filestab ul li {
display: block;
padding-right: 16px;
padding-left: 5px;
width: calc(100% - 1px);
height: 20px;
text-align: left;
font-family: "Arial";
font-size: 12px;
}
.filestab ul li:hover {
background-color: #00007b;
color: #fff;
}
.filestab ul li a {
color: #0000ff;
}
.filestab ul li:hover a {
color: #fff;
}
.filepop1,
.filepop2 {
display: block;
position: absolute;
outline: white 1px outset;
outline-offset: -2px;
border-right: 1px #000 solid;
border-top: 1px #dedfde solid;
border-left: 1px #dedfde solid;
border-bottom: 1px #000 solid;
background-color: #bdbebd;
width: 164px;
left: calc(100% - 3px);
top: -1px;
}
<div class="filestab">
<ul class="filesubmenu">
<li><span>I'm an example submenu!</span></li>
<li><span>Example</span></li>
<li><span><a href="">Example with link</a></span></li>
<li><span>Example</span>
<ul class="filepop1">
<li><span><a href="">Example with link</a></span></li>
<li><span><a href="#">Example with link</a></span></li>
<li><span>Example</span>
<ul class="filepop2">
<li><span><a href="">Example with link</a></span></li>
<li><span><a href="#">Example with link</a></span></li>
<li><span>Example</span></li>
<li><span>Example</span></li>
</ul>
</li>
<li><span>Example</span></li>
</ul>
</li>
<li><span>Example</span></li>
<li><span>Example</span></li>
<li><span>Example</span></li>
<li><span>Example</span></li>
</ul>
</div>
<!-- FILESTAB -->
I have tried almost every way to style lists and links that I can possibly think of, and NOTHING has worked 🙁
2
Answers
There are some problems in your approach…
<li> height problem (and being display:inline by default)
First of all you set the
height
of theli
elements.. despite they might have inline contents (spans) that won’t consume actual height so their container won’t grow accordingly.You have to change that! Otherwhise you will have list items with a short fixed height, containing further lists inside that will overlap.
To make sure such problem won’t occur, just style the
<li>
elements withdisplay: inline-block
and don’t set anyheight
. If you want to control the height of the label of each list item, just style the label not its parent<li>
,Styling the label for each <li>
But more importantly you want to style the
li
, but the side effect will be affecting its all content. If you instead wished to style only the name listed next to the list item, you should target that element instead in your css selectors. That way you’ll make sure to "highlight" only that specific label instead of the whole container holding deeper trees.Use specific selectors for better parent > children relationships
Plus since the parent relationship described by
ul li
will match also with any tree involving stuff inbetween you want to make sure your selector match one category only, by using the direct child operator>
by doing.filestab ul > li > span
.https://developer.mozilla.org/en-US/docs/Web/CSS/:first-child
In the end to estabilish a very strict condition for your label to be determined given a
li
I would suggest it being the very first child instead of any children by doing.filestab ul > li > span:first-child
.Using :has to specifically style li > span with anchors
Then following the same route, to discriminate when such label contains an anchor you may just use the
:has
pseudo-class.filestab ul > li > span:first-child:has(a)
.https://developer.mozilla.org/en-US/docs/Web/CSS/:has
Here follow 2 demos where all the problems described above were addressed, and two distinct strategies were used…
Demo 1 – Using your own html styled with :has
Here I highly simplified your demo.. the only side effect is not having one of your
<li>
engaged by the style, because its span is not the first child.To solve that scenario, you’ll need to stick with the decided convention of having the first span as your label, and just use it as a container for all your content that in that case will include a picture before the text.
I highlighted that point in this demo by doing a comparison between
Example broken
andExample solved
:Demo 2 – Using custom class
Anyway
:has
was a recent addition in the browsers space and some older versions will be cut off -> https://caniuse.com/?search=%3AhasIf you need a safer approach, you can’t rely on css to style the
<span>
based on a condition over its content. But yet you can just define a distinct css class needed to style the labels bound to list items having an anchorHere I used such approach by having a special class
itemAnchor
that when present will style the label differently then the general rule applied for list items label.Such strategy requires to add the class to the desider labels inside the html itself upfront! But yet if relying on Javascript is not a problem, this will be enough:
In the example I both used the class manually in the html
anchorItemCustom
(just a placeholder not having any css styling rule) and also included the javascript that would add itanchorItem
automatically when the page is loaded:I think it would be just as simple as splitting out the colour rule to just target
> span
(e.g. anyspan
elements in theli
that are a direct descendant, e.g.