Structural Pseudo-classes

Back

Loading concept...

🎯 CSS Structural Pseudo-classes: Finding Elements Like a Detective

Imagine you’re a detective at a big family gathering. Everyone is sitting around a huge dinner table. Your job? Find specific people based on where they sit and who they are. That’s exactly what structural pseudo-classes do in CSS!


🏠 The Family Analogy

Think of HTML elements as family members sitting at a table:

  • Parent = The table (container)
  • Children = People sitting at the table
  • First child = Person at the head of the table
  • Last child = Person at the end

Structural pseudo-classes help you pick exactly who you want to style!


πŸ‘Ά Child Selector Pseudo-classes

These find elements based on their position among siblings.

:first-child β€” The Firstborn

Selects an element that is the first child of its parent.

p:first-child {
  color: gold;
  font-weight: bold;
}

Real Talk: If <p> is the very first thing inside its parent, it gets styled!


:last-child β€” The Baby of the Family

Selects the last child of a parent.

li:last-child {
  border-bottom: none;
}

Pro Tip: Great for removing borders on the last list item!


:nth-child(n) β€” The Magic Counter

Pick any child by number! Like saying β€œgive me the 3rd kid.”

/* Every 2nd child (even items) */
tr:nth-child(2n) {
  background: #f0f0f0;
}

/* First 3 children */
li:nth-child(-n+3) {
  font-weight: bold;
}

/* Every 3rd child starting from 2nd */
div:nth-child(3n+2) {
  color: blue;
}

The Formula:

  • 2n = even (2, 4, 6…)
  • 2n+1 = odd (1, 3, 5…)
  • 3n = every third (3, 6, 9…)
  • -n+3 = first three only

:nth-last-child(n) β€” Counting Backwards

Same as nth-child, but starts from the end!

/* Last 2 items */
li:nth-last-child(-n+2) {
  opacity: 0.5;
}

🎨 Type Selector Pseudo-classes

These are pickier! They only count elements of the same type.

:first-of-type β€” First of Its Kind

Selects the first element of that type among siblings.

p:first-of-type {
  font-size: 1.2em;
}

The Difference:

  • :first-child = Must be THE first child (any type)
  • :first-of-type = First <p> even if other things come before it
<div>
  <h2>Title</h2>
  <p>I'm first-of-type!</p>
  <p>I'm second</p>
</div>

Here, the <p> is NOT :first-child (h2 is first), but it IS :first-of-type!


:last-of-type β€” Last of Its Kind

p:last-of-type {
  margin-bottom: 0;
}

:nth-of-type(n) β€” Counting Only Your Type

/* Style every 2nd paragraph */
p:nth-of-type(2n) {
  background: #fffde7;
}

Only counts <p> elements, ignores everything else!


:nth-last-of-type(n) β€” Backwards Type Counting

/* Second-to-last image */
img:nth-last-of-type(2) {
  border: 3px solid red;
}

πŸ‘‘ Only-Element Pseudo-class

:only-child β€” The Only Kid

Matches when an element is the only child of its parent.

p:only-child {
  text-align: center;
  font-style: italic;
}
<div>
  <p>I'm styled! I'm alone here.</p>
</div>

<div>
  <p>I'm NOT styled</p>
  <p>Because I have a sibling</p>
</div>

:only-of-type β€” Only One of Your Kind

An element is the only one of its type among siblings.

img:only-of-type {
  display: block;
  margin: 0 auto;
}

Even if there are other elements, if there’s only ONE image, it matches!


πŸ“­ The :empty Pseudo-class

Selects elements with NO children at all β€” not even text or spaces!

.message:empty {
  display: none;
}

.box:empty::before {
  content: "Nothing here!";
  color: gray;
}

Watch Out! Even a single space breaks :empty:

<div></div>        βœ… Matches :empty
<div> </div>       ❌ Has whitespace
<div>Hi</div>      ❌ Has text

🌳 The :root Pseudo-class

Selects the root element of the document. In HTML, that’s always <html>.

:root {
  --primary-color: #667eea;
  --spacing: 16px;
  font-size: 16px;
}

Why Use It?

  • Define CSS custom properties (variables)
  • Set global styles
  • Higher specificity than html selector
/* Using variables */
button {
  background: var(--primary-color);
  padding: var(--spacing);
}

🎯 The :target Pseudo-class

Matches an element when its ID matches the URL hash.

:target {
  background: yellow;
  animation: highlight 1s ease;
}

@keyframes highlight {
  from { background: orange; }
  to { background: yellow; }
}

How It Works:

  1. URL: page.html#section2
  2. Element: <section id="section2">
  3. That section now matches :target!
<nav>
  <a href="#intro">Intro</a>
  <a href="#details">Details</a>
</nav>

<section id="intro">...</section>
<section id="details">...</section>

Click a link β†’ URL changes β†’ Section highlights!

Cool Uses:

  • Highlight sections when navigated
  • CSS-only tabs (no JavaScript!)
  • Show/hide content

πŸ—ΊοΈ Quick Reference Map

graph LR A["Structural Pseudo-classes"] --> B["Child-based"] A --> C["Type-based"] A --> D["Special"] B --> B1[":first-child"] B --> B2[":last-child"] B --> B3[":nth-child"] B --> B4[":only-child"] C --> C1[":first-of-type"] C --> C2[":last-of-type"] C --> C3[":nth-of-type"] C --> C4[":only-of-type"] D --> D1[":empty"] D --> D2[":root"] D --> D3[":target"]

πŸ’‘ Key Differences to Remember

Scenario :first-child :first-of-type
<div><p>Hi</p></div> βœ… Matches βœ… Matches
<div><h1>...</h1><p>Hi</p></div> ❌ No match βœ… Matches

Simple Rule:

  • Child selectors count ALL siblings
  • Type selectors count only SAME TYPE siblings

πŸš€ You Did It!

Now you can:

  • βœ… Select the first, last, or any numbered child
  • βœ… Target elements by type position
  • βœ… Style lonely elements with :only-child
  • βœ… Handle empty containers with :empty
  • βœ… Set global variables with :root
  • βœ… Create dynamic highlights with :target

You’re now a CSS detective! Go find those elements! πŸ”

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.