What CSS :first-child is
:first-child is a CSS pseudo-class that matches an element only if it is the very first child of its parent.
Read that again: first child of its parent. Not “the first one of a kind”, not “the first one you see”, not “the first one with a class”. It’s purely about the DOM tree order.
.item:first-child {
background: #ffe08a;
}
.item:first-child {
background: #8ad9ff;
}
.item:first-child {
background: #b9ffa6;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
font-family: ui-monospace, SFMono-Regular, monospace;
padding: 16px;
}
.row {
display: flex;
gap: 10px;
}
.item {
border: 2px solid #111;
padding: 10px 12px;
border-radius: 10px;
background: #f2f2f2;
}
Item AItem BItem C
In that example, the first .item is also the first child of .row, so it matches .item:first-child.
:first-child in plain English
- Parent-focused: the selector checks the element’s position among its siblings under the same parent.
- All children count: different tags, different classes, every element counts as a child.
- It either matches or it doesn’t: there’s no “kind of first”.
.card:first-child {
outline: 4px solid #111;
}
.card:first-child {
transform: translateY(-6px);
}
.card:first-child {
box-shadow: 0px 12px 0px 0px rgba(0, 0, 0, 0.25);
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
font-family: system-ui, ui-sans-serif, sans-serif;
}
.card {
border: 2px solid #111;
border-radius: 14px;
padding: 12px;
background: #f7f7f7;
}
.card p {
margin: 0;
}
Card 1 (I am the first child)
Card 2
Card 3
Card 4
Card 5
Card 6
:first-child vs :first-of-type
This is the #1 confusion. The selectors look similar, but they answer different questions:
-
:first-childmeans: “Am I the first child of my parent?” -
:first-of-typemeans: “Am I the first of my tag name among siblings?”
Example: why :first-child “fails”
In the next playground, the first child of the parent is an h3, not a p. So p:first-child matches nothing, even though the first paragraph “feels” first.
p:first-child {
background: #ffe08a;
}
p:first-of-type {
background: #ffe08a;
}
p:first-of-type {
background: #ffe08a;
}
h3:first-child {
background: #b9ffa6;
}
*,
::before,
::after {
box-sizing: border-box;
}
.box {
border: 2px solid #111;
border-radius: 14px;
padding: 16px;
margin: 16px;
font-family: system-ui, ui-sans-serif, sans-serif;
background: #f7f7f7;
}
.box > * {
border: 1px dashed rgba(0, 0, 0, 0.35);
padding: 8px 10px;
border-radius: 10px;
margin: 10px 0;
}
.box h3 {
margin: 0;
}
.box p {
margin: 0;
}
Heading
Paragraph A
Paragraph B
If you want “the first paragraph”, p:first-of-type is usually what you mean.
Learn more in the CSS Nth Of Type Interactive Tutorial.
The parent-child relationship
:first-child is all about who your parent is. If your HTML structure changes (wrappers, layout divs, headings inserted by a CMS), the match can change.
Use the direct child selector to make intent clear
Adding > is not required, but it often makes your selector clearer and safer:
-
.list > li:first-childmeans: “the firstlithat is a direct child of.list” -
.list li:first-childmeans: “anylithat is the first child of its parent, anywhere inside.list”
.list li:first-child {
background: #ffe08a;
}
.list > li:first-child {
background: #ffe08a;
}
.list > li:first-child {
background: #ffe08a;
}
.list .sub li:first-child {
background: #b9ffa6;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
padding: 16px;
font-family: system-ui, ui-sans-serif, sans-serif;
}
.list,
.sub {
border: 2px solid #111;
border-radius: 14px;
padding: 12px 12px 12px 28px;
background: #f7f7f7;
margin: 0;
}
.list {
margin-bottom: 14px;
}
li {
padding: 6px 10px;
border-radius: 10px;
}
.sub {
margin-top: 10px;
}
- Top item 1
- Top item 2 (has a nested list)
- Nested item A
- Nested item B
- Top item 3
Notice how .list li:first-child can light up nested list items too. That might be what you want, or it might be a surprise party you did not RSVP to.
Learn more in the CSS Direct Child Selector (>) Interactive Tutorial.
Common real-world gotchas
Gotcha: wrapper elements
Many layouts add wrappers (grid items, card wrappers, CMS blocks). Suddenly the element you want is no longer a “child” of the parent you thought.
.card:first-child {
background: #ffe08a;
}
.cards > .card-wrap:first-child .card {
background: #ffe08a;
}
.cards > .card-wrap:first-child .card {
background: #ffe08a;
}
.cards > .card-wrap:first-child {
outline: 4px solid #111;
}
*,
::before,
::after {
box-sizing: border-box;
}
.cards {
padding: 16px;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
font-family: system-ui, ui-sans-serif, sans-serif;
}
.card-wrap {
border: 2px dashed rgba(0, 0, 0, 0.35);
border-radius: 14px;
padding: 10px;
background: #fff;
}
.card {
border: 2px solid #111;
border-radius: 12px;
padding: 12px;
background: #f7f7f7;
}
.card p {
margin: 0;
}
Card 1 (inside a wrapper)
Card 2
Card 3
The “first child” might be the wrapper, not the card. In that case, you target the wrapper first, then style what’s inside it.
Gotcha: mixed siblings
If your parent starts with a different element (like a heading, an image, or a “featured” banner), your selector may stop matching.
.article p:first-child {
background: #ffe08a;
}
.article p:first-of-type {
background: #ffe08a;
}
.article > *:first-child {
outline: 4px solid #111;
}
*,
::before,
::after {
box-sizing: border-box;
}
.article {
margin: 16px;
padding: 16px;
border: 2px solid #111;
border-radius: 14px;
background: #f7f7f7;
font-family: system-ui, ui-sans-serif, sans-serif;
}
.article > * {
margin: 10px 0;
padding: 10px;
border-radius: 10px;
border: 1px dashed rgba(0, 0, 0, 0.35);
}
.article h3 {
margin: 0;
}
.article p {
margin: 0;
}
Title injected by the CMS
This paragraph looks “first”, but it is not the first child.
Another paragraph.
Practical patterns you’ll actually use
Remove top margin from the first item
A super common pattern: you want spacing between items, but you don’t want the first one to push the whole group down.
.stack > * {
margin-top: 16px;
}
.stack > *:first-child {
margin-top: 0px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
padding: 16px;
font-family: system-ui, ui-sans-serif, sans-serif;
}
.stack {
border: 2px solid #111;
border-radius: 14px;
padding: 16px;
background: #f7f7f7;
}
.block {
border: 2px solid #111;
border-radius: 12px;
padding: 12px;
background: #fff;
}
First block (no top margin)Second blockThird block
This is often nicer than adding “special” classes like .is-first in your HTML.
Style the first list item like a header
Sometimes you have a list and the first item is the “title” or “featured” entry.
.menu > li:first-child {
font-weight: 700;
}
.menu > li:first-child {
font-weight: 700;
background: #ffe08a;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
padding: 16px;
font-family: system-ui, ui-sans-serif, sans-serif;
}
.menu {
list-style: none;
padding: 0;
margin: 0;
border: 2px solid #111;
border-radius: 14px;
overflow: hidden;
}
.menu li {
padding: 12px 14px;
border-top: 1px solid rgba(0, 0, 0, 0.2);
background: #f7f7f7;
}
.menu li:first-child {
border-top: none;
}
.menu a {
color: inherit;
text-decoration: none;
}
Make the first card “featured”
This is great for “featured post”, “top product”, “latest release”, etc.
.grid > .card:first-child {
grid-column: span 2;
}
.grid > .card:first-child {
grid-column: span 2;
background: #ffe08a;
}
.grid > .card:first-child {
grid-column: span 2;
background: #ffe08a;
transform: translateY(-6px);
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
font-family: system-ui, ui-sans-serif, sans-serif;
}
.card {
border: 2px solid #111;
border-radius: 14px;
padding: 12px;
background: #f7f7f7;
}
.card p {
margin: 0;
}
Featured card (first child)
Card 2
Card 3
Card 4
Card 5
Card 6
Combining :first-child with other selectors
1) :first-child with a class filter
Important to note: .thing:first-child means “an element with class thing that is also first child”.
It does not mean “the first element with class thing”.
.tag:first-child {
background: #ffe08a;
}
.tag:first-of-type {
background: #ffe08a;
}
.tag:first-child {
background: #ffe08a;
}
.note {
outline: 4px solid #111;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
padding: 16px;
font-family: system-ui, ui-sans-serif, sans-serif;
}
.row {
border: 2px solid #111;
border-radius: 14px;
padding: 12px;
background: #f7f7f7;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.row > div {
border: 2px solid #111;
padding: 8px 10px;
border-radius: 999px;
background: #fff;
}
.note {
border-style: dashed;
}
I am first child, but not .tagTag ATag BTag C
If you want “the first .tag”, you might want .tag:first-of-type only if tags are the same element type.
If you really want “the first .tag” regardless of element type, you will need :nth-child(N of S). Learn more in the CSS Nth Child (N of Selector) Interactive Tutorial.
2) :first-child with :not()
You can exclude certain cases. For example, style the first child unless it’s a “disabled” item.
.list > li:first-child:not(.disabled) {
background: #b9ffa6;
}
.list > li:first-child:not(.disabled) {
background: #b9ffa6;
font-weight: 700;
}
.list > li:first-child:not(.disabled) {
background: #b9ffa6;
font-weight: 700;
}
.list > li.disabled {
opacity: 0.5;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
padding: 16px;
font-family: system-ui, ui-sans-serif, sans-serif;
}
.list {
margin: 0;
padding: 0;
list-style: none;
border: 2px solid #111;
border-radius: 14px;
overflow: hidden;
background: #f7f7f7;
}
.list li {
padding: 12px 14px;
border-top: 1px solid rgba(0, 0, 0, 0.2);
}
.list li:first-child {
border-top: none;
}
- First item is disabled
- Second item
- Third item
In this case, nothing is highlighted because the first item is disabled, and the selector is specifically about the first child.
Learn more about the :not() pseudo-class in the CSS :not Interactive Tutorial.
Debugging when :first-child “doesn’t work”
When a :first-child selector doesn’t match, it’s almost always one of these:
- You’re not targeting the correct parent. Your element is inside a wrapper you forgot about.
- Something else is the actual first child (a heading, an image, a hidden element, etc.).
- Your selector is too broad and matches something unexpected (nested lists are a classic).
A mini checklist
- Inspect the element in DevTools and look at its parent.
- Look at the parent’s children in order. What is child number one?
-
Try temporarily styling
:first-childon all children:.parent > *:first-child. -
Add
>to ensure you’re selecting direct children when you intend to.
.parent > *:first-child {
outline: 4px solid #111;
}
.parent > *:first-child {
outline: 4px solid #111;
}
.parent > * {
background: #f2f2f2;
}
.parent > *:first-child {
outline: 4px solid #111;
}
.parent > * {
background: #f2f2f2;
}
.parent > *:first-child {
background: #ffe08a;
}
*,
::before,
::after {
box-sizing: border-box;
}
.parent {
margin: 16px;
padding: 16px;
border: 2px solid #111;
border-radius: 14px;
background: #fff;
font-family: system-ui, ui-sans-serif, sans-serif;
}
.parent > * {
border: 2px solid #111;
border-radius: 12px;
padding: 12px;
margin: 10px 0;
}
Child 1Child 2 (a paragraph)
Child 3
That “debug selector” (.parent > *:first-child) is one of the fastest ways to see what’s actually first.
Quick reference
-
.box:first-childselects .box only if it is the first child of its parent. -
.parent > :first-childselects the parent’s first direct child, whatever it is. -
p:first-childselects aponly if the parent’s first child is ap. -
p:first-of-typeselects the firstpamong siblings, even if it’s not the first child.
Wrap-up
:first-child is simple, but it’s very literal. It doesn’t guess what you meant. It looks at the parent, looks at child number one, and says: “Is this you?” If yes, you get the style. If not, better luck next selector.
Once you start thinking in parent-child relationships (and you make peace with wrappers), :first-child becomes one of those small CSS tools you’ll reach for constantly.
Learn even more about :nth-child in the CSS Nth Child Interactive Tutorial.
