0

I'm trying to select only the last child ul as underlined in the picture

enter image description here

Code

li:before {
  content: ' ';
}
<div id="container">
  <ul>
    <li>
      <ul>
        <li>123</li>
        <li>
          <ul>
            <li>Abc !</li>
          </ul>
        </li>
      </ul>
    </li>
    <li>
      <ul>
        <li>
          <ul>
            <li>
              <ul>
                <li>
                  <ul>
                    <li>Def !</li>
                  </ul>
                </li>
              </ul>
            </li>
            <li>456</li>
            <li>
              <ul>
                <li>
                  <ul>
                    <li>Ghi !</li>
                    <li>Jkl !</li>
                    <li>Mno !</li>
                  </ul>
                </li>
                <li>789</li>
              </ul>
            </li>
            <li>
              <ul>
                <li>
                  <ul>
                    <li>
                      <ul>
                        <li>Prs !</li>
                      </ul>
                    </li>
                  </ul>
                </li>
                <li>1011</li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</div>
TylerH
  • 20,799
  • 66
  • 75
  • 101
  • 2
    Please show us your relevant code, and what you have tried. Also be more specific for what do you want. – Sfili_81 Jul 15 '19 at 13:03
  • 1
    Can you give class to that particular ul element and access it using that? – Monika Mangal Jul 15 '19 at 13:03
  • @Monika This is part of a dynamic menu. So I can't add a class for every last ul element. – GeorgeMihai Jul 15 '19 at 13:06
  • @GheorgeMihai What does __dynamic__ mean in this context? Is it created with an backend scripting language (like PHP, Python, etc.)? Or is it dynamically created/changed in the Frontend with JavaScript? – yunzen Jul 15 '19 at 13:11
  • May be this could help - https://stackoverflow.com/questions/31599805/selecting-the-last-element-among-various-nested-containers – Monika Mangal Jul 15 '19 at 13:14
  • @yunzen it's created with PHP. – GeorgeMihai Jul 15 '19 at 13:14
  • 1
    @GheorgeMihai Can't you dynamically add the classed to the relevant `
      `s in PHP?
    – yunzen Jul 15 '19 at 13:20
  • 1
    Currently, there's no way to do it with plain CSS (possible with JS). With the [`:has()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:has) CSS pseudo-class, it will be possible, but there's no browser support for it. – FZs Jul 15 '19 at 13:21
  • Check this: https://codepen.io/HerrSerker/pen/ac825f789eb846c61ae5f9cbd2529896 – yunzen Jul 15 '19 at 13:32
  • Usually being dynamic means it's *easier* to add classes to every element, not harder... – JJJ Jul 15 '19 at 14:00
  • 1
    @yunzen selecting one element or many elements doesn't make this question *not* a duplicate. As a side note the duplicate target have one level but it can work with any level so the selector proposed there will work here too. You answer like the most upvoted one is using the same selector in the duplicate target. – Temani Afif Jul 22 '19 at 10:19
  • @yunzen Please don't add code to a question where OP just posted a screenshot. Such a question should be closed as off-topic until the *asker* puts in the minimum required effort. Also, it's OP's prerogative to describe how the duplicate targets don't solve the question, not yours. – TylerH Jul 22 '19 at 15:50

2 Answers2

3

Sadly this can't be achieved dynamically with CSS. However this can be achieved with jQuery by filtering every ul that does not have a ul descendent.

$(document).ready(function(){
  $('ul').filter(":not(:has(ul))").addClass('last');
});
.last {
  background:blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li>
    level 1
    <ul>
      <li>level 2</li>
      <li>level 2</li>
      <li>level 2</li>
      <li>
        level 2
        <ul>
          <li>level 3</li>
          <li>level 3</li>
          <li>
            level 3
            <ul>
              <li>level 4</li>
              <li>level 4</li>
              <li>level 4</li>
              <li>level 4</li>
            </ul>
          </li>
          <li>level 3</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>level 1</li>
  <li>
    level 1
    <ul>
      <li>level 2</li>
      <li>level 2</li>
      <li>level 2</li>
      <li>level 2</li>
    </ul>
  </li>
  <li>level 1</li>
</ul>
WizardCoder
  • 3,353
  • 9
  • 20
0

There is no possible pure CSS method that would do this.

Edit

With CSS Selector Level 4 it would be easy: ul:not(:has(ul)) You can do it with jQuery, which supports the :has() selector.

jQuery('ul:not(:has(ul))').addClass('deep')

Here is a VanillaJS solution:

"use strict";
console.clear()

{
  const container = document.getElementById('container')
  
  // Get all list items inside #container
  let uls = Array.from(container.getElementsByTagName('ul'));
  
  uls = uls.filter(ul => {
    return ul.getElementsByTagName('ul').length === 0
  })
  
  // Add a class to those list items
  uls.forEach(ul => ul.classList.add('deep'))
  
}
.deep {
  border: 1px solid;
  background-color: rgba(255, 0, 0, 0.2);
}

li:before {
  content: ' ';
}
<div id="container">
  <ul>
    <li>
      <ul>
        <li>123</li>
        <li>
          <ul>
            <li>Abc !</li>
          </ul>
        </li>
      </ul>
    </li>
    <li>
      <ul>
        <li>
          <ul>
            <li>
              <ul>
                <li>
                  <ul>
                    <li>Def !</li>
                  </ul>
                </li>
              </ul>
            </li>
            <li>456</li>
            <li>
              <ul>
                <li>
                  <ul>
                    <li>Ghi !</li>
                    <li>Jkl !</li>
                    <li>Mno !</li>
                  </ul>
                </li>
                <li>789</li>
              </ul>
            </li>
            <li>
              <ul>
                <li>
                  <ul>
                    <li>
                      <ul>
                        <li>Prs !</li>
                      </ul>
                    </li>
                  </ul>
                </li>
                <li>1011</li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</div>

The following is an incorrect answer, because I misread the OP You can do with a little JavaScript:

"use strict";
console.clear()

{
  const container = document.getElementById('container')
  
  // Get all list items inside #container
  let lis = Array.from(container.getElementsByTagName('li'));

  // Filter to get only those, that don't have child lists
  lis = lis.filter(el => {
    return el.querySelectorAll(':scope > ul').length === 0
  })
  // Filter again to get only those, that are last childs
  lis = lis.filter(el => {
    return el.parentElement.lastElementChild === el
  })
  
  // Add a class to those list items
  lis.forEach(el => el.parentElement.classList.add('deep'))
  
}
.deep {
  border: 1px solid;
  background-color: rgba(255, 0, 0, 0.2);
}

li:before {
  content: ' ';
}
<div id="container">
  <ul>
    <li>
      <ul>
        <li>123</li>
        <li>
          <ul>
            <li>Abc !</li>
          </ul>
        </li>
      </ul>
    </li>
    <li>
      <ul>
        <li>
          <ul>
            <li>
              <ul>
                <li>
                  <ul>
                    <li>Def !</li>
                  </ul>
                </li>
              </ul>
            </li>
            <li>456</li>
            <li>
              <ul>
                <li>
                  <ul>
                    <li>Ghi !</li>
                    <li>Jkl !</li>
                    <li>Mno !</li>
                  </ul>
                </li>
              </ul>
            </li>
            <li>
              <ul>
                <li>
                  <ul>
                    <li>
                      <ul>
                        <li>Prs !</li>
                      </ul>
                    </li>
                  </ul>
                </li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</div>
Community
  • 1
  • 1
yunzen
  • 32,854
  • 11
  • 73
  • 106