Skip to main content

CSS Pseudo-Classes Cheatsheet

Complete reference for all CSS pseudo-classes.
Click any example to copy the code to your clipboard.

Interactive Demos

:hover Demo

button:hover {
  background: primary/80;
  transform: scale(1.05);
  box-shadow: 0 10px 25px rgba(0,0,0,0.2);
}

:focus vs :focus-visible Demo

Tip: :focus-visible only shows outline when using keyboard navigation (Tab key), not mouse clicks.

:checked Demo

input:checked + span {
  font-weight: bold;
  color: var(--primary);
}

:valid / :invalid Demo

Type an email to see validation styles

input:valid { border-color: green; }
input:invalid { border-color: red; }

:focus-within Demo

This container uses :focus-within

.container:focus-within {
  border-color: primary;
  background: primary/5;
}

:nth-child() Interactive Demo

Odd elements (1st, 3rd, 5th...)

1
2
3
4
5
6
7
8
9
10
li:nth-child(odd) {
  background: var(--primary);
  color: white;
}

:has() - The Parent Selector (Game-Changer!)

Finally! Select parent elements based on their children. This was impossible in CSS for decades.

Logo

Card with image (styled with :has)

Card without image (no :has styles)

/* Style parent based on child */
.card:has(img) {
  background: primary/10;
  border-color: primary/30;
}

/* Style form if any input is invalid */
form:has(input:invalid) {
  border-color: red;
}

/* Show sibling when checkbox is checked */
input:has(+ .dropdown:focus) {
  border-color: blue;
}

User Action

Pseudo-classes that respond to user interactions

:hoverAll browsers

Applies when mouse is over the element

button:hover { background: blue; }
Click to copy
:activeAll browsers

Applies while element is being clicked/pressed

button:active { transform: scale(0.95); }
Click to copy
:focusAll browsers

Applies when element has focus (clicked or tabbed to)

input:focus { border-color: blue; }
Click to copy
:focus-visible95%+ support

Applies when element has focus AND user is using keyboard navigation

button:focus-visible { outline: 2px solid blue; }
Click to copy
:focus-within95%+ support

Applies when element OR any of its descendants has focus

form:focus-within { box-shadow: 0 0 10px blue; }
Click to copy

Form States

Pseudo-classes for form element states and validation

:checkedAll browsers

Applies to checked checkboxes, radios, or selected options

input:checked + label { font-weight: bold; }
Click to copy
:indeterminateAll browsers

Checkbox in indeterminate state (neither checked nor unchecked)

input:indeterminate { opacity: 0.5; }
Click to copy
:disabledAll browsers

Disabled form elements

input:disabled { background: #eee; cursor: not-allowed; }
Click to copy
:enabledAll browsers

Enabled form elements (default state)

input:enabled { background: white; }
Click to copy
:requiredAll browsers

Form elements with required attribute

input:required { border-left: 3px solid red; }
Click to copy
:optionalAll browsers

Form elements without required attribute

input:optional { border-left: 3px solid gray; }
Click to copy
:validAll browsers

Form elements with valid input

input:valid { border-color: green; }
Click to copy
:invalidAll browsers

Form elements with invalid input

input:invalid { border-color: red; }
Click to copy
:in-rangeAll browsers

Input with value within min/max range

input[type='number']:in-range { background: lightgreen; }
Click to copy
:out-of-rangeAll browsers

Input with value outside min/max range

input[type='number']:out-of-range { background: lightcoral; }
Click to copy
:placeholder-shown95%+ support

Input currently showing placeholder text

input:placeholder-shown { font-style: italic; }
Click to copy
:defaultAll browsers

Default form element in a group (default button, initially selected option)

input:default { box-shadow: 0 0 2px blue; }
Click to copy
:read-onlyAll browsers

Elements with readonly attribute

input:read-only { background: #f5f5f5; }
Click to copy
:read-writeAll browsers

Editable elements (inputs without readonly)

input:read-write { background: white; }
Click to copy

Structural (Tree)

Pseudo-classes based on element position in the DOM tree

:rootAll browsers

The document root element (usually <html>)

:root { --primary-color: blue; }
Click to copy
:emptyAll browsers

Elements with no children (including text nodes)

p:empty { display: none; }
Click to copy
:first-childAll browsers

First child of its parent

li:first-child { font-weight: bold; }
Click to copy
:last-childAll browsers

Last child of its parent

li:last-child { border-bottom: none; }
Click to copy
:only-childAll browsers

Element that is the only child of its parent

p:only-child { margin: 0; }
Click to copy
:first-of-typeAll browsers

First element of its type among siblings

p:first-of-type { font-size: 1.2em; }
Click to copy
:last-of-typeAll browsers

Last element of its type among siblings

p:last-of-type { margin-bottom: 0; }
Click to copy
:only-of-typeAll browsers

Only element of its type among siblings

img:only-of-type { display: block; margin: auto; }
Click to copy
:nth-child(n)All browsers

Element based on position among siblings (1-indexed)

tr:nth-child(2n) { background: #f5f5f5; }
Click to copy
:nth-last-child(n)All browsers

Like :nth-child but counting from the end

li:nth-last-child(2) { color: gray; }
Click to copy
:nth-of-type(n)All browsers

Element based on position among same-type siblings

p:nth-of-type(odd) { background: #f0f0f0; }
Click to copy
:nth-last-of-type(n)All browsers

Like :nth-of-type but counting from the end

p:nth-last-of-type(1) { font-weight: bold; }
Click to copy

Logical

Pseudo-classes for complex selector logic

:not()All browsers

Matches elements that do NOT match the selector

input:not([type='submit']) { border: 1px solid gray; }
Click to copy
:is()95%+ support

Matches any of the given selectors (forgiving - ignores invalid selectors)

:is(h1, h2, h3) { color: navy; }
Click to copy
:where()95%+ support

Like :is() but with zero specificity

:where(article, section) p { line-height: 1.6; }
Click to copy
:has()Modern browsers

Parent selector - matches elements containing the specified selector (game-changer!)

article:has(img) { display: grid; }
Click to copy

Other

Additional useful pseudo-classes

:targetAll browsers

Element whose ID matches the URL fragment (e.g., #section1)

section:target { background: yellow; }
Click to copy
:scope95%+ support

Reference element for selectors (usually :root in stylesheets)

:scope > p { margin: 0; }
Click to copy
:lang()All browsers

Elements with specific language attribute

p:lang(ko) { font-family: 'Noto Sans KR'; }
Click to copy
:dir()Modern browsers

Elements with specific text direction (ltr or rtl)

p:dir(rtl) { text-align: right; }
Click to copy

:nth-child() Formula Reference

The :nth-child() formula is An+B where:

  • A = cycle size (how often to repeat)
  • n = counter starting from 0
  • B = offset (where to start)
FormulaDescriptionMatches
:nth-child(odd)Odd elements (1st, 3rd, 5th...)1, 3, 5, 7, 9
:nth-child(even)Even elements (2nd, 4th, 6th...)2, 4, 6, 8, 10
:nth-child(2n)Every 2nd element (same as even)2, 4, 6, 8, 10
:nth-child(2n+1)Every 2nd, starting from 1st (same as odd)1, 3, 5, 7, 9
:nth-child(3n)Every 3rd element3, 6, 9
:nth-child(3n+1)Every 3rd, starting from 1st1, 4, 7, 10
:nth-child(n+4)4th element and beyond4, 5, 6, 7, 8, 9, 10
:nth-child(-n+3)First 3 elements only1, 2, 3
:nth-child(5)Only the 5th element5

Common Patterns & Use Cases

Zebra Striping

tr:nth-child(even) {
  background: #f5f5f5;
}

Remove Last Border

li:not(:last-child) {
  border-bottom: 1px solid #ddd;
}

Form Validation Styles

input:valid { border-color: green; }
input:invalid { border-color: red; }
input:focus:invalid { outline: red; }

Accessible Focus Styles

button:focus-visible {
  outline: 2px solid blue;
  outline-offset: 2px;
}

Style All Headings

:is(h1, h2, h3, h4) {
  color: navy;
  font-weight: bold;
}

Conditional Parent Styling

/* Style card if it has an image */
.card:has(img) {
  display: grid;
  grid-template-columns: 200px 1fr;
}

Browser Support Legend

All browsersSupported everywhere
95%+ supportAll modern browsers
Modern browsersChrome 105+, Safari 15.4+, Firefox 121+