106

My goal is to apply the CSS on the last li, but it doesn't do that.

#refundReasonMenu #nav li:last-child {
    border-bottom: 1px solid #b5b5b5;
}
<div id="refundReasonMenu">
     <ul id="nav">
      <li><a id="abc" href="#">abcde</a></li>
      <li><a id="def" href="#">xyz</a></li>
     </ul>
    </div>

How can I select only the last child?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Miral
  • 5,968
  • 16
  • 57
  • 85

11 Answers11

171

The :last-child pseudoclass still cannot be reliably used across browsers. In particular, Internet Explorer versions < 9, and Safari < 3.2 definitely don't support it, although Internet Explorer 7 and Safari 3.2 do support :first-child, curiously.

Your best bet is to explicitly add a last-child (or similar) class to that item, and apply li.last-child instead.

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
VoteyDisciple
  • 37,319
  • 5
  • 97
  • 97
  • That can also be what causes it, yeah :) – changelog Aug 18 '09 at 11:52
  • IIRC, IE7 doesn't support it, and first-child is sketchy. I'd go with this method of adding your own class, it's much more reliable. – Kieran Senior Aug 18 '09 at 11:53
  • I tested the above on Safari 4 and it worked ok. But support in general is variable, so you'll need to try something else. – dave Aug 18 '09 at 11:57
  • 46
    IE8 doesn't support `:last-child` either. And it's not *that* curious. `:first-child` is a CSS2 pseudo-class, `:last-child` a CSS3 pseudo-class. – mercator Aug 18 '09 at 12:18
  • 92
    last-child works in all the modern browsers, which means, of course, it does not work in any version of IE. – Rob Apr 08 '10 at 21:25
  • 25
    fyi, IE **9** [supports `:last-child`](http://msdn.microsoft.com/en-us/library/cc351024%28v=vs.85%29.aspx#pseudoclasses). – Jari Keinänen Jan 04 '12 at 11:28
  • 6
    @mercator It's curious that :first-child was implement in CSS2 but :last-child was left until CSS3 ... seems pretty obvious to add them at the same time. – Cobby Jun 29 '12 at 04:01
  • 21
    IE7 refuses to recognize other bastard children – Dewayne Nov 02 '12 at 21:46
  • 3
    @Cobby It's a parsing thing. :first-child is easier to implement because it doesn't require a look-ahead. See http://snook.ca/archives/html_and_css/css-parent-selectors – Tamlyn May 21 '13 at 15:41
  • @Tamlyn I didn't realise ease of implementation affected spec writing :P That's a nice article though, thanks! – Cobby May 22 '13 at 00:47
  • Wow... checking the edit time vs comment posts.. I would think programmers here know what < 9 means...... – Angry 84 Feb 26 '15 at 02:07
76

Another solution that might work for you is to reverse the relationship. So you would set the border for all list items. You would then use first-child to eliminate the border for the first item. The first-child is statically supported in all browsers (meaning it can't be added dynamically through other code, but first-child is a CSS2 selector, whereas last-child was added in the CSS3 specification)

Note: This only works the way you intended if you only have 2 items in the list like your example. Any 3rd item and on will have borders applied to them.

Branden Silva
  • 1,406
  • 1
  • 11
  • 15
  • 2
    +1 for out of the box thinking :-) I just converted my last-child elements to first-child and changed by border-right to border-left for menu separators. Now IE8 likes my css. – Scott B Apr 08 '11 at 14:23
43

If you think you can use Javascript, then since jQuery support last-child, you can use jQuery's css method and the good thing it will support almost all the browsers

Example Code:

$(function(){
   $("#nav li:last-child").css("border-bottom","1px solid #b5b5b5")
})

You can find more info about here : http://api.jquery.com/css/#css2

Tarik
  • 79,711
  • 83
  • 236
  • 349
  • 96
    Wayyy better to do something like `$("#nav li:last-child").addClass('last-child')` so you can keep your styling in your stylesheets. – jason Oct 11 '10 at 17:58
  • This is cleaner than the first solution since it is handled automatically. But I agree with jason, too. – Josh M. Oct 26 '11 at 19:35
  • 1
    Actually, IE7 doesn't load a class that has both `div:last-child` and `div.last-child`. It appears that it considers the `:last-child` syntax to be invalid and any class with that pseudo-selector won't be applied. – Josh M. Oct 26 '11 at 21:17
  • @Josh M.: That's correct and expected behavior. *Quite* unfortunate, I should say. You'd have to duplicate the rule. – BoltClock Jan 20 '12 at 21:52
19

If the number of list items is fixed you can use the adjacent selector, e.g. if you only have three <li> elements, you can select the last <li> with:

    li+li+li {
        color: red;
        font-size: 170%;
    }
 <ul>
  <li>First</li>
  <li>Second</li>
  <li>Last</li>
 </ul>
ccpizza
  • 28,968
  • 18
  • 162
  • 169
  • 3
    Your selector is wrong. `li + #nav li` selects `li` inside `#nav` that comes after `li`. Your selector should simply be `#nav li + li + li`. – BoltClock Jan 20 '12 at 21:50
  • 1
    That's nifty. Works fine in IE8, however not in IE7. – Mateng Jan 31 '12 at 16:25
13

If you find yourself frequently wanting CSS3 selectors, you can always use the selectivizr library on your site:

http://selectivizr.com/

It's a JS script that adds support for almost all of the CSS3 selectors to browsers that wouldn't otherwise support them.

Throw it into your <head> tag with an IE conditional:

<!--[if (gte IE 6)&(lte IE 8)]>
  <script src="/js/selectivizr-min.js" type="text/javascript"></script>
<![endif]-->
nzifnab
  • 15,876
  • 3
  • 50
  • 65
3

last-child pseudo class does not work in IE

CSS Compatibility and Internet Explorer

IE7 CSS Selectors: How they fail

rahul
  • 184,426
  • 49
  • 232
  • 263
0

As an alternative to using a class you could use a detailed list, setting the child dt elements to have one style and the child dd elements to have another. Your example would become:

#refundReasonMenu #nav li:dd
{
  border-bottom: 1px solid #b5b5b5;
}

html:

<div id="refundReasonMenu">
  <dl id="nav">
        <dt><a id="abc" href="#">abcde</a></dt>
        <dd><a id="def" href="#">xyz</a></dd>
  </dl>
</div>

Neither method is better than the other and it is just down to personal preference.

lexx
  • 637
  • 3
  • 9
0

Why not apply the border to the bottom of the UL?

#refundReasonMenu #nav ul
{
    border-bottom: 1px solid #b5b5b5;
}
pork-chop
  • 83
  • 3
  • 12
  • 1
    If you have `padding-bottom` on the `
      ` element or `margin-bottom` on the last `
    • ` element, this will not have the desired placement of right underneath the last `
    • ` element. Otherwise, this is a good solution.
    – Wex Dec 14 '12 at 17:46
0

If you are floating the elements you can reverse the order

i.e. float: right; instead of float: left;

And then use this method to select the first-child of a class.

/* 1: Apply style to ALL instances */
#header .some-class {
  padding-right: 0;
}
/* 2: Remove style from ALL instances except FIRST instance */
#header .some-class~.some-class {
  padding-right: 20px;
}

This is actually applying the class to the LAST instance only because it's now in reversed order.

Here is a working example for you:

<!doctype html>
<head><title>CSS Test</title>
<style type="text/css">
.some-class { margin: 0; padding: 0 20px; list-style-type: square; }
.lfloat { float: left; display: block; }
.rfloat { float: right; display: block; }
/* apply style to last instance only */
#header .some-class {
  border: 1px solid red;
  padding-right: 0;
}
#header .some-class~.some-class {
  border: 0;
  padding-right: 20px;
}
</style>
</head>
<body>
<div id="header">
  <img src="some_image" title="Logo" class="lfloat no-border"/>
  <ul class="some-class rfloat">
    <li>List 1-1</li>
    <li>List 1-2</li>
    <li>List 1-3</li>
  </ul>
  <ul class="some-class rfloat">
    <li>List 2-1</li>
    <li>List 2-2</li>
    <li>List 2-3</li>
  </ul>
  <ul class="some-class rfloat">
    <li>List 3-1</li>
    <li>List 3-2</li>
    <li>List 3-3</li>
  </ul>
  <img src="some_other_img" title="Icon" class="rfloat no-border"/>
</div>
</body>
</html>
Ozzy
  • 8,244
  • 7
  • 55
  • 95
0

Another way to do it is using the last-child selector in jQuery and then use the .css() method. Be weary though because some people are still in the stone age using JavaScript disabled browsers.

ecollis6
  • 5,357
  • 4
  • 17
  • 12
-2

It's hard to say without seeing the rest of your CSS, but try adding !important in front of the border color, to make it like so:

#refundReasonMenu #nav li:last-child
{
  border-bottom: 1px solid #b5b5b5 !important;
}
changelog
  • 4,646
  • 4
  • 35
  • 62