CSS Pseudo-Classes and Pseudo-Elements: The Complete Styling Guide

CSS Pseudo-Classes and Pseudo-Elements: The Complete Styling Guide
2 views

CSS pseudo-classes and pseudo-elements are some of the most underused CSS features — letting you style elements based on state, position, and relationships without JavaScript or extra HTML. :has() (the parent selector) finally arrived in modern browsers, and :is()/:where() slash specificity headaches.

⚡ TL;DR: Pseudo-class: :hover, :focus, :active, :nth-child, :not, :has, :is, :where. Pseudo-element: ::before, ::after, ::placeholder, ::first-line. :has() selects parents. :not() excludes. :nth-child(even/odd/3n+1) for patterns. ::before/::after add content without HTML.

State pseudo-classes — CSS pseudo-classes

/* :hover :focus :active :visited */
button:hover  { background: #1d4ed8; }
button:active { transform: scale(0.98); }
input:focus   { outline: 2px solid #2563eb; outline-offset: 2px; }
a:visited     { color: purple; }

/* :focus-visible — keyboard focus only (not mouse click) */
button:focus-visible { outline: 2px solid #2563eb; } /* Accessibility! */
button:focus:not(:focus-visible) { outline: none; }  /* Remove for mouse */

/* :disabled :enabled :checked :required :optional */
input:disabled { opacity: 0.5; cursor: not-allowed; }
input:invalid  { border-color: #ef4444; }
input:valid    { border-color: #10b981; }

:nth-child and structural selectors

/* :first-child :last-child :only-child :nth-child */
li:first-child { font-weight: bold; }
li:last-child  { border-bottom: none; }
li:nth-child(even) { background: #f8fafc; }
li:nth-child(3n+1) { /* Every 3rd, starting at 1: 1,4,7,10... */ }

/* :nth-of-type: count only matching type */
p:nth-of-type(2) { /* Second 

, ignoring other elements */ } /* :not() — exclude specific elements */ button:not([disabled]) { cursor: pointer; } li:not(:last-child) { border-bottom: 1px solid #e2e8f0; }

:has() — the parent selector

/* Select parent based on child — CSS's biggest missing feature, now here! */

/* Form label if required input inside */
label:has(input:required) { font-weight: bold; }
label:has(input:required)::after { content: ' *'; color: red; }

/* Card with image gets different layout */
.card:has(img) { grid-template-rows: auto 1fr; }
.card:not(:has(img)) { padding: 32px; }

/* Sibling selection with :has + ~ */
/* When checkbox is checked, style following sibling */
:has(input[type=checkbox]:checked) ~ .content { display: block; }

::before and ::after pseudo-elements

/* Add decorative content without extra HTML */

/* Tooltip on hover */
[data-tooltip]:hover::before {
  content: attr(data-tooltip); /* Reads HTML attribute */
  position: absolute;
  background: #1e293b;
  color: white;
  padding: 4px 8px;
  border-radius: 4px;
  white-space: nowrap;
}

/* Counter badges */
.badge::after {
  content: counter(badge-count);
  background: #ef4444;
  border-radius: 50%;
}

/* Decorative dividers */
.section-title::before, .section-title::after {
  content: '';
  flex: 1;
  height: 1px;
  background: #e2e8f0;
}
  • ✅ :focus-visible for keyboard-only focus styles (accessibility)
  • ✅ :has() for parent selection — no more JS for this pattern
  • ✅ :is()/:where() to reduce specificity in complex selectors
  • ✅ ::before/::after for decorative content without HTML
  • ❌ :has() not supported in Firefox before 121 — check caniuse
  • ❌ Excessive use of ::before/after for functional content — use real HTML

External reference: MDN CSS Pseudo-classes.

Recommended Reading

→ Designing Data-Intensive Applications — The bible of distributed systems and production engineering at scale.

→ The Pragmatic Programmer — Timeless engineering wisdom every senior developer needs.

Affiliate links. We earn a small commission at no extra cost to you.

Free Weekly Newsletter

🚀 Join 2,000+ Senior Developers

Get expert-level JavaScript, Python, AWS, system design and AI secrets every week. Zero fluff, pure signal.

✓ No spam✓ Unsubscribe anytime✓ Expert-level only

Related: CSS Flexbox and Grid: The Complete Layout Guide With Every Property Explained · CSS Animations and Transitions: Performance-Optimized Motion for Modern UIs · CSS Grid Advanced Patterns: Build Any Layout With Grid Template Areas

Related: Time-Saving One-Liners Every Developer Should Know · API Debugging in 30 Seconds: The Fastest Ways to Fix API Issues

Deep-dive PDF

Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.

Already subscribed? or open the subscribe page.


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a comment

No account needed. Name and email are optional.