CSS Cheatsheet

Pseudo-classes and Elements

Use this CSS reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Pseudo-class Syntax

Pseudo-classes select elements based on state, position, or relationship without adding markup. They use a single colon :.

a:hover   { color: blue; }
li:first-child { font-weight: bold; }
input:focus { outline: 2px solid blue; }

User Interaction / State

Pseudo-classMatches
:hoverPointer is over the element
:activeElement is being activated (mousedown)
:focusElement has focus
:focus-visibleFocus shown via keyboard (UA heuristic)
:focus-withinElement or any descendant has focus
:visited<a> to a URL in history
:link<a> with href that has NOT been visited
:any-linkAny <a>, <area>, <link> with href
:local-linkSame-origin link (limited support)
:targetElement whose id matches the URL fragment
:target-withinElement or descendant is :target
a:link    { color: blue; }
a:visited { color: purple; }
a:hover   { text-decoration: underline; }
a:active  { color: red; }
/* LVHA order matters! */

button:focus-visible { outline: 3px solid blue; outline-offset: 2px; }
input:focus-within { box-shadow: 0 0 0 3px rgba(59,130,246,0.3); }
:target { scroll-margin-top: 5rem; }

Form / Input State

Pseudo-classMatches
:checkedChecked checkbox, radio, or <option>
:indeterminateIndeterminate checkbox/radio/progress
:defaultDefault form element in its group
:disabledDisabled form element
:enabledNon-disabled form element
:requiredInput with required attribute
:optionalInput without required
:validInput passing constraint validation
:invalidInput failing constraint validation
:in-rangeInput value within min/max
:out-of-rangeInput value outside min/max
:placeholder-shownInput showing its placeholder
:read-onlyNon-editable element (readonly attr or non-input)
:read-writeEditable element
:autofillAutofilled by browser (also :-webkit-autofill)
:blankEmpty user-value input (draft — limited support)
:user-validValid after user interaction (CSS Selectors 4)
:user-invalidInvalid after user interaction
input:valid   { border-color: green; }
input:invalid { border-color: red; }
input:placeholder-shown { font-style: italic; }
input:required::placeholder::after { content: " *"; }  /* not possible — use label */
:disabled { opacity: 0.5; cursor: not-allowed; }
input:autofill { background: lightyellow !important; }

Structural / Tree Position

Pseudo-classMatches
:rootThe root element (usually <html>)
:emptyElement with no children (incl. text nodes)
:first-childFirst child of its parent
:last-childLast child of its parent
:only-childOnly child of its parent
:nth-child(n)nth child
:nth-last-child(n)nth child from end
:first-of-typeFirst of its element type within parent
:last-of-typeLast of its element type
:only-of-typeOnly element of its type within parent
:nth-of-type(n)nth of its type
:nth-last-of-type(n)nth of its type from end
:scopeScoping element (:root in stylesheets)
li:first-child { border-top: none; }
li:last-child  { border-bottom: none; }
tr:nth-child(even) { background: #f9f9f9; }
tr:nth-child(odd)  { background: #fff; }
p:nth-of-type(2)   { color: gray; }
div:empty { display: none; }

nth-child() Formulas

ExpressionSelects
odd / 2n+11, 3, 5…
even / 2n2, 4, 6…
3Exactly the 3rd
3nEvery 3rd (3, 6, 9…)
3n+22, 5, 8, 11…
-n+3First 3 (counting back from 3)
n+44th and beyond
/* CSS Selectors 4: nth-child with selector list */
:nth-child(even of .item) { background: #f0f0f0; }

Logical / Relational

Pseudo-classMatches
:is(sel1, sel2)Matches any selector in list; inherits highest specificity
:where(sel1, sel2)Like :is() but zero specificity
:not(sel1, sel2)Does NOT match any selector in list
:has(rel-sel)Has a descendant/sibling matching rel-sel
/* :is() */
:is(h1, h2, h3) { font-weight: 600; }
:is(article, section) > p { margin-top: 0; }

/* :where() — zero specificity, easy to override */
:where(header, footer) a { color: inherit; }

/* :not() */
a:not([href]) { color: gray; }
:not(h1):not(h2) { font-size: 1rem; }

/* :has() — "parent selector" */
form:has(:invalid) { border: 1px solid red; }
li:has(> a:hover) { background: #f0f0f0; }
h2:has(+ p) { margin-bottom: 0.25rem; }
.card:has(img) { padding: 0; }
article:not(:has(h2)) { display: none; }

Page and Print

Pseudo-classMatches
:firstFirst printed page (in @page)
:leftLeft-side printed pages
:rightRight-side printed pages
:blankBlank printed pages
@page :first { margin-top: 4cm; }
@page :left  { margin-left: 3cm; }
@page :right { margin-right: 3cm; }

Language and Direction

:lang(en)    { quotes: '"' '"'; }
:lang(fr)    { quotes: '«' '»'; }
:dir(ltr)    { text-align: left; }
:dir(rtl)    { text-align: right; }

Fullscreen and Modal

:fullscreen         { background: black; }
:-webkit-full-screen { background: black; }
:modal              { background: white; box-shadow: 0 0 0 100vmax rgba(0,0,0,0.5); }
:picture-in-picture { opacity: 0.5; }

Miscellaneous

:defined     { /* elements that have been defined (custom elements) */ }
:host        { /* shadow host from within shadow DOM */ }
:host(.open) { /* host with .open class */ }
:host-context(.dark) { color: white; } /* host inside .dark ancestor */
:global(.cls) { /* escape local scope in CSS Modules */ }
:local(.cls)  { /* CSS Modules local scope */ }
:playing      { /* media element currently playing */ }
:paused       { /* media element paused */ }
:seeking      { /* media element seeking */ }
:muted        { /* media element muted */ }
:volume-locked { /* media volume locked */ }
:open         { /* <details> or <select> that is open */ }
:popover-open { /* popover in open state */ }

Pseudo-element Syntax

Pseudo-elements create a virtual element or select a specific part of an element. They use double colon :: (: works for legacy :before/:after but :: is preferred).

.item::before { content: "→ "; }
p::first-line { font-weight: bold; }
::selection   { background: #b3d4fc; }

::before and ::after

.required::after {
  content: " *";
  color: red;
}

.quote::before { content: open-quote; }
.quote::after  { content: close-quote; }

/* Decorative line */
.section-title::after {
  content: "";
  display: block;
  height: 2px;
  background: currentColor;
  margin-top: 0.5rem;
}

/* Clearfix */
.group::after {
  content: "";
  display: table;
  clear: both;
}

content values:

content: "";                          /* empty string — required for display */
content: "text";
content: attr(data-label);           /* attribute value */
content: url("/icon.svg");           /* image */
content: open-quote;
content: close-quote;
content: no-open-quote;
content: counter(section);          /* counter value */
content: counters(item, ".");
content: " (" attr(href) ")";       /* combine strings */
content: none;                       /* suppress inherited ::before/::after */
content: normal;                     /* as if not specified */

::first-line and ::first-letter

p::first-line {
  font-weight: bold;
  text-transform: uppercase;
}

p::first-letter {
  font-size: 3em;
  float: left;
  margin-right: 0.1em;
  line-height: 1;
}
/* Only font, color, background, text decoration, margin, padding, border, float,
   line-height, word-spacing, letter-spacing, text-transform are allowed */

::selection

::selection {
  background: #b3d4fc;
  color: #000;
  /* Only color, background, text-shadow, text-decoration allowed */
}
::selection { text-shadow: none; }

::marker

li::marker {
  color: teal;
  content: "▸ ";
  font-size: 0.75em;
}
summary::marker { content: ""; } /* hide default triangle */
summary::-webkit-details-marker { display: none; }

::placeholder

input::placeholder {
  color: #9ca3af;
  font-style: italic;
  opacity: 1;   /* Firefox sets 0.54 by default */
}

::backdrop

/* Behind dialog, fullscreen, popover */
dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(4px);
}
:fullscreen::backdrop { background: black; }

::file-selector-button

input[type="file"]::file-selector-button {
  padding: 0.4rem 0.8rem;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: #f0f0f0;
  cursor: pointer;
}

::cue

/* WebVTT captions */
video::cue        { background: rgba(0,0,0,0.8); color: white; }
video::cue(b)     { font-weight: bold; }
video::cue(.warning) { color: yellow; }

Shadow DOM Pseudo-elements

/* Target named parts exported by a custom element */
my-element::part(button) { background: blue; }
my-element::part(icon)   { width: 1em; }

/* Slotted content in shadow DOM */
::slotted(p)   { margin: 0; }
::slotted(.highlighted) { background: yellow; }

::spelling-error and ::grammar-error

/* Limited support — browser-controlled */
::spelling-error { text-decoration: wavy red underline; }
::grammar-error  { text-decoration: wavy green underline; }

CSS Nesting with Pseudo-classes

.btn {
  background: blue;

  &:hover { background: darkblue; }
  &:focus-visible { outline: 3px solid blue; }
  &:disabled { opacity: 0.5; }
  &:is(:hover, :focus) { color: white; }
  &::before { content: "→ "; }
}

Specificity of Pseudo-classes and Elements

SelectorSpecificity
::before, ::after, ::first-line0-0-0-1 (element)
:hover, :focus, :nth-child()0-0-1-0 (class)
:is(), :not(), :has()inherits from most specific argument
:where()0-0-0-0 always