:last without context

25 June 2012

Why doesn't ul li:last select all final li elements on the page?

Because I think it's broken! Well, the way it works is wrong. Or maybe I'm missing something?

Given the following HTML:

  <ul class="broken">   <li>List 1 - 1</li>   <li>List 1 - 2</li>   <li>List 1 - 3</li>  </ul>    <ul class="broken">   <li>List 2 - 1</li>   <li>List 2 - 2</li>   <li>List 2 - 3</li>  </ul>  

What would you expect the following jQuery to do?

  $(function() {   $("ul.broken li:last").css("backgroundColor", "#cccccc");  });  

I read it as "Change the background colour for each last li element in an unordered list".

But what it actually does, is change the last li in the full jQuery selection. See below:

I've come across this problem before and have worked around it. Those pieces of code were always more complex, so I didn't bother thinking too much.

This time however, it's as simple as it gets and I'd like an answer.

I have HTML content that the user can modify. Styling this content is fine, but I add classes like 'last' and 'first' to list elements to make things look nice. For example:

  <ol>   <li>Item 1</li>   <li>Item 1</li>   <li>Item 1</li>  </ol>    <style type="text/css">   ol li {    border-bottom: 1px solid #cccccc;   }  </style>  

Produces:

  1. Item 1
  2. Item 1
  3. Item 1

I'd rather not have the bottom border on the last element, so I add a class of last and remove it accordingly. This works great but...

... along comes the client and edits the list. The class="last" is lost and the border reappears.

I could handle this in my serverside code but that's complicating things for what isn't the biggest of problems. Instead, I like to use jQuery to modify the DOM and add classes and styles that make things look nicer but also don't look terrible if they fail through lack of JavaScript.

So, how to fix the problem.

Add context for the 'li:last' selector.

The following jQuery line says "Change the BG colour of the last li in every ul with a class of fixed".

  <script type="text/javascript">   $(function() {    $("li:last", $("ul.fixed")).css("backgroundColor", "#cccccc");   });  </script>    <ul class="fixed">   <li>List 1 - 1</li>   <li>List 1 - 2</li>   <li>List 1 - 3</li>  </ul>    <ul class="fixed">   <li>List 2 - 1</li>   <li>List 2 - 2</li>   <li>List 2 - 3</li>  </ul>  

Personally I think this shouldn't be the way to do it but I'm open to be told otherwise if there's a valid reason.