Emergency server help: get in touch

CSS Cheat Sheet: Selectors, Flexbox, Grid and Modern CSS

Current CSS in one page: selectors, :has(), flexbox, grid, custom properties, container queries and native nesting, with copy-ready examples.

Published Updated 5 min read

Short answer: Modern CSS covers most layout and theming without a preprocessor. Use flexbox for one-dimensional rows or columns and grid for two-dimensional layouts. Custom properties (--brand) handle theming, and container queries (@container) let components respond to their own width. :has() selects a parent by its contents, and native nesting (&:hover) works in all major browsers. The tables below give the syntax for each, with the specificity rules you need to debug styles.

The examples in this CSS cheat sheet were run in headless Chromium 141 on 9 October 2026, checking the computed styles for each selector, layout, custom property, container query and nesting rule. Support notes for other browsers come from MDN.

Selectors and specificity

SelectorMatches
p, .card, #mainType, class, ID
[href^="https"], [href$=".pdf"], [data-state="open"]Attribute starts with, ends with, equals
nav a, ul > li, h2 + p, h2 ~ pDescendant, direct child, next sibling, any later sibling
a:hover, button:focus-visible, input:invalidState pseudo-classes. :focus-visible shows focus rings for keyboard users only
li:nth-child(2n+1), li:first-child, li:last-childPosition
:not(.active), :is(h1, h2, h3)Negation and grouping; specificity of the most specific argument
:where(ul, ol) liLike :is() but with zero specificity, so it is easy to override
p::first-line, .req::after { content: "*"; }Pseudo-elements

Specificity is counted as (IDs, classes/attributes/pseudo-classes, types). #nav a (1,0,1) beats .menu a.link (0,2,1). When specificity ties, the rule that comes later wins. Avoid !important except for utilities.

The :has() selector

:has() selects an element based on what it contains or what follows it, which CSS could not do before. It has been in all major browsers since December 2023.

SelectorMatches
.card:has(img)Cards that contain an image
form:has(input:invalid) button[type="submit"]The submit button of a form with an invalid field
h2:has(+ p)An h2 immediately followed by a paragraph
label:has(input:checked)A label whose checkbox is ticked
body:has(dialog[open])The page while a dialog is open, for example to stop scrolling
.grid:not(:has(*))An empty grid

Box model, units and sizing

*, *::before, *::after { box-sizing: border-box; }

.wrapper {
  max-width: 70rem;
  margin-inline: auto;            /* centre horizontally */
  padding: 1rem clamp(1rem, 4vw, 3rem);
}
.hero { min-height: 100dvh; }
ValueMeaning
box-sizing: border-boxWidth includes padding and border
margin: 1rem 2remShorthand: top/bottom, then left/right. Four values go clockwise from the top
margin-inline, padding-block, inset: 0Logical properties; follow the writing direction
rem, em, chRoot font size, current font size, width of the 0 character
vw, vh, dvh, svhViewport units. dvh follows mobile browser bars as they show and hide
clamp(1rem, 2.5vw, 2rem)Fluid value with a minimum and a maximum
min(100%, 40rem), max(), calc(100% - 2rem)Maths functions
aspect-ratio: 16 / 9Keep proportions without padding hacks

Flexbox

PropertyWhat it does
display: flexOne-dimensional layout of the children (a row by default)
flex-direction: columnStack vertically
justify-content: space-betweenSpread items along the main axis (center, flex-start, space-around also work)
align-items: centerAlign on the cross axis; vertical centring in a row
flex-wrap: wrapLet items move to a new line
gap: 1remSpace between items, not around the edges
flex: 1Grow to share free space equally
flex: 0 0 15remFixed 15rem item that does not grow or shrink
margin-left: autoPush an item, and everything after it, to the far end
align-self, orderOverride alignment or visual order for one item

Grid

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.5rem;
}

.layout {
  display: grid;
  grid-template-columns: 14rem 1fr;
  grid-template-areas:
    "side header"
    "side main";
}
.layout > header { grid-area: header; }
PropertyWhat it does
grid-template-columns: 1fr 2frTwo columns sharing space 1 : 2
repeat(auto-fit, minmax(15rem, 1fr))As many columns of at least 15rem as fit, with no media queries
grid-column: 1 / -1Span from the first to the last line
grid-column: span 2Span two columns
grid-template-areas and grid-areaName regions and place children by name
place-items: centerCentre content in both directions
grid-template-rows: subgridChild grid uses the parent’s tracks, so card rows line up

Custom properties

:root {
  --brand: #0b6bcb;
  --radius: 0.5rem;
}
.button {
  background: var(--brand);
  border-radius: var(--radius, 4px);   /* fallback if unset */
}
.dark .button { --brand: #5aa9ff; }  /* override in a scope */
FeatureWhat it does
--name: valueDeclare; inherited by descendants
var(--name, fallback)Use, with an optional fallback
@property --angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }Typed property that can be animated. Baseline since 2024
color-mix(in srgb, var(--brand) 80%, white)Tint or shade a variable
color-scheme: light dark with light-dark(#111, #eee)Pick a value for the light or dark theme

Custom properties are case-sensitive and resolved when used, not when declared. They work in JavaScript too: el.style.setProperty('--brand', 'red').

Media and container queries

SyntaxWhat it does
@media (width >= 48rem) { ... }Range syntax; same as (min-width: 48rem)
@media (prefers-color-scheme: dark)Dark mode set in the operating system
@media (prefers-reduced-motion: reduce)Turn off animations for people who ask for it
@media (hover: hover) and (pointer: fine)Mouse or trackpad, not touch
container-type: inline-sizeMake an element a size container for its children
container: card / inline-sizeShorthand: name and type
@container card (width >= 30rem) { ... }Style children by the container’s width, not the viewport
cqi, cqwUnits relative to the container’s size
.card-wrap { container: card / inline-size; }

@container card (width >= 30rem) {
  .card { display: grid; grid-template-columns: 10rem 1fr; }
}

Container size queries are supported in all major browsers. Style queries on custom properties (@container style(--theme: dark)) are much newer: Firefox added them in version 151 in May 2026, so plan a fallback for older browsers.

Native CSS nesting

.card {
  padding: 1rem;

  & h2 { margin-top: 0; }    /* .card h2 */
  &:hover { outline: 2px solid var(--brand); }  /* .card:hover */
  .dark & { background: #222; }  /* .dark .card */

  @media (width >= 48rem) {
    padding: 2rem;
  }
}
RuleDetail
& is optional before a descendanth2 { } inside .card also means .card h2
& is required for compound selectors&:hover and &.active; without &, a space is implied
No string concatenationSass-style &__title does not work; write .card__title in full
Specificity& behaves like :is() with the parent selector list
SupportAll major browsers since December 2023; older browsers ignore nested rules

Official documentation (checked 9 October 2026): MDN: CSS · W3C: CSS current work · MDN: CSS flexible box layout · MDN: CSS grid layout · MDN: Container size and style queries · MDN: :has() · MDN: Using CSS nesting

CSS Cheat Sheet at a glance

CSS Cheat Sheet – short answer
In short: Current CSS in one page: selectors, :has(), flexbox, grid, custom properties, container queries and native nesting, with copy-ready examples.
CSS Cheat Sheet – what this guide covers
CSS Cheat Sheet: what this guide covers.

Related: HTML Cheat Sheet: Elements, Attributes and Forms · .

Reading a lot of our guides? Go ad-free with srvScripts Pro for $6 a month. It also pays for new guides. Cancel any time.

Share this guide

Free website test

Is your website set up right?

Check SSL, security headers, redirects, robots.txt, sitemap, llms.txt and security.txt in one test. It takes about 30 seconds.