[Fixed] CSS :last-child not working issues

Reasons why CSS :last-child is not working and how we can fix it!

Jan 1, 2023 | Read time 9 minutes

🔔 Table of contents

Introduction

Using the :last-child pseudo class can make our CSS more clean - eg not introducing uncessary classes or IDs.

Note: These pseudo-classes relate to the location of an element within the document tree - also known as tree-structural pseudo-classes

The :last-child selector is great when your HTML is dynamic and you want to apply styles to the last element (eg highlight or change background color).

The :last-child pseudo class will not work can be due to the following reasons:

  • Incorrect use of the syntax
  • Misunderstanding of :last-child and :last-of-type
  • There are conflicting styles that will override your :last-child
  • Limited browser support

Reason 1 - Incorrect use of the syntax

The :last-child pseudo class is used to select the very last element of a given parent container.

The syntax needs to start with a colon (:) and the last-child keyword. Often a few times where I see that my CSS is not working is that the spelling is not correct or I have double colons (::).

Make sure that we are using the single colon (:) and not the pseudo-element selector (::)!

Pseudo elements are “fake” elements that gets created, but not seen in the HTML mark up. Some examples include: ::after, ::before, etc

Lets say we have the following HTML of a unordered list:

<ul>
    <li>Jane Miller</li>
    <li>Colin Drew</li>
    <li>John Heinsohn</li>
    <li>Tom Jones</li>
</ul>

Now we can select the last list item (“Tom Jones”) by using the following :last-child selector and apply a solid orange border around it:

li:last-child {
    border: 2px solid orange; /* Give border for  "Tom Jones" */
}

Tip: Using :last-child with CSS classes will filter it!

A problem when I first used :last-child with CSS classes in front of the keyword is that I can’t seem to target the right element. For example, .my-class:last-child does not work as intended!

Adding a CSS class in front of the :last-child keyword just tells the browser to ONLY select the LAST element of a given container if that last element has the class .my-class!

So even if you think you have selected the “last child”, double check again. Because if your last child does not have the class applied to it, nothing will be selected!

Reason 2 - Misunderstanding between :last-child and :last-of-type

A common misunderstanding of the :last-child selector is that can filter out and select the last child type of a parent element.

Lets consider the following HTML structure - we want to select the last <p> with .red class:

<div class="home">
    <p class="red">first</p>
    <p class="red">second</p>
    <p class="red">third</p>
    <p class="red">fourth</p>
    <span>blah</span>
</div>

A typical selector that you will use might be: .home .red:last-child. This will not be correct, since .red:last-child will refer to the <span> element (the last element of .home container).

Additionally since the <span> element does not have a .red class applied, our :last-child CSS selector will do nothing!

.home .red:last-child { /*❌ Will not work! last-child refers to the span element*/
    border: 1px solid red;
}

.home .red:last-of-type { /*✔️ Will select the last red class! */
    border: 1px solid red;
}

As seen from the above code, to actually get what we want - selecting the last <p> with .red class, we have to use the :last-of-type!

The difference between :last-child and :last-of-type is that :last-child is less specific. What this means is that using :last-child will always select the last element of a given parent element.

As for :last-of-type it will select the last element of a type for a given parent element!

Reason 3 - conflicting styles that will override your :last-child

A common problem that you can encounter is the :last-child styling is getting overwritten by another style.

In this case, we need to check the specifity of the element you are trying to style.

For example, you could have a styling that is more specific or using the !important keyword.

Lets consider the following example. We want to apply the last <span> font to have color of red and we have the last selector using :last-child and the second using a class .my-span

<div class="container">
    <span>XXX</span>
    <span class="my-span">YYY</span>

</div>
.container :last-child { /*❌ Will not work! */
  color: red;
}

.container .my-span { /*✔️ This is more specific than the above */
  color: blue;
}

As we can see from the above code, targetting classes (.my-span) will override our last-child styling. This is due to CSS classes being more specific than the pseudo classes!

What is CSS specificity?

Specificity is how browsers decide on which style to apply to which element. Based on the CSS selector is an order in which styles will be applied!

Generally, selectors with IDs will override classes. In turn, CSS selectors with classes will override pseudo-classes such as :last-child!

Reason 4 - Check browser support

Browser support is quite good for most modern browsers. There are issues however when you are trying to support this in Safari, when the :last-child does not have any parent elements.

There are also support issues with IE6-8 versions. If you really need to support these versions then its best to have a look at javascript polyfills.

For example, we can use the lastChild property in JavaScript:

/* using the lastChild property */

document.getElementById("myList").lastChild.innerHTML;

/* OR the lastElementChild property */

const element = document.getElementById("myList")
let html = element.lastElementChild.innerHTML;

Tip: Using :last-child with ::before or ::after

We can combine the use of the :last-child pseudo class with pseudo elements such as ::before and ::after.

In this case, the pseudo element needs to be used after the :last-child keyword. Using pseudo element before the last-child keyword would be redundant! Eg p::after:last-child just targets <p>!

As an example, consider the selector of .home :last-child::before - this would mean that we want to select the last-child of the .home container element and target the ::before pseudo element.

The HTML structure could look like the following:

<div class="home">
    <p>first</p>
    <p>second</p>
    <p>third</p>
    <p>
      ::before <!-- ✔️ Will select this element -->
      "fourth"
      ::after
    </p>
</div>

Additionally, when using pseudo elements, remember to also use the content property!

.home :last-child::before{
  content: ''; /*✔️ Need this for pseudo elements to work! */
  color:red;
}

Browser support

:last-child is well supported across most modern browsers. Theres issues with Safari when we trying to select the last-child with no parent.

Additionally if you need to support this with IE6-8, you will need to use JavaScript polyfills since this feature is not supported in those IE versions!

Summary

In this post, we went over a few reasons why using :last-child is not working in your CSS. Using :last-child is great for dynamic HTML - we do not care how many childen our container element has - just use last-child and it will select the very last child element!

However, using this pseudo class can have some problems. The issues stem from using incorrect syntax, a misunderstanding of how :last-child behaves, having other classes override your last-child styings and browser support (mainly using Safari when trying to target elements with no parent).

Support is quite good across most modern browsers - if you need to support legacy browsers such as IE6-8, then its best to have a look at JavaScript polyfills!

👋 About the Author

G'day! I am Huy a software engineer based in Australia. I have been creating design-centered software for the last 10 years both professionally and as a passion.

My aim to share what I have learnt with you! (and to help me remember 😅)

Follow along on Twitter , GitHub and YouTube