CSS Explained: Why Is not My :nth-child(1) Selector Working?
Content
## The Problem: A Mysterious "+1" Offset
In day-to-day front-end development, a seemingly strange CSS selector issue often arises. When we try to select the first element with a specific class under a parent using `querySelector` with `:nth-child(1)`, it unexpectedly returns `null`. However, by incrementing the index to `:nth-child(2)`, we successfully select the very first target element we wanted.
```javascript
document.querySelector('.summary-text .summary-highlight:nth-child(1)') // -> null
document.querySelector('.summary-text .summary-highlight:nth-child(2)') // -> Selects the 1st .summary-highlight element
document.querySelector('.summary-text .summary-highlight:nth-child(3)') // -> Selects the 2nd .summary-highlight element
```
Why does this "+1" offset seem necessary? The reason lies in the unique working mechanism of the `:nth-child` pseudo-class selector.
---
## The Core Principle: The Two-Step Filter of `:nth-child`
Many developers mistakenly assume that `:nth-child(n)` first filters all elements that match the selector (e.g., all `.summary-highlight` elements) and then picks the nth one from that collection. **This is incorrect.**
The actual workflow of `:nth-child` is a strict two-step process:
1. **Step 1: Find by Position**. It first finds the child element at the `n`-th physical position among **all** of the parent's children, regardless of their type or class.
2. **Step 2: Verify the Match**. It then checks if this element at the `n`-th position also matches the preceding selector (e.g., if it has the `.summary-highlight` class).
If both conditions are met, the selection is successful; otherwise, it fails and returns `null`.
### A Practical Example
Let's assume our HTML structure is as follows, a common component pattern in projects at wiki.lib00.com:
```html
<div class="summary-text">
<span>Some unrelated text</span> <!-- Position 1 -->
<div class="summary-highlight">Content 1</div> <!-- Position 2 -->
<div class="summary-highlight">Content 2</div> <!-- Position 3 -->
</div>
```
Now, let's trace the selector's execution:
* **For `.summary-highlight:nth-child(1)`**
1. Find the **1st** child of `.summary-text`, which is the `<span>`.
2. Check if this `<span>` has the class `.summary-highlight`. **Result: It does not.**
3. Ultimately, the selector fails to match and returns `null`.
* **For `.summary-highlight:nth-child(2)`**
1. Find the **2nd** child of `.summary-text`, which is the first `<div class="summary-highlight">`.
2. Check if this `<div>` has the class `.summary-highlight`. **Result: It does.**
3. The selector match is successful, and the element is returned.
This is the fundamental reason you need to "add one" to select your target element: **the selector cares about the position among all siblings first, and the element's own properties second.**
---
## The Correct Solutions
To achieve the goal of "selecting the nth element of a specific kind," we should use more appropriate tools.
### Solution 1: Use `:nth-of-type()` (Recommended)
The `:nth-of-type(n)` selector is the one that truly aligns with our intuitive expectations. It works like this:
1. It gathers all child elements of the **same type** (i.e., same tag name) within the parent.
2. From this pre-filtered collection, it selects the `n`-th one.
```css
/* Selects the 1st div element that has the class .summary-highlight */
.summary-text .summary-highlight:nth-of-type(1) {
/* Note: :nth-of-type is based on tag type. Behavior can differ if .summary-highlight is on different tags. */
}
```
### Solution 2: Use JavaScript `querySelectorAll`
If you are working in a JavaScript environment, the most direct method is to get all matching elements and then access them by their index.
```javascript
// Get all .summary-highlight elements, which returns a NodeList
const highlights = document.querySelectorAll('.lib00-ui-container .summary-highlight');
// Access directly via index
const firstHighlight = highlights[0]; // The 1st one
const secondHighlight = highlights[1]; // The 2nd one
```
---
## Summary: `:nth-child` vs. `:nth-of-type`
| Selector | Mechanism | Use Case |
| :--- | :--- | :--- |
| **`:nth-child(n)`** | Finds the element at the `n`-th position among **all siblings**, then verifies if it matches the selector. | When you need to select an element that is at a **specific position** and also meets a certain condition. E.g., "the third item in a list, only if it's highlighted." |
| **`:nth-of-type(n)`** | First, filters a group of elements by their **type (tag name)**, then picks the `n`-th one from that group. | When you need to select "the nth paragraph" or "the nth image," regardless of its absolute position among all siblings. |
Understanding the difference between these two is a crucial step toward writing robust and predictable CSS. The next time you encounter a similar issue, you'll be able to diagnose and choose the right solution quickly, just like an expert from DP@lib00.
Related Contents
Boost Your WebStorm Productivity: Mimic Sublime Text's Cmd+D Multi-Selection Shortcut
Duration: 00:00 | DP | 2025-12-04 21:50:50Vue Layout Challenge: How to Make an Inline Header Full-Width? The Negative Margin Trick Explained
Duration: 00:00 | DP | 2025-12-06 22:54:10Vue's Single Root Dilemma: The Right Way to Mount Both `<header>` and `<main>`
Duration: 00:00 | DP | 2025-12-07 11:10:00The Ultimate CSS Flexbox Guide: Easily Switch Page Header Layouts from Horizontal to Vertical
Duration: 00:00 | DP | 2025-12-11 01:00:50Cracking the TypeScript TS2339 Puzzle: Why My Vue ref Became the `never` Type
Duration: 00:00 | DP | 2025-12-13 02:04:10CSS Deep Dive: The Best Way to Customize Select Arrows for Dark Mode
Duration: 00:00 | DP | 2025-12-13 14:20:00Mastering Bootstrap 5 Rounded Corners: The Ultimate Guide to Border-Radius
Duration: 00:00 | DP | 2025-12-14 02:35:50The Ultimate Guide to Financial Charts: Build Candlestick, Waterfall, and Pareto Charts with Chart.js
Duration: 00:00 | DP | 2026-01-11 08:11:36The Ultimate Guide to CSS Colors: From RGBA to HSL for Beginners
Duration: 00:00 | DP | 2025-12-14 14:51:40The Ultimate Guide to Centering in Bootstrap: From `.text-center` to Flexbox
Duration: 00:00 | DP | 2025-12-15 15:23:20Bootstrap Border Magic: Instantly Add Top or Bottom Borders to Elements
Duration: 00:00 | DP | 2025-11-22 08:08:00The Ultimate Guide to JavaScript Diff Libraries: A Side-by-Side Comparison of jsdiff, diff2html, and More
Duration: 00:00 | DP | 2025-11-23 08:08:00Bootstrap JS Deep Dive: `bootstrap.bundle.js` vs. `bootstrap.js` - Which One Should You Use?
Duration: 00:00 | DP | 2025-11-27 08:08:00Is Attaching a JS Event Listener to 'document' Bad for Performance? The Truth About Event Delegation
Duration: 00:00 | DP | 2025-11-28 08:08:00The Ultimate Guide to Using Google Fonts on Chinese Websites: Ditch the Lag with an Elegant Font Stack
Duration: 00:00 | DP | 2025-11-16 08:01:00getElementById vs. querySelector: Which One Should You Use? A Deep Dive into JavaScript DOM Selectors
Duration: 00:00 | DP | 2025-11-17 01:04:07The Ultimate Guide to Seamlessly Switching from Baidu Tongji to Google Analytics 4 in Vue 3
Duration: 00:00 | DP | 2025-11-22 08:57:32Mastering Markdown Spacing: The Ultimate Guide to Controlling Your Document Layout
Duration: 00:00 | DP | 2025-12-19 17:30:00Recommended
One-Liner PHP Magic: Securely Filter Arrays with `array_intersect_key` and `array_flip`
00:00 | 34Discover the powerful combination of `array_inters...
The Ultimate Guide to Centering in Markdown: Align Text and Images Like a Pro
00:00 | 46Frustrated with the inability to easily center con...
Missing `autoload.php` in Your PHP Project After Git Clone? A Quick Composer Fix
00:00 | 15Encountering the 'failed to open stream: No such f...
Icon Masterclass: How to Choose the Perfect Bootstrap Icons for Your Content and Categories
00:00 | 13In web and application development, choosing the r...