129
<ul>
    <li class="list">test1</li>
    <li class="list">test2</li>
    <li class="list">test3</li>
    <li>test4</li>
</ul>

How do I select the "last child" with the class name: list?

<style>
    ul li.list:last-child{background-color:#000;}
</style>

I know the example above doesn't work, but is there anything similar to this that does work?

IMPORTANT:

a) I can't use ul li:nth-child(3), because it could happen that it's on the fourth or fifth place too.

b) No JavaScript.

TylerH
  • 20,799
  • 66
  • 75
  • 101
  • 4
    give it a class name that will be the easiest cross browser way – Ibu Jun 19 '11 at 08:08
  • 1
    Another duplicate would be https://stackoverflow.com/questions/49942102/select-last-child-with-class-name ... though can't add as it become a circular reference. – Asons Sep 20 '19 at 09:51
  • 1
    If it wasn't for the SEO, I would've deleted this question as all of the answers here are really bad. They're either wrong/misleading, or missing the point of the question entirely. Chase's answer in particular is another example of why qualifying :*-of-type with anything other than a type selector causes all sorts of misunderstandings about how these pseudo-classes actually work - I discuss a similar misunderstanding of :first-of-type in the last section of my answer [here](https://stackoverflow.com/questions/2717480/css-selector-for-first-element-with-class/8539107#8539107). – BoltClock May 02 '21 at 10:34

6 Answers6

57

This can be done using an attribute selector.

[class~='list']:last-of-type  {
    background: #000;
}

The class~ selects a specific whole word. This allows your list item to have multiple classes if need be, in various order. It'll still find the exact class "list" and apply the style to the last one.

See a working example here: http://codepen.io/chasebank/pen/ZYyeab

Read more on attribute selectors:

http://css-tricks.com/attribute-selectors/ http://www.w3schools.com/css/css_attribute_selectors.asp

Chase
  • 2,051
  • 2
  • 21
  • 26
  • 35
    Unfortunately, I found this technically doesn't work... What it's really doing is finding the items that match the class, seeing what they are, which in this case would be a list item, and then selecting the 'last-of-type' regardless of whether or not that particular one has a class of `list`. I'll leave the answer though, in case it sparks some other solutions as the attribute and pseudo selectors are quite interesting and powerful. – Chase Jan 23 '15 at 21:23
  • 8
    This doesn't select the last div with class 'list' using the html in the question – Agu Dondo Jul 24 '15 at 16:13
  • 21
    What is the point of doing `[class~='list']` instead of just `.list`? –  Jan 20 '16 at 03:36
  • 1
    There wouldn't be any point, if you were only trying to target the class. However, the goal here was to target the last iteration of a class, and if you try using the `:last-of-type` pseudo selector (ie: `.list:last-of-type`) you'll end up with cross-browser issues. Pseudo selectors target elements, not attributes and sometimes don't work on classes, as vsync mentions in the previous answer. But if you use an attribute selector to target the class instead of just the class, `:last-of-type` works much more reliably. – Chase Jan 20 '16 at 09:46
  • 2
    Does not work. But I found another approach which works for my case. `.Select-value:nth-last-child(2)`(or even `.Select-value:not(:nth-last-child(2))` to disable styles for this element). In my case I can't modify html because it is legacy(from the library). But I always know that my element 2 from the end. – Евгений Масленков Dec 05 '16 at 10:28
  • 5
    What cross-browser issues? This answer makes no sense. – Ry- Aug 14 '19 at 15:26
  • 10
    This **doesn't work**, and never did. There is no CSS way to select the _the-last-of_ anything but an element type. Your attribute selector will be matched with the type that element has, and not the attribute itself. – Asons Sep 20 '19 at 09:37
  • 4
    Your working sample happens to work as the last `div` in the first `section` happens to be the one with that attribute/class. If you would add yet another `div`, last, with some other class name, it will stop working – Asons Sep 20 '19 at 09:43
40

You can use the adjacent sibling selector to achieve something similar, that might help.

.list-item.other-class + .list-item:not(.other-class)

Will effectively target the immediately following element after the last element with the class other-class.

Read more here: https://css-tricks.com/almanac/selectors/a/adjacent-sibling/

Kenneth Lynne
  • 15,461
  • 12
  • 63
  • 79
33

This is a cheeky answer, but if you are constrained to CSS only and able to reverse your items in the DOM, it might be worth considering. It relies on the fact that while there is no selector for the last element of a specific class, it is actually possible to style the first. The trick is to then use flexbox to display the elements in reverse order.

ul {
  display: flex;
  flex-direction: column-reverse;
}

/* Apply desired style to all matching elements. */
ul > li.list {
  background-color: #888;
}

/* Using a more specific selector, "unstyle" elements which are not the first. */
ul > li.list ~ li.list {
  background-color: inherit;
}
<ul>
  <li class="list">0</li>
  <li>1</li>
  <li class="list">2</li>
</ul>
<ul>
  <li>0</li>
  <li class="list">1</li>
  <li class="list">2</li>
  <li>3</li>
</ul>
joki
  • 6,619
  • 2
  • 22
  • 30
  • 8
    This is actually the only hack that actually solves the problem for real – Reuven Karasik Dec 06 '16 at 15:16
  • 1
    I agree, this is the answer, for now. And I suppose there may be a situation where you can't change the DOM, but maybe can change the data getting injected. If you reverse it's order, the flexbox re-order will be returning it to normal. – Chase Sep 20 '19 at 19:15
  • Should also address a situation when there's only a **single item** with that *class* – vsync Jul 23 '20 at 08:31
1

You can't target the last instance of the class name in your list without JS.

However, you may not be entirely out-of-css-luck, depending on what you are wanting to achieve. For example, by using the next sibling selector, I have added a visual divider after the last of your .list elements here: http://jsbin.com/vejixisudo/edit?html,css,output

Reggie Pinkham
  • 11,985
  • 4
  • 38
  • 36
-13
$('.class')[$(this).length - 1] 

or

$( "p" ).last().addClass( "selected" );
Nicolas Z
  • 47
  • 4
-27

I suggest that you take advantage of the fact that you can assign multiple classes to an element like so:

<ul>
    <li class="list">test1</li>
    <li class="list">test2</li>
    <li class="list last">test3</li>
    <li>test4</li>
</ul>

The last element has the list class like its siblings but also has the last class which you can use to set any CSS property you want, like so:

ul li.list {
    color: #FF0000;
}

ul li.list.last {
    background-color: #000;
}
Ibu
  • 42,752
  • 13
  • 76
  • 103
  • 166
    This doesnt at all answer the question, did you even read it? He's asking for how to do it without specifically having to add another class for the last element, that's the entire beauty of the :last-child selector. This shouldnt be an accepted answer. – nights Apr 14 '15 at 02:27
  • 1
    @Ibu I think it might be best to put the "last" class on the 3rd li element (ie the element with text "test3" rather than on "test4" just to avoid some confusion - when I initially tried your code in jsfiddle, l thought "how is this doing what the OP asked for" until I understood what you meant with the 'last' class. – neodymium Apr 24 '15 at 04:29
  • Depending on your HTML markup, this can be the only option that works. The `:last-child` selector doesn't work on class names if the last element doesn't have the class name. See https://jsfiddle.net/qgqf7gpq/2/ – CookieEater Mar 03 '18 at 11:00