Cheat Sheet Library

CSS Cheat Sheet

The language that styles web pages: selectors, the cascade, box model, flexbox, grid, responsive design and modern features. Browser support notes use web.dev Baseline status as of October 2026.

  • 141 entries
  • 14 sections
  • Updated

141 entries

On this page

Selectors #

SelectorMatches
pEvery <p> element (type selector)
.cardElements with class="card"
#mainThe element with id="main" (high specificity, prefer classes)
[href] / [type="email"]Has the attribute / has that exact value
[href^="https"] / [href$=".pdf"] / [class*="btn"]Value starts with / ends with / contains
h1, h2Both h1 and h2 (selector list)
.nav aAny a inside .nav (descendant)
.nav > aOnly direct children
h2 + pThe p right after an h2 (next sibling)
h2 ~ pEvery p sibling after an h2
a:hover / a:activeMouse is over it / being clicked
:focus-visibleFocused and the browser shows a focus ring (keyboard); use instead of :focus for outlines
:focus-withinThe element or something inside it has focus
li:first-child / li:last-childFirst / last child of its parent
li:nth-child(odd) / li:nth-child(3n)Odd children / every 3rd child
:not(.active)Anything that doesn't match
:is(h1, h2, h3) aShorter selector lists; specificity of the most specific argument
:where(ul, ol)Like :is() but zero specificity: easy to override
.card:has(img)A card that contains an image: the "parent selector" (widely available since 2026)
input:checked / :disabled / :requiredForm element states
input:user-invalidInvalid only after the user has interacted (widely available)
::before / ::afterGenerated content; needs content: ""
::placeholder / ::selection / ::markerPlaceholder text / selected text / list bullet or number

Specificity & Cascade #

SyntaxMeaning
#idSpecificity (1, 0, 0)
.class / [attr] / :hover(0, 1, 0)
p / ::before(0, 0, 1)
* / :where()(0, 0, 0)
:is() / :not() / :has()Count as their most specific argument
style="..."Inline styles beat every selector
color: red !importantBeats all normal declarations; avoid outside utility classes
@layer reset, base, components;Declare layer order: later layers win
@layer base { a { color: blue; } }Put rules in a layer; unlayered styles beat layered ones
inherit / initial / unset / revertTake the parent's value / the CSS default / either / the browser default

Conflict order: !important → layer → specificity → source order (last one wins). Text properties (color, font-*) inherit, box properties (margin, border) don't.

Box Model #

CodeWhat it does
*, *::before, *::after { box-sizing: border-box; }width includes padding and border (put it in every project)
margin: 10pxAll four sides
margin: 10px 20pxTop + bottom, left + right
margin: 10px 20px 30pxTop, left + right, bottom
margin: 10px 20px 30px 40pxTop, right, bottom, left (clockwise)
margin-inline: autoCenter a block that has a width or max-width
padding: 1rem 2remInner space; same shorthand rules as margin
border: 1px solid #cccWidth, style, colour
border-radius: 8px / border-radius: 50%Rounded corners / circle (on a square)
outline: 2px solid; outline-offset: 2pxLike a border but takes no space (focus rings)
overflow: autoScrollbar only when needed (hidden clips, clip clips without scrolling)

Vertical margins between blocks collapse: only the larger one is used. This doesn't happen in flex or grid.

Units & Colors #

ValueMeaning
pxPixels (borders, shadows)
remMultiple of the root font size (16px by default); use for font sizes and spacing
emMultiple of the element's font size (in font-size itself: the parent's); padding that scales with text
%Percentage of the parent (for width: of the parent's width)
vw / vh1% of the viewport width / height
dvh / svh / lvhDynamic / small / large viewport height: fixes 100vh on mobile (widely available)
chWidth of the "0" character: max-width: 65ch gives readable lines
frA share of the free space in a grid
#0b5fff / #0b5fff80Hex colour / with alpha
rgb(11 95 255 / 50%)Modern syntax, alpha after / (old: rgba(11, 95, 255, 0.5))
hsl(220 100% 52%)Hue, saturation, lightness
oklch(60% 0.2 260)Lightness, chroma, hue: even-looking palettes, wide gamut (widely available)
currentColorThe element's current color (icons, borders)
color-mix(in oklch, var(--brand), white 20%)Mix two colours (widely available)
light-dark(#111, #eee)Light-mode value, dark-mode value; needs color-scheme: light dark (Baseline 2024, all current browsers)

Typography #

CodeWhat it does
font-family: system-ui, sans-serifFont stack: first available font wins
font-size: 1.125remText size
font-weight: 400 / font-weight: 700Normal / bold
line-height: 1.5Unitless = multiple of the font size (best choice)
text-align: centerAlso start, end, justify
text-decoration: noneRemove the underline from links
white-space: nowrapNever wrap the text
text-overflow: ellipsis"Long text…" (needs overflow: hidden and white-space: nowrap)
overflow-wrap: anywhereBreak long words or URLs instead of overflowing
text-wrap: balanceEven line lengths for headings (Baseline 2024)
text-wrap: prettyAvoid a lonely last word in paragraphs (Chromium and Safari 26+ only; safe to add)
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter.woff2") format("woff2");
  font-weight: 100 900;   /* variable font */
  font-display: swap;     /* show fallback text while loading */
}

Display & Positioning #

CodeWhat it does
display: blockFull width, starts on a new line
display: inlineFlows with text; ignores width and height
display: inline-blockFlows with text but accepts width, height and padding
display: noneRemoved from layout and from screen readers
visibility: hiddenInvisible but keeps its space
position: staticDefault; top, left and z-index don't apply
position: relativeOffset from its normal spot; anchor for absolute children
position: absoluteOut of the flow; placed against the nearest positioned ancestor
position: fixedPinned to the viewport (a transform on an ancestor breaks this)
position: sticky; top: 0Scrolls normally, then sticks at top inside its parent
inset: 0Shorthand for top, right, bottom, left
z-index: 10Stacking order for positioned, flex and grid items
isolation: isolateNew stacking context: keeps child z-index values local

Flexbox #

CodeWhat it does
display: flexContainer: lay children out in a row
flex-direction: columnContainer: stack vertically (main axis becomes vertical)
flex-wrap: wrapContainer: allow items to wrap onto more lines
justify-content: space-betweenContainer: spread along the main axis (center, flex-start, flex-end, space-evenly)
align-items: centerContainer: align on the cross axis (default stretch)
gap: 1remContainer: space between items
flex: 1Item: grow to share free space equally (short for flex: 1 1 0%; longhands flex-grow, flex-shrink, flex-basis)
flex: 0 0 200pxItem: fixed 200px, no growing or shrinking
align-self: flex-endItem: override align-items for one item
order: -1Item: move visually (tab order stays the same)
margin-left: autoItem: push it and the items after it to the end
min-width: 0Item: allow shrinking below its content (fixes overflow)

Grid #

CodeWhat it does
display: gridContainer: two-dimensional layout
grid-template-columns: 200px 1frFixed sidebar + flexible column
grid-template-columns: repeat(3, 1fr)Three equal columns
repeat(auto-fit, minmax(250px, 1fr))Responsive cards with no media query
auto-fill / auto-fitKeep empty tracks / collapse them so items stretch
grid-template-rows: auto 1fr autoHeader, content, footer
grid-auto-rows: minmax(100px, auto)Size of rows created automatically
gap: 1rem 2remRow gap, column gap
place-items: centerCenter every item in its cell
grid-column: 1 / -1Item: span from the first to the last line (full width)
grid-column: span 2Item: take two columns
grid-area: sidebarItem: put it in a named area
justify-self: end / align-self: startItem: position inside its cell
grid-template-columns: subgridItem: reuse the parent's columns (widely available since 2026)
.layout {
  display: grid;
  grid-template-columns: 220px 1fr;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
}
header { grid-area: header; }  aside  { grid-area: sidebar; }
main   { grid-area: main; }    footer { grid-area: footer; }

Responsive Design #

CodeWhat it does
@media (width >= 768px) { }Range syntax (widely available); older: (min-width: 768px)
@media (prefers-color-scheme: dark)User has dark mode on
@media (hover: hover)Device has a real hover (mouse, trackpad)
container-type: inline-sizeMake an element a container that children can query
container: card / inline-sizeSame, with a name
@container card (width > 400px) { }Style by the container's width, not the screen (widely available)
clamp(1rem, 0.8rem + 1vw, 1.5rem)Fluid value: minimum, preferred, maximum
width: min(100% - 2rem, 70rem)The smaller of the two (max() takes the larger)
img { max-width: 100%; height: auto; }Images never overflow their container

Write mobile-first: base styles for small screens, then add @media (width >= ...) for bigger ones.

Custom Properties #

CodeWhat it does
:root { --brand: #0b5fff; }Define a global variable
color: var(--brand)Use it
var(--gap, 1rem)With a fallback if it isn't set
.dark { --brand: #7aa2ff; }Override for an element and its children
padding: calc(var(--space) * 2)Do maths with variables
el.style.setProperty("--x", "10px")Set a variable from JavaScript
@property --angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }Typed variable that can be animated (Baseline 2024)

var() doesn't work inside a media query condition: @media (width >= var(--bp)) never matches.

Modern Features #

CodeWhat it does
.card { &:hover { } }Nesting with & (widely available since 2026)
.card { .title { } }Nested descendant, & optional
form:has(:user-invalid) buttonStyle based on children or later state (widely available since 2026)
aspect-ratio: 16 / 9Keep a ratio (videos, cards) (widely available)
margin-inline / padding-blockLogical properties: follow text direction (left/right, top/bottom in English)
inline-size / block-sizeLogical width / height
@scope (.card) to (.content) { img { } }Styles that only apply inside a part of the page (Baseline 2026, newly available)
field-sizing: contentInputs and textareas grow with their content (Baseline since June 2026)
color-scheme: light darkDark scrollbars and form controls in dark mode; required for light-dark()

Transitions & Animations #

CodeWhat it does
transition: opacity 200ms ease-outAnimate changes to opacity
transition: transform 0.3s, opacity 0.3sSeveral properties (avoid all)
transform: translateY(-4px) scale(1.05)Move, scale, rotate without affecting layout
translate: 0 -4px / rotate: 45deg / scale: 1.1Separate transform properties (widely available)
animation: fade-in 300ms ease-out bothName, duration, easing, fill mode (add infinite to loop)
@starting-style { }Start values for an element that just appeared (Baseline 2024)
transition-behavior: allow-discreteLet display and popovers fade out (Baseline 2024)
@keyframes fade-in {
  from { opacity: 0; translate: 0 8px; }
  to   { opacity: 1; translate: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Animate transform and opacity where possible: they're cheap. Animating width, top or margin causes layout work on every frame.

Centering Recipes #

/* Both axes: grid */
.parent { display: grid; place-items: center; }
/* Both axes: flexbox */
.parent { display: flex; justify-content: center; align-items: center; }
/* Vertically in a plain block, no flex or grid (Baseline 2024) */
.parent { align-content: center; }
/* Horizontally: a block with a max width */
.content { max-width: 60ch; margin-inline: auto; }
/* On top of a positioned parent */
.child { position: absolute; top: 50%; left: 50%; translate: -50% -50%; }

Tips #

  • z-index does nothing? The element must be positioned (or a flex/grid item), and it only competes inside its stacking context: transform, opacity below 1 and isolation create a new one.
  • 100vh is too tall on mobile because of the browser bars: use 100dvh or min-height: 100svh.
  • A flex or grid child overflows with long text: give it min-width: 0 (in grid, use minmax(0, 1fr)).
  • position: sticky not sticking: it needs top (or bottom), and an ancestor with overflow: hidden or auto becomes its scroll box.
  • Never remove focus outlines without a replacement: style :focus-visible instead of writing outline: none.
  • Specificity wars: keep selectors to one class, use :where() for defaults and @layer for order instead of piling on !important.