1

I have a list inside a list and inside the inner list I need to select the last list item. The inner list looks like:

<ol>
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li class="x">...</li>
</ol>

But I must ignore items with a class x. DEMO

li li:not(.x):last-child {
   color: red;
}

I would expect the C to be red, but it doesn't work. Can someone explain to me what the issue is and if possible a solution would be great :) Thnx

Harry
  • 87,580
  • 25
  • 202
  • 214
Jeanluca Scaljeri
  • 26,343
  • 56
  • 205
  • 333
  • What is your expected output? – Linga Feb 01 '16 at 08:04
  • I've updated the question. Hope it is clear now – Jeanluca Scaljeri Feb 01 '16 at 08:05
  • 1
    No, the `:last-child` doesn't work that way. It can't select the last child which doesn't have x. It always points to the last child of that parent. So you'r selector would select the last element if it doesn't have class as x. Else, it would select nothing. – Harry Feb 01 '16 at 08:11
  • 1
    I'm sure you're already aware of it but if .x was the last class of every list item you could target c, (or whatever comes before .x) with nth-last-child(2) https://jsfiddle.net/Hastig/sky44bfo/8/ – Hastig Zusammenstellen Feb 01 '16 at 08:14
  • 1
    No you can't. Only thing you can do is to use `nth-last-child` in this case. Better you change your logic. Remember, there is no `previous sibling` selector – Linga Feb 01 '16 at 08:16
  • A `previous sibling` selector would be great :) Thanks for the comments! – Jeanluca Scaljeri Feb 01 '16 at 08:27

1 Answers1

1

As I had explained in my answer here, :last-child selector does not work that way. This selector points to only one element and it is always the element which is the last child of its parent. The child that is selected doesn't change based on the other conditions that are attached to the selector. Only thing that is affected by the additional conditions is whether the last child element itself is selected or not.

The below selector simply means select the last child li element only if it does not have class x and not select the last child li element which does not have class x.

li li:not(.x):last-child {
   color: red;
}

There are no plans to introduce previous sibling selector even in Selectors Level 4 and I don't think they would ever be introduced because that goes against the meaning of Cascading Style Sheets.

There is however a selector that is specced in Level 4 which could solve cases like this and it is the :nth-last-match pseudo-selector. For your case, it could end up being something like the below:

li li:nth-last-match(1 of :not(.x))

I am assuming the nth-last-match will allow a negation selector because there is no mention about it being invalid even though :matches(:not(...)) is said to be invalid. There is a chance that it may be marked as invalid in which case we would still find it tough to select such elements.

As per the latest Editor's Draft of the spec, it seems like the :nth-last-match selector is no longer in scope (and has been subsumed into :nth-last-child selector). So, the selector would instead be:

li li:nth-last-child(1 of :not(.x))

It also talks about another one which could be useful for this case. It is the :has pseudo selector.

li li {
  color: red; /* apply the styling which needs to be set to the last child without class x */
}
li li:has( ~ li:not(.x)) { /* this selects all li which have a sibling whose class is not x */
  color: black; /* override the style for these alone and set them to the default */
}

Note: This again is only a draft and can change.


One possible solution would be to use jQuery (or JavaScript) to find out the last element that satisfies the conditions and then set the required styles or classes to it.

$(document).ready(function() {
  $('li ol').map(function() {
    return $(this).children().not('.x').get(-1);
  }).css('color', 'red');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol>
  <li>
    <ol>
      <li>A</li>
      <li>B</li>
      <li class="x">X</li>
    </ol>
  </li>
  <li>
    <ol>
      <li>A</li>
      <li>C</li>
      <li class="x">X</li>
    </ol>
  </li>
  <li>
    <ol>
      <li>A</li>
      <li>D</li>
      <li class="x">X</li>
    </ol>
  </li>
  <li>
    <ol>
      <li>A</li>
      <li>D</li>
      <li class="ex">X</li>
    </ol>
  </li>
</ol>
Community
  • 1
  • 1
Harry
  • 87,580
  • 25
  • 202
  • 214