Skip to main content

CSS Selectors Cheatsheet

Basic Selectors

SelectorSyntaxMatches
Universal*Every element
ElementdivAll <div> elements
Class.cardElements with class="card"
ID#navElement with id="nav"
Attribute[href]Elements that have href attribute
Attribute =[type="text"]Exact value match
Attribute ^=[href^="https"]Value starts with
Attribute $=[href$=".pdf"]Value ends with
Attribute *=[class*="btn"]Value contains
Attribute ~=[class~="active"]Space-separated word match
Multi-class.card.featuredHas BOTH classes
Grouph1, h2, h3Any of these selectors

Combinators

CombinatorSyntaxMatches
Descendantnav a<a> anywhere inside <nav>
Childul > li<li> direct child of <ul> only
Adjacent siblingh2 + p<p> immediately after <h2>
General siblingh2 ~ pAll <p> after <h2> at same level
Column`col

Pseudo-Classes: Interaction

Pseudo-classWhen It Applies
:hoverMouse over element
:focusElement has keyboard focus
:focus-visibleFocus via keyboard (not mouse) — use this for custom focus rings
:focus-withinElement or any descendant is focused
:activeBeing clicked/pressed
:visitedVisited link
:linkUnvisited link

Pseudo-Classes: Form State

Pseudo-classMatches
:checkedChecked checkbox or radio
:disabledDisabled form control
:enabledEnabled form control
:requiredHas required attribute
:optionalDoes NOT have required
:validInput passes validation
:invalidInput fails validation
:in-rangeValue within min/max
:out-of-rangeValue outside min/max
:placeholder-shownPlaceholder is currently displayed
:user-validValid after user interaction
:user-invalidInvalid after user interaction
:read-onlyHas readonly attribute
:read-writeIs editable

Pseudo-Classes: Structural

Pseudo-classMatches
:first-childFirst child of its parent
:last-childLast child of its parent
:only-childOnly child of its parent
:nth-child(n)nth child (1-indexed)
:nth-child(odd)Every odd child: 1, 3, 5...
:nth-child(even)Every even child: 2, 4, 6...
:nth-child(3n)Every 3rd: 3, 6, 9...
:nth-child(3n+1)1, 4, 7, 10...
:nth-last-child(n)nth from the end
:first-of-typeFirst of its tag type
:last-of-typeLast of its tag type
:nth-of-type(n)nth of its tag type
:only-of-typeOnly element of that tag in parent
:emptyNo children or text
:rootThe <html> element
:targetID matches URL hash
:scopeScoped reference point

Pseudo-Classes: Functional (Modern)

Pseudo-classUseSpecificity
:is(h1, h2, h3)Match any in listHighest in list
:not(.active)Exclude matchesHighest arg specificity
:where(h1, h2)Match any in listAlways 0
:has(> img)Parent has matching childHighest arg specificity
:has(input:focus)Parent of focused input

Pseudo-Elements

Pseudo-elementWhat It Creates/Targets
::beforeGenerates first child (needs content:)
::afterGenerates last child (needs content:)
::first-lineFirst rendered line of text
::first-letterFirst letter (drop cap)
::selectionText selected by user
::placeholderInput placeholder text
::markerList item bullet/number
::backdropBehind <dialog> or fullscreen element
::file-selector-buttonFile input button
::spelling-errorMisspelled text (browser-determined)
::-webkit-scrollbarScrollbar (Chrome/Edge)
::-webkit-scrollbar-thumbScrollbar draggable handle

Specificity Quick Reference

[inline] [IDs] [classes/attrs/pseudo-classes] [elements/pseudo-elements]
1 1 1 1

Examples:
style="" = 1,0,0,0
#id = 0,1,0,0
.class, [attr], :hover = 0,0,1,0
div, ::before = 0,0,0,1
* = 0,0,0,0

:is(), :not(), :has() → specificity of their most specific argument
:where() → always 0,0,0,0

Selector Patterns: Quick Copy

/* All headings */
:is(h1, h2, h3, h4, h5, h6) { }

/* Everything except header and footer */
main *:not(header, footer) { }

/* Sibling spacing (lobotomized owl) */
* + * { margin-top: 1em; }

/* First child: no top margin */
.c-stack > :first-child { margin-top: 0; }

/* Last child: no bottom margin */
.c-stack > :last-child { margin-bottom: 0; }

/* Parent of invalid input */
.c-form__group:has(input:invalid) { border-color: var(--color-danger); }

/* Card with image: remove top padding */
.c-card:has(> img:first-child) { padding-top: 0; }

/* Links that open in new tab */
a[target="_blank"]::after { content: ' ↗'; }

/* External links */
a[href^="http"]:not([href*="yourdomain.com"]) { }

/* Zebra table rows */
tr:nth-child(even) { background: var(--color-surface-2); }

/* Last except last (border between items, not after last) */
.c-list__item:not(:last-child) { border-bottom: 1px solid var(--color-border); }