I have some HTML with div
s and next sibling ul
s like this:
<div id="someid" >
<div ></div>
<ul>
<li style="display: none;">1</li>
<li style="display: none;">2</li>
<li style="display: none;">3</li>
<li>4</li>
</ul>
<div ></div>
<ul>
<li style="display: none;">1</li>
<li style="display: none;">2</li>
<li style="display: none;">3</li>
<li style="display: none;">4</li>
</ul>
<div ></div>
<ul>
<li style="display: none;">1</li>
<li>2</li>
<li style="display: none;">3</li>
<li style="display: none;">4</li>
</ul>
</div>
How to make the div
with class title
display: none
if next ul
's li
's are all display: none
?
CodePudding user response:
Unfortunately, today's CSS can't do that (see below for tomorrow's CSS), but with JavaScript you can loop through the .title
elements and see if their next element is a ul
and all of its child elements are display: none
, and set the title element to display: none
if so:
for (const element of document.querySelectorAll(".title")) {
if (element.nextElementSibling.tagName === "UL" &&
[...element.nextElementSibling.children].every(
(child) => getComputedStyle(child).display === "none"
)) {
element.style.display = "none";
}
}
<div id="someid" >
<div >Should Show</div>
<ul>
<li style="display: none;">1</li>
<li style="display: none;">2</li>
<li style="display: none;">3</li>
<li>4</li>
</ul>
<div >Should Hide</div>
<ul>
<li style="display: none;">1</li>
<li style="display: none;">2</li>
<li style="display: none;">3</li>
<li style="display: none;">4</li>
</ul>
<div >Should Show</div>
<ul>
<li style="display: none;">1</li>
<li>2</li>
<li style="display: none;">3</li>
<li style="display: none;">4</li>
</ul>
</div>
You might factor out at least the every
calback (and possibly the whole check):
const isDisplayNone = (element) => getComputedStyle(element).display === "none";
for (const element of document.querySelectorAll(".title")) {
if (element.nextElementSibling.tagName === "UL" &&
[...element.nextElementSibling.children].every(isDisplayNone)
) {
element.style.display = "none";
}
}
<div id="someid" >
<div >Should Show</div>
<ul>
<li style="display: none;">1</li>
<li style="display: none;">2</li>
<li style="display: none;">3</li>
<li>4</li>
</ul>
<div >Should Hide</div>
<ul>
<li style="display: none;">1</li>
<li style="display: none;">2</li>
<li style="display: none;">3</li>
<li style="display: none;">4</li>
</ul>
<div >Should Show</div>
<ul>
<li style="display: none;">1</li>
<li>2</li>
<li style="display: none;">3</li>
<li style="display: none;">4</li>
</ul>
</div>
With tomorrow's CSS, we can do it if we change the structure slightly to add a wrapper div
and we hide the li
elements with a class rather than inline styling (which is almost always best anyway):
.hidden {
display: none;
}
.container .title {
display: none;
}
.container:has(li:not(.hidden)) .title {
display: block;
}
<p><strong>Only works on cutting-edge browsers!!</strong></p>
<div id="someid" >
<div >
<div >Should Show</div>
<ul>
<li >1</li>
<li >2</li>
<li >3</li>
<li>4</li>
</ul>
</div>
<div >
<div >Should Hide</div>
<ul>
<li >1</li>
<li >2</li>
<li >3</li>
<li >4</li>
</ul>
</div>
<div >
<div >Should Show</div>
<ul>
<li >1</li>
<li>2</li>
<li >3</li>
<li >4</li>
</ul>
</div>
</div>
That will only work on cutting-edge browsers such as Chrome v105 and higher (not even Chrome v104 has it). More about :has
here on MDN and in the spec.