JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicscssCSS Selectors & Specificity
PrevNext
css
beginner
10 min read

CSS Selectors & Specificity

cascade
combinators
fundamentals
has
is
pseudo-classes
pseudo-elements
selectors
specificity
where

CSS selectors target elements for styling using type, class, ID, attribute, and pseudo-class/element patterns, with specificity calculated as a weighted score (inline > ID > class > element) that determines which rule wins when multiple selectors match the same element.

Key Points

1Specificity Weight System

Specificity is calculated as (IDs, Classes/Attributes/Pseudo-classes, Types/Pseudo-elements). A single ID selector (1,0,0) always outweighs any number of class selectors (0,n,0).

2The Cascade Resolution Order

When multiple rules conflict, the browser checks origin/importance first, then cascade layers, then specificity, and finally source order — specificity is only one factor among several.

3Modern Pseudo-Classes

:is() groups selectors with the highest argument's specificity, :where() groups with zero specificity, and :has() enables parent selection based on children — all solving longstanding CSS limitations.

4Combinator Types

Descendant (space) matches any depth, child (>) matches direct children only, adjacent sibling (+) matches the next sibling, and general sibling (~) matches all following siblings.

What You'll Learn

  • Calculate the specificity of any CSS selector and predict which rule wins in a conflict
  • Use combinators (descendant, child, sibling) to target elements precisely
  • Apply :is(), :where(), and :has() to simplify selectors and control specificity
  • Explain the full cascade algorithm from origin through specificity to source order

Deep Dive

CSS selectors and specificity are among the most commonly tested CSS topics in front-end interviews. Understanding how the browser decides which styles to apply when multiple rules conflict is fundamental to writing maintainable CSS.

Selector Types

Simple selectors:

  • Type selector: div, p, a — matches element names
  • Class selector: .card, .active — matches class attribute values
  • ID selector: #header — matches id attribute (should be unique per page)
  • Universal selector: * — matches all elements
  • Attribute selector: [type="text"], [href^="https"] — matches attribute values with optional pattern matching

Combinators:

  • Descendant: article p — any p inside article (any depth)
  • Child: article > p — direct child p of article only
  • Adjacent sibling: h2 + p — the first p immediately after h2
  • General sibling: h2 ~ p — all p elements after h2 at the same level

Pseudo-classes (select elements by state):

  • :hover, :focus, :active — user interaction states
  • :first-child, :last-child, :nth-child(n) — structural position
  • :not(selector) — negation
  • :is(selector-list) — matches any selector in the list with the highest specificity of its arguments
  • :where(selector-list) — same as :is() but with zero specificity (great for defaults that are easy to override)
  • :has(selector) — the "parent selector" that matches elements containing specific children. :has() is revolutionary because CSS historically could never select parents based on children.

Pseudo-elements (create virtual elements):

  • ::before, ::after — generate content before/after the element
  • ::first-line, ::first-letter — style text portions
  • ::placeholder — style input placeholder text
  • ::selection — style highlighted text

Specificity Calculation

Specificity is calculated as a three-component weight (a, b, c):

  • a — Number of ID selectors
  • b — Number of class selectors, attribute selectors, and pseudo-classes
  • c — Number of type selectors and pseudo-elements

Examples:

  • p → (0, 0, 1)
  • .card → (0, 1, 0)
  • #header → (1, 0, 0)
  • #header .nav li.active → (1, 2, 1)
  • div.card:hover → (0, 2, 1)

Higher specificity wins. If specificity is equal, the last rule in source order wins.

Inline styles (style="...") beat all selector-based specificity. !important beats inline styles but should be a last resort.

Specificity Traps

The most common specificity issue: styles from a component library have higher specificity than your custom styles. Solutions:

  1. Write a more specific selector (specificity arms race — not recommended)
  2. Use !important (last resort)
  3. Use :where() in the library for zero-specificity defaults
  4. Use cascade layers (@layer) to control priority regardless of specificity

:is(), :where(), and :has()

These modern pseudo-classes solve longstanding problems:

:is() reduces repetition: :is(h1, h2, h3) a replaces h1 a, h2 a, h3 a. Its specificity is the highest specificity of its arguments.

:where() works identically but has zero specificity — perfect for base styles that should be easy to override.

:has() is the long-awaited parent selector. article:has(img) selects articles that contain images. form:has(:invalid) selects forms with invalid inputs. This opens up styling patterns that previously required JavaScript.

The Cascade Algorithm

When multiple rules match an element, the browser resolves conflicts in this order:

  1. Origin and importance — User agent < user < author (reversed for !important)
  2. Cascade layers — Layer order (if using @layer)
  3. Specificity — Higher specificity wins
  4. Order of appearance — Later rule wins if all else is equal

Understanding this full algorithm is what separates junior from senior CSS knowledge.

Fun Fact

The :has() pseudo-class was called 'the holy grail of CSS selectors' for years because it enables parent selection — something developers had requested since CSS2 in 1998. It finally shipped in all major browsers in late 2023, a 25-year wait.

Continue Learning

Cascade Layers (@layer)

advanced

CSS Custom Properties (Variables)

intermediate

Practice What You Learned

What are CSS selectors and how does specificity work?
junior
selectors
CSS selectors target HTML elements for styling. Specificity determines which rules win when multiple selectors match the same element. The hierarchy is: inline styles (1000) > ID selectors (100) > class/attribute/pseudo-class (10) > element/pseudo-element (1). !important overrides all specificity.
Previous
Responsive Design Fundamentals
Next
CSS Methodologies & Styling Approaches
PrevNext