CSS Selectors: A Complete Reference with Examples
April 12, 2026 · 8 min read
CSS selectors are the mechanism by which styles are applied to HTML elements. Understanding the full range of selectors — from basic type selectors to complex pseudo-classes — lets you write leaner stylesheets and target exactly the elements you need without adding unnecessary classes.
Basic Selectors
Type selector
p { color: white; } /* all <p> elements */
h1 { font-size: 2rem; } /* all <h1> elements */Class selector
.card { border-radius: 8px; }
.card.featured { border: 1px solid gold; } /* element with both classes */ID selector
#header { position: sticky; top: 0; }
/* IDs have high specificity — prefer classes for reusable styles */Universal selector
* { box-sizing: border-box; }
.container > * { margin-bottom: 1rem; } /* all direct children */Attribute Selectors
Attribute selectors match elements based on the presence or value of an attribute.
a[href] /* has href attribute */ a[href="https://io9.me"] /* exact match */ a[href^="https"] /* starts with "https" */ a[href$=".pdf"] /* ends with ".pdf" */ a[href*="github"] /* contains "github" */ input[type="text"] /* type is exactly "text" */ [lang|="en"] /* lang is "en" or starts with "en-" */ [class~="featured"] /* space-separated list contains "featured" */
Combinators
div p /* descendant: any <p> inside a <div> */ div > p /* child: <p> that is a direct child of <div> */ h2 + p /* adjacent sibling: <p> immediately after <h2> */ h2 ~ p /* general sibling: all <p> after <h2> in same parent */
Pseudo-Classes
Pseudo-classes select elements based on state or position, not just their markup.
User interaction states
:hover { background: rgba(255,255,255,0.05); }
:focus { outline: 2px solid cyan; }
:focus-visible { /* keyboard focus only — skip mouse clicks */ }
:active { transform: scale(0.98); }
:visited { color: purple; } /* visited links */Form states
:disabled { opacity: 0.5; cursor: not-allowed; }
:enabled { cursor: pointer; }
:checked { accent-color: cyan; }
:required { border-color: orange; }
:valid { border-color: green; }
:invalid { border-color: red; }
:placeholder-shown { font-style: italic; }Structural pseudo-classes
:first-child /* first child of its parent */ :last-child /* last child */ :nth-child(2) /* second child */ :nth-child(odd) /* odd-numbered children: 1, 3, 5... */ :nth-child(even) /* even-numbered children */ :nth-child(3n+1) /* every 3rd, starting from 1 */ :first-of-type /* first element of its type */ :last-of-type :nth-of-type(2) :only-child /* only child of its parent */ :empty /* no children (including text nodes) */ :not(.disabled) /* negation — anything not matching .disabled */
:is(), :where(), :has()
/* :is() — group selectors, takes highest specificity of the list */
:is(h1, h2, h3) { line-height: 1.2; }
/* :where() — same but always zero specificity */
:where(h1, h2, h3) { line-height: 1.2; }
/* :has() — parent selector (CSS4) */
.card:has(img) { padding: 0; } /* .card that contains an img */
label:has(+ input:required)::after { content: " *"; } /* label before required input */Pseudo-Elements
Pseudo-elements create virtual elements that can be styled independently.
p::first-line { font-weight: bold; }
p::first-letter { font-size: 2em; float: left; }
/* ::before and ::after insert generated content */
.required::after {
content: " *";
color: red;
}
/* ::placeholder */
input::placeholder { color: #888; font-style: italic; }
/* ::selection */
::selection { background: cyan; color: black; }
/* ::marker — style list bullets/numbers */
li::marker { color: cyan; font-weight: bold; }Specificity
When multiple rules target the same element, specificity determines which wins. It is calculated as a three-part score: (ID count, class/attribute/pseudo-class count, element/pseudo-element count).
| Selector | Specificity |
|---|---|
| * | 0-0-0 |
| p | 0-0-1 |
| .card | 0-1-0 |
| #header | 1-0-0 |
| p.card | 0-1-1 |
| #nav a:hover | 1-1-1 |
| style attribute | 1-0-0-0 (always wins) |
Avoid !important except as a last resort. It breaks the natural cascade and makes debugging painful. Instead, increase specificity by scoping the rule or restructuring the HTML. Use the HTML Tools on io9.me to work with HTML entities and escape special characters in your markup.