CSS Selectors & Specificity
Learn how CSS targets elements using element, class, ID, attribute, and pseudo-class selectors. Understand specificity scoring math, pseudo-classes, and cascade resolution rules.
CSS Selectors & Specificity In-Depth Overview & Use Cases
CSS Selectors are the targeting mechanism used by style sheets to apply design rules to specific HTML elements in the DOM tree. Browsers evaluate selectors using a mathematical Specificity Weight scoring algorithm (Inline, ID, Class, Element) to resolve style conflicts when multiple rules target the same element.
Understanding selectors and specificity is vital for clean front-end architecture. Modern CSS has evolved beyond basic class and ID rules to include functional grouping (:is(), :where()) and relational parent selectors (:has()), allowing developers to write modular, low-specificity styles that are easy to maintain.
Key Real-World Use Cases
Using pseudo-classes (:hover, :focus-visible, :active, :checked) to provide feedback on user interactions.
Using the :has() pseudo-class to style card containers differently when an image or video thumbnail is present.
Using :where() in UI component libraries to allow easy style overrides without needing !important.
Using input:invalid and input:required to display real-world validation indicators.
Complete CSS Selector Categories
CSS selectors allow developers to target precise HTML elements for styling based on tag names, classes, IDs, structural position, user interaction state, or attribute values.
| Category | Syntax Example | Description |
|---|---|---|
| Universal | * | Matches every element in the document |
| Type / Element | h1, p, div, button | Matches all elements with specified HTML tag name |
| Class Selector | .btn, .card-title | Matches elements with matching class attribute |
| ID Selector | #header, #main-nav | Matches unique element with matching id attribute |
| Attribute Selector | input[type="text"], [data-active] | Matches elements with specified attribute or value |
| Pseudo-class | a:hover, li:nth-child(2), input:focus-visible | Matches element in dynamic state or structural index |
| Pseudo-element | p::first-line, button::after | Styles specific sub-part or virtual pseudo-content |
CSS Combinators Reference
Combinators define relationships between multiple selectors:
| Combinator Symbol | Name | Matches |
|---|---|---|
| space | Descendant Combinator | All matching child/grandchild elements inside parent |
| > | Child Combinator | Direct immediate child elements of parent |
| + | Adjacent Sibling | Immediate next sibling element sharing same parent |
| ~ | General Sibling | All subsequent sibling elements sharing same parent |
How Specificity Score is Calculated
When multiple CSS rules target the same element, the browser calculates Specificity Weight (Inline, ID, Class, Element) to decide which rule wins:
- Inline Styles (1,0,0,0): Attributes directly on HTML style="..." hold highest priority.
- IDs (0,1,0,0): Count of #id selectors in the rule.
- Classes, Attributes, Pseudo-classes (0,0,1,0): Count of .class, [attr], and :hover selectors.
- Elements & Pseudo-elements (0,0,0,1): Count of tag names (p, div) and ::before pseudo-elements.
Modern CSS Pseudo-Classes: :is(), :where(), and :has()
Modern CSS introduced powerful functional pseudo-classes for grouping and parent querying:
| Pseudo-Class | Specificity Weight | Description / Power |
|---|---|---|
| :is(h1, h2, h3) | Takes specificity of highest selector inside list | Groups multiple selectors into compact syntax |
| :where(h1, h2, h3) | Always 0 (zero specificity) | Zero specificity reset grouping for design systems |
| :has(.card-image) | Takes specificity of selector inside list | The parent selector! Targets parent if child exists |
The !important Exception and Best Practices
Adding !important to a property value overrides all specificity calculations and stylesheet ordering.
Best Practice Warning: Avoid using !important in general styles because it breaks CSS cascade inheritance and makes debugging styles difficult. Use higher specificity selectors or utility classes instead.