Home > Enterprise >  Hide a div tag if the next ul's li's are all displayed none
Hide a div tag if the next ul's li's are all displayed none

Time:09-15

I have some HTML with divs and next sibling uls 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.

  • Related