Modern CSS

Modern CSS rules for creating robust, responsive and accessible UIs.

The rules work best when you apply a progressive enhancement approach. The CSS features are within Baseline Newly Available. Thanks to Interop, most are within Widely Available.

The rules, constraints, and examples are not intended to be prescriptive. Use your best judgment and consider the specific needs of the project when applying them. However, if you use a rule, apply it consistently.

Rules

Architecture

Organizing styles (@layer)

@layer elements, components;

@layer elements {
  a {
    text-decoration-skip-ink: auto;
  }
}

Encapsulating styles (@scope)

@scope (.card) {
  h2 {
    font-size: var(--large);
  }
}

Nesting rules and at-rules (&)

a {
  color: var(--blue);

  &:hover {
    text-decoration: underline;
  }

  @container (width > 20em ) {
    place-self: center;
  }
}

Relational styles (:has())

.card {
  &:has(img) {
    grid-template-rows: auto 1fr;
  }
}

Additive properties (:not() and 20em < width <= 40em ))

.card {
  /* Apply to all conditions */
  color: red;

  /* Apply based on the selector */
  &:not(:first-child) {
    margin-block-start: var(--medium);
  }

  /* Apply based on non-overlapping container conditions */
  @container example (width <= 20em) {
    background-color: var(--primary);
  }

  @container example (20em < width <= 40em ) {
    background-color: var(--secondary);
  }

  @container example (width > 40em ) {
    background-color: var(--tertiary);
  }
}

Typography

Fluid type sizes (clamp())

:root {
  --medium: clamp(1.3125rem, 1.1821rem + 0.6522cqi, 1.6875rem);
  --large: clamp(1.75rem, 1.5761rem + 0.8696cqi, 2.25rem);
}

Widow and orphan words (text-wrap)

h1,
h2,
h3 {
  text-wrap: balance;
}

p {
  text-wrap: pretty;
}

Colors

Perceptual uniform lightness (oklch())

:root {
  --success: oklch(40% 0.15 150deg);
  --danger: oklch(40% 0.2 25deg);
}

Respecting color preferences (color-scheme)

body {
  color-scheme: light dark;
  background-color: light-dark(oklch(98% 0.03 250deg), oklch(14% 0 0deg));
}

Relative color functions (oklch(from /* .. */) & color-mix() )

button {
  background-color: var(--primary);

  &:hover {
    background-color: oklch(from var(--primary) l c calc(h - 10deg));
  }
}

Layout

Container queries and units (@container, cqi etc.)

.card {
  container: card / inline-size;
  padding: 2cqi;

  p {
    @container card (width > 30cqi) {
      place-self: center;
    }
  }
}

Intrinsic sizing (*-content)

nav {
  max-inline-size: fit-content;
}

Motion

Respecting motion preferences (prefers-reduced-motion)

@media (prefers-reduced-motion: no-preference) {
  .hero {
    animation: bounce-in 0.5s ease;
  }
}

Example in practice

This site follows the rules. Study the implementation on GitHub for concrete examples of each: