What is :last-child in CSS?

:last-child is a pseudo-class that matches an element only if it is the last child of its parent. In other words: it’s about position among siblings, not about classes, not about types… just “are you literally last in this parent?”

The classic form is: parent-selector :last-child

  • It matches elements based on DOM order (the actual HTML order).
  • It does not look at visibility (an element with display: none is still a child).
  • Whitespace text nodes do not count as “children” in CSS selector logic (CSS selectors only match elements).
.list > li:last-child {
  background: #ffe08a;
  transform: translateX(8px);
}
  
.list > li:last-child {
  background: #baf7c8;
  font-weight: 700;
}
  
.list > li:last-child {
  background: #d7e6ff;
  border-style: dashed;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  display: grid;
  gap: 12px;
  padding: 18px;
  max-width: 920px;
  font-family: system-ui, Arial, sans-serif;
}

.list {
  margin: 0;
  padding: 0;
  display: grid;
  gap: 10px;
  list-style: none;
}

.list > li {
  padding: 12px 14px;
  border: 3px solid #111;
  background: #fff;
}
  
  • First item
  • Middle item
  • Last item (this one is selected)

Notice how the selector is .list > li:last-child. That means: “Select a li that is the last child of .list.”

Learn more about the direct child selector (>) in the CSS Direct Child Selector (>) Interactive Tutorial.

CSS last child selector patterns

You’ll see :last-child used a lot for “remove spacing on the last item”, “remove separator”, “round the last card”, and similar UI polishing.

Remove margin on the last item

.stack > *:last-child {
  margin-bottom: 0;
}
  
.stack > *:last-child {
  margin-bottom: 0;
  outline: 3px dashed #111;
}
  
.stack > *:last-child {
  margin-bottom: 0;
  border-radius: 16px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.stack > * {
  border: 3px solid #111;
  background: #fff;
  padding: 14px;
  margin: 0 0 14px;
}
  
Card 1
Card 2
Card 3 (no margin-bottom)

That .stack > *:last-child pattern is super handy because it works regardless of whether the last element is a div, p, section, etc.

Learn more about the universal selector (*) in the CSS Universal Selector (*) Interactive Tutorial.

Target the last child inside a specific component

.card :last-child {
  margin-bottom: 0;
}
  
.card > :last-child {
  margin-bottom: 0;
  background: #fff7d6;
}
  
.card > :last-child {
  margin-bottom: 0;
  border-left-width: 10px;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.card {
  border: 3px solid #111;
  background: #fff;
  padding: 14px;
  display: grid;
  gap: 10px;
}

.card h3 {
  margin: 0;
}

.card p {
  margin: 0 0 12px;
  padding: 10px;
  border: 2px solid #111;
  background: #f4f4f4;
}
  

Card title

Paragraph 1

Paragraph 2 (this is the last child of .card)

Tip: .card :last-child (with a space) can match “the last child of any nested parent inside the card”, which is often not what you intended. If you mean “the last direct child of the card”, prefer .card > :last-child.

CSS last child of type

People often say “last child of type” when they really mean: “I want the last paragraph” or “the last li”.

Important reality check: :last-child does not mean “last of this tag name”. It means “last child, period.”

.note p:last-child {
  border-color: #111;
  background: #ffe08a;
}
  
.note p:last-of-type {
  border-color: #111;
  background: #baf7c8;
}
  
.note p:last-of-type {
  background: #baf7c8;
}

.note p:last-child {
  outline: 3px dashed #111;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.note {
  border: 3px solid #111;
  background: #fff;
  padding: 14px;
  display: grid;
  gap: 10px;
}

.note p,
.note footer {
  margin: 0;
  padding: 10px;
  border: 2px solid #111;
  background: #f4f4f4;
}
  

Paragraph A

Paragraph B (this is the last <p>)

Footer (this is the last child overall)

In that example:

  • p:last-child does not match the last paragraph, because the last child is a footer.
  • p:last-of-type does match the last paragraph, because it means “the last p among its siblings”.

Learn more about :last-of-type in the Learn more in the CSS Nth Of Type Interactive Tutorial.

CSS :last-child vs :last-of-type

This is the most common “wait, what?” moment, so let’s make it crystal clear:

  • :last-child = “I am the last element child of my parent.”
  • :last-of-type = “I am the last element of my tag name among my siblings.”
.row > *:last-child {
  background: #ffe08a;
}
  
.row > p:last-of-type {
  background: #baf7c8;
}
  
.row > p:last-child {
  background: #d7e6ff;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
  display: grid;
  gap: 12px;
}

.row {
  border: 3px solid #111;
  background: #fff;
  padding: 14px;
  display: grid;
  gap: 10px;
}

.row > * {
  margin: 0;
  border: 2px solid #111;
  padding: 10px;
  background: #f4f4f4;
}
  

Paragraph 1

Paragraph 2 (this is last-of-type for p)

A div after the paragraphs (this is the last-child overall)

The third snippet (p:last-child) matches nothing here, because the last child is a div.

CSS :last-child not working

When :last-child “doesn’t work”, it’s usually working perfectly… on an element you’re not targeting. Here’s a beginner-friendly checklist:

  • Are you selecting the correct parent? .menu li:last-child only works if the li is the last child of its parent.
  • Is there another element after it? A hidden button, a script tag, or a div can break your expectations.
  • Are you confusing it with :last-of-type? If you mean “last li”, use li:last-of-type.
  • Are you actually targeting the element, not a wrapper? .item:last-child fails if .item is not the last child.
.menu a:last-child {
  background: #ffe08a;
}
  
.menu li:last-child a {
  background: #baf7c8;
}
  
.menu li:last-of-type a {
  background: #d7e6ff;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.menu {
  border: 3px solid #111;
  background: #fff;
  padding: 14px;
  margin: 0;
  list-style: none;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.menu li {
  margin: 0;
}

.menu a {
  display: inline-block;
  padding: 10px 12px;
  border: 2px solid #111;
  background: #f4f4f4;
  text-decoration: none;
  color: #111;
  font-weight: 700;
}
  

  

Why snippet 1 is “wrong”: a:last-child checks if the a is the last child of its parent (li). In this markup, every a is the only child of its li, so they are all :last-child.

If you mean “the last menu item”, target the last li (snippet 2), or the last li of its type (snippet 3).

CSS last child - 1 (select the one before the last)

There is no built-in selector literally called “last child - 1, but you have several solid options.

Option 1: Use :nth-last-child(2)

:nth-last-child(2) means: “the second child from the end”. That’s exactly “last child - 1”.

.tags > li:nth-last-child(2) {
  background: #ffe08a;
  font-weight: 800;
}
  
.tags > li:last-child {
  background: #baf7c8;
  font-weight: 800;
}
  
.tags > li:nth-last-child(2),
.tags > li:last-child {
  font-weight: 800;
}

.tags > li:nth-last-child(2) {
  background: #ffe08a;
}

.tags > li:last-child {
  background: #baf7c8;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.tags {
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  list-style: none;
}

.tags > li {
  padding: 10px 12px;
  border: 3px solid #111;
  background: #fff;
}
  
  • HTML
  • CSS
  • JavaScript
  • A11Y
  • Last item

Option 2: Combine with :not(:last-child)

This isn’t “minus one”, but it’s extremely common: “style everything except the last”.

.breadcrumbs > a:not(:last-child) {
  text-decoration: underline;
}
  
.breadcrumbs > a:not(:last-child)::after {
  content: "›";
  margin-inline: 10px;
  opacity: 0.6;
}
  
.breadcrumbs > a:last-child {
  font-weight: 800;
  text-decoration: none;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0;
  border: 3px solid #111;
  background: #fff;
  padding: 14px;
}

.breadcrumbs > a {
  padding: 8px 10px;
  color: #111;
  text-decoration: none;
  border-radius: 10px;
}
  

  

Learn more about :not() in the CSS :not Interactive Tutorial.

CSS last child ::after

The pseudo-element ::after lets you draw or insert decorative content. A classic pattern is: “add a separator after every item… except the last one.”

.nav a::after {
  content: "•";
  margin-inline: 12px;
  opacity: 0.4;
}
  
.nav a:not(:last-child)::after {
  content: "•";
  margin-inline: 12px;
  opacity: 0.4;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.nav {
  border: 3px solid #111;
  background: #fff;
  padding: 14px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

.nav a {
  color: #111;
  text-decoration: none;
  font-weight: 700;
  border-radius: 10px;
}
  

  

Snippet 2 is usually the cleanest approach: a:not(:last-child)::after means “only add the separator to links that aren’t the last child.”

Learn more about ::after in the CSS ::before and ::after Pseudo-Elements Interactive Tutorial.

CSS last child and first child together

Sometimes you need to treat the first and last items differently, for example rounding corners in a vertical list.

.panel > .row:first-child {
  border-top-left-radius: 16px;
  border-top-right-radius: 16px;
}
  
.panel > .row:last-child {
  border-bottom-left-radius: 16px;
  border-bottom-right-radius: 16px;
}
  
.panel > .row:first-child,
.panel > .row:last-child {
  font-weight: 800;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
}

.panel {
  border: 3px solid #111;
  background: #fff;
  padding: 14px;
  display: grid;
  gap: 10px;
}

.row {
  border: 3px solid #111;
  background: #f4f4f4;
  padding: 12px 14px;
  border-radius: 0;
}
  
First row
Middle row
Last row

Extra: the “only child” special case

If a parent has only one element child, that child is both :first-child and :last-child. If you want to style “a single item list” differently, there’s :only-child.

.single > .chip:only-child {
  outline: 3px dashed #111;
}
  
.single > .chip:first-child {
  outline: 3px dashed #111;
}
  
.single > .chip:last-child {
  outline: 3px dashed #111;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
  display: grid;
  gap: 12px;
}

.single {
  border: 3px solid #111;
  background: #fff;
  padding: 14px;
}

.chip {
  display: inline-block;
  padding: 10px 12px;
  border: 3px solid #111;
  background: #f4f4f4;
}
  
Only chip

CSS last child of class

CSS has :last-child (last child overall) and :last-of-type (last of a tag name), but there is no direct :nth-of-class or :last-of-class selector built into CSS.

The good news: there’s now an equivalent pattern using the selector list argument of :nth-child() and :nth-last-child(). At the time of writing, browser support is around ~92%. For the latest support data, check Can I use.

The big idea: :nth-child(N of .class)

The newest versions of :nth-child() and :nth-last-child() accept an optional of S clause. This filters the counting to only children that match the selector list S.

For example, :nth-child(1 of .class) selects the first child among the children that have the .class class (ignoring any non-.class children that come before it). It’s similar to :nth-of-type, but for arbitrary selectors instead of only tag names.

“Last of class” using :nth-last-child(1 of .class)

If you want “the last child that has .highlight”, you can use: :nth-last-child(1 of .highlight).

  • First of class: :nth-child(1 of .highlight)
  • Second of class: :nth-child(2 of .highlight)
  • Last of class: :nth-last-child(1 of .highlight)
  • Second-to-last of class: :nth-last-child(2 of .highlight)

Let’s see it in action with a list that mixes normal items and highlighted items. Notice how the “of .highlight” counting ignores everything else.

.list > li:nth-child(1 of .highlight) {
  background: #ffe08a;
  font-weight: 800;
}
  
.list > li:nth-child(2 of .highlight) {
  background: #baf7c8;
  font-weight: 800;
}
  
.list > li:nth-last-child(1 of .highlight) {
  background: #d7e6ff;
  font-weight: 800;
}
  
*,
::before,
::after {
  box-sizing: border-box;
}

.wrap {
  max-width: 920px;
  padding: 18px;
  font-family: system-ui, Arial, sans-serif;
  display: grid;
  gap: 12px;
}

.hint {
  margin: 0;
  padding: 12px 14px;
  border: 3px solid #111;
  background: #fff;
}

.list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 10px;
}

.list > li {
  padding: 12px 14px;
  border: 3px solid #111;
  background: #f4f4f4;
  display: flex;
  align-items: center;
  gap: 10px;
}

.badge {
  font-size: 12px;
  font-weight: 800;
  padding: 4px 8px;
  border: 2px solid #111;
  border-radius: 999px;
  background: #fff;
}
  

Click the snippets: they select the 1st, 2nd, or last .highlight item, even though other items are mixed in.

  • normal Alpha
  • highlight Bravo
  • normal Charlie
  • highlight Delta
  • normal Echo
  • highlight Foxtrot
  • normal Golf

Learn much more about :nth-child(N of S) in the CSS Nth Child (N of Selector) Interactive Tutorial.

Quick reference cheatsheet

  • Last child overall: .parent > :last-child
  • Last list item: ul > li:last-child
  • Last paragraph in a container: .box p:last-of-type
  • Everything except the last: .items > *:not(:last-child)
  • One before the last (“last child - 1”): .items > :nth-last-child(2)
  • Add separator after all but last: .nav a:not(:last-child)::after
  • First and last: .row:first-child and .row:last-child
  • Only child: :only-child
  • Last of class: :nth-last-child(1 of .class)

If :last-child ever feels “buggy”, it’s almost always a structure mismatch. Your best debugging tool is simply to re-check the parent and the siblings: “Is this element truly the last element child?”