CSS Explained: Why Is not My :nth-child(1) Selector Working?

Published: 2026-02-21
Author: DP
Views: 0
Category: CSS
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