The :nth-child() pseudo-class targets elements by their position among siblings. It powers zebra stripes, grid patterns, and precise positional styling.
01
By position
1-based index.
02
odd / even
Striped rows.
03
2n, 3n+1
Formulas.
04
li:nth-child
List patterns.
05
Tables
Row striping.
06
vs nth-of-type
Know the diff.
Fundamentals
Introduction
The :nth-child() selector in CSS allows you to target elements based on their position within a parent element. This pseudo-class is extremely flexible, letting you style elements based on patterns or specific positions.
Whether you are working with tables, lists, or any repeated HTML structure, :nth-child() is a powerful tool for dynamic styling.
Definition and Usage
Write element:nth-child(n) where n is a number, the keyword odd or even, or a formula like 2n+1.
💡
Beginner Tip
Counting starts at 1, not 0. :nth-child(1) is the first child. :nth-child(odd) and :nth-child(2n+1) select the same rows — items 1, 3, 5, and so on.
Foundation
📝 Syntax
The syntax for the :nth-child() pseudo-class is:
syntax.css
element:nth-child(n){/* CSS properties */}
element is the tag you want to style. n can be a number, keyword, or an+b formula.
Common Patterns
Expression
Matches children at positions…
:nth-child(2)
2 (second child only)
:nth-child(odd)
1, 3, 5, 7, …
:nth-child(even)
2, 4, 6, 8, …
:nth-child(2n)
2, 4, 6, 8, … (same as even)
:nth-child(2n+1)
1, 3, 5, 7, … (same as odd)
:nth-child(3n+1)
1, 4, 7, 10, …
The an+b Formula
n is a counter starting at 0, increasing by 1 for each child.
a is the step size — how often to select (e.g. every 2nd, every 3rd).
b is the offset — the starting position in the sequence.
The first row gets header styling via :nth-child(1). Even data rows get a subtle gray background for zebra striping.
Tips
💬 Usage Tips
Use odd/even keywords — More readable than 2n+1 for simple striping.
Combine selectors — ul li:nth-child(2) scopes to list items inside a ul.
Test formulas — Plug n=0,1,2 into an+b to verify which positions match.
Tables and grids — tr:nth-child(even) is the classic zebra table pattern.
When type matters — Switch to :nth-of-type() if mixed tags break your count.
Watch Out
⚠️ Common Pitfalls
Counts all children — A <div> before your <li> shifts the count; use :nth-of-type() if needed.
1-based, not 0-based — The first child is :nth-child(1), not 0.
Complex formulas — Double-check a (step) and b (offset) in an+b expressions.
p:nth-child(2) trap — Matches a p only if it is the second child overall, not the second paragraph.
Overlapping rules — Multiple :nth-child() rules can apply to the same element; watch specificity.
A11y
♿ Accessibility
Contrast on stripes — Alternating row colors must still meet WCAG contrast requirements.
Do not rely on color alone — Pair zebra stripes with clear borders or labels where needed.
Semantic tables — Use <th> for headers; :nth-child(1) on tr is not a substitute.
Lists stay lists — Use proper <ul>/<ol> markup for screen readers.
🧠 How :nth-child() Works
1
Browser lists siblings
All children inside the parent are numbered starting from 1.
Index
2
Evaluates n expression
The value inside :nth-child() is tested against each position.
Match
3
Filters by element
Only elements matching the tag before :nth-child() receive styles.
Filter
=
📊
Pattern-based styling
Stripes, highlights, and grid rhythms appear without extra HTML classes.
Compatibility
🖥 Browser Compatibility
:nth-child() is supported in all modern browsers and has been available since CSS3 Selectors.
✓ Baseline · Universal support
Positional selectors everywhere
:nth-child() works reliably in Chrome, Firefox, Safari, Edge, and Opera.
99%Universal support
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions
Full support
OperaAll modern versions
Full support
:nth-child() pseudo-class99% supported
Bottom line::nth-child() is safe for lists, tables, and layout patterns in all modern projects.
Wrap Up
🎉 Conclusion
The CSS :nth-child() selector provides a robust way to style elements based on their position within a parent container. It enables dynamic, patterned styling that improves maintainability.
From simple zebra stripes to complex an+b formulas, mastering :nth-child() helps you handle lists, tables, and grids with ease.
Scope with parent selectors like ul li:nth-child()
Use :nth-of-type() when mixed tags break counts
Combine with :not() for refined patterns
❌ Don’t
Assume counting starts at 0
Expect p:nth-child(2) to mean second paragraph
Forget that all sibling types are counted
Overcomplicate when odd/even suffices
Rely on stripe color alone for meaning
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about :nth-child()
Use these points when styling by position.
5
Core concepts
#n01
By position
1-based index.
Purpose
odd02
Keywords
odd / even.
Syntax
2n03
Formulas
an+b.
Pattern
≠04
vs nth-of-type
All children.
Compare
🌐05
99% support
All browsers.
Compat
❓ Frequently Asked Questions
The :nth-child() pseudo-class matches elements based on their position among all sibling children inside a parent. You pass a number, odd, even, or an an+b formula inside the parentheses.
Counting starts at 1, not 0. :nth-child(1) matches the first child, :nth-child(2) the second, and so on.
They select the same elements — odd-numbered children (1, 3, 5, …). :nth-child(even) is equivalent to :nth-child(2n).
:nth-child() counts all sibling children regardless of tag type. :nth-of-type() counts only siblings of the same element type.
Yes. All modern browsers support :nth-child(). It has been available since CSS3 Selectors and works reliably for lists, tables, and grids.