I’m working on a navigation component and want the nav element to be visible, using display: block
when it has :focus-within
for keyboard navigation. This state seems to be applying when I click the nav button, but remains visible when I hover sibling elements. I would like the focus-within
state to be hidden when a sibling has the hover
state.
Given the following HTML
<ul>
<li>
<button>
One
</button>
<span>
submenu 1
</span>
</li>
<li>
<button>
Two
</button>
<span>
submenu 2
</span>
</li>
<li>
<button>
Three
</button>
<span>
submenu 3
</span>
</li>
</ul>
and the following CSS
span {
display: none;
}
li {
&:hover > span {
display: block;
}
&:focus-within > span {
display: block;
}
}
I can show the submenu
items when I click or keyboard navigate the page. However, if I click <button>One
and then hover <button>Two
, submenu 1
remains visible. The submenu should only be visible if it has 1) :hover state or 2) :focus-within state (but no sibling has hover state).
I would like no more than 1 submenu visible at once. Is this possible to achieve with CSS?
>Solution :
Yes, it is:
li:hover ~ li:focus-within,
li:focus-within:has(~ li:hover) {
display: none;
}
Note that :has()
is not very well supported (yet).
Try it:
span {
display: none;
}
li:hover > span {
display: block;
}
li:focus-within > span {
display: block;
}
li:hover ~ li:focus-within,
li:focus-within:has(~ li:hover) {
display: none;
}
<ul>
<li>
<button>One</button>
<span>submenu 1</span>
</li>
<li>
<button>Two</button>
<span>submenu 2</span>
</li>
<li>
<button>Three</button>
<span>submenu 3</span>
</li>
</ul>