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-class | Matches |
|---|---|
:hover | Pointer is over the element |
:active | Element is being activated (mousedown) |
:focus | Element has focus |
:focus-visible | Focus shown via keyboard (UA heuristic) |
:focus-within | Element or any descendant has focus |
:visited | <a> to a URL in history |
:link | <a> with href that has NOT been visited |
:any-link | Any <a>, <area>, <link> with href |
:local-link | Same-origin link (limited support) |
:target | Element whose id matches the URL fragment |
:target-within | Element 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-class | Matches |
|---|---|
:checked | Checked checkbox, radio, or <option> |
:indeterminate | Indeterminate checkbox/radio/progress |
:default | Default form element in its group |
:disabled | Disabled form element |
:enabled | Non-disabled form element |
:required | Input with required attribute |
:optional | Input without required |
:valid | Input passing constraint validation |
:invalid | Input failing constraint validation |
:in-range | Input value within min/max |
:out-of-range | Input value outside min/max |
:placeholder-shown | Input showing its placeholder |
:read-only | Non-editable element (readonly attr or non-input) |
:read-write | Editable element |
:autofill | Autofilled by browser (also :-webkit-autofill) |
:blank | Empty user-value input (draft — limited support) |
:user-valid | Valid after user interaction (CSS Selectors 4) |
:user-invalid | Invalid 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-class | Matches |
|---|---|
:root | The root element (usually <html>) |
:empty | Element with no children (incl. text nodes) |
:first-child | First child of its parent |
:last-child | Last child of its parent |
:only-child | Only child of its parent |
:nth-child(n) | nth child |
:nth-last-child(n) | nth child from end |
:first-of-type | First of its element type within parent |
:last-of-type | Last of its element type |
:only-of-type | Only 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 |
:scope | Scoping 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
| Expression | Selects |
|---|---|
odd / 2n+1 | 1, 3, 5… |
even / 2n | 2, 4, 6… |
3 | Exactly the 3rd |
3n | Every 3rd (3, 6, 9…) |
3n+2 | 2, 5, 8, 11… |
-n+3 | First 3 (counting back from 3) |
n+4 | 4th and beyond |
/* CSS Selectors 4: nth-child with selector list */ :nth-child(even of .item) { background: #f0f0f0; }
Logical / Relational
| Pseudo-class | Matches |
|---|---|
: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-class | Matches |
|---|---|
:first | First printed page (in @page) |
:left | Left-side printed pages |
:right | Right-side printed pages |
:blank | Blank 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; }
::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
| Selector | Specificity |
|---|---|
::before, ::after, ::first-line | 0-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 |