DEV Community

Weather Clock Dash
Weather Clock Dash

Posted on

Modern CSS in 2024: Nesting, :has(), Container Queries, color-mix(), and More

CSS has evolved dramatically. Features that required JavaScript hacks or were impossible a few years ago are now native CSS. Here's a rundown of modern CSS features that are production-ready in Firefox and all modern browsers as of 2024.

CSS Nesting

No more BEM or repeated selectors — nest rules directly:

/* Old way */
.card { background: white; }
.card:hover { box-shadow: 0 4px 20px rgba(0,0,0,0.1); }
.card .title { font-size: 1.25rem; }
.card .title:hover { color: blue; }

/* Modern CSS nesting */
.card {
  background: white;

  &:hover {
    box-shadow: 0 4px 20px rgba(0,0,0,0.1);
  }

  .title {
    font-size: 1.25rem;

    &:hover {
      color: blue;
    }
  }

  @media (max-width: 768px) {
    padding: 12px; /* Media queries nested inside too */
  }
}
Enter fullscreen mode Exit fullscreen mode

Firefox 117+. No preprocessor needed.

:has() Relational Pseudo-Class

Style parents based on their children — the "parent selector" CSS has lacked for decades:

/* Card with an image → show image at full width */
.card:has(img) {
  padding: 0;
}

/* Form field with an error → turn label red */
.field:has(.error-message) label {
  color: red;
}

/* Navigation with a dropdown open → prevent scroll */
body:has(.dropdown:open) {
  overflow: hidden;
}

/* Table row on hover → highlight entire row */
tr:has(td:hover) {
  background: rgba(0,0,0,0.05);
}
Enter fullscreen mode Exit fullscreen mode

Firefox 121+. Also available as :not(:has(X)) — elements without X.

CSS Grid subgrid

Children of a grid item can participate in the grandparent's grid:

.parent {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto auto;
  gap: 16px;
}

.card {
  display: grid;
  grid-row: span 2;
  grid-template-rows: subgrid; /* Use parent's row tracks */
}
Enter fullscreen mode Exit fullscreen mode

Without subgrid, all cards have independently-sized header/body. With subgrid, they align across the row.

Firefox 71+ (first browser to support it!).

color-mix()

Mix two colors in CSS without JavaScript or preprocessors:

:root {
  --color-primary: oklch(60% 0.2 230);
}

.button-light {
  background: color-mix(in oklch, var(--color-primary), white 30%);
}

.button-dark {
  background: color-mix(in oklch, var(--color-primary), black 20%);
}

/* Mix in different color spaces */
.cool { background: color-mix(in hsl, blue, green 50%); }
.warm { background: color-mix(in srgb, red, yellow 40%); }
Enter fullscreen mode Exit fullscreen mode

Firefox 113+.

@layer Cascade Layers

Explicit priority for CSS blocks:

@layer reset, base, components, utilities;

@layer reset { * { box-sizing: border-box; } }
@layer base { a { color: blue; } }
@layer components { .btn { /* ... */ } }
@layer utilities { .hidden { display: none !important; } }
Enter fullscreen mode Exit fullscreen mode

Later layers override earlier layers regardless of specificity. Firefox 97+.

Container Queries

Style elements based on their container's size, not the viewport:

.card-container { container-type: inline-size; }

@container (min-width: 480px) {
  .card { flex-direction: row; }
}
Enter fullscreen mode Exit fullscreen mode

Firefox 110+.

@property Typed Custom Properties

Register custom properties with a type, enabling animation:

@property --progress {
  syntax: '<number>';
  inherits: false;
  initial-value: 0;
}

.bar { transition: --progress 0.5s ease; }
.bar.loaded { --progress: 75; }
Enter fullscreen mode Exit fullscreen mode

Firefox 128+.

CSS Logical Properties

Write direction-agnostic CSS that works for both LTR and RTL layouts:

/* Old */
margin-left: 16px;
padding-right: 8px;
border-top: 1px solid;

/* Logical */
margin-inline-start: 16px;  /* left in LTR, right in RTL */
padding-inline-end: 8px;    /* right in LTR, left in RTL */
border-block-start: 1px solid; /* top in horizontal, left in vertical */

/* Even more concise */
margin-inline: 16px;    /* left + right margin */
padding-block: 8px;     /* top + bottom padding */
inset-inline: 0;        /* left + right position */
Enter fullscreen mode Exit fullscreen mode

Firefox 91+. Essential for internationalized sites.

oklch() Color Space

Perceptually uniform colors — consistent lightness across hues:

/* oklch(lightness chroma hue) */
:root {
  /* Same lightness, different hues — looks equally bright */
  --red: oklch(60% 0.25 30);
  --blue: oklch(60% 0.25 250);
  --green: oklch(60% 0.25 140);
}

/* HSL 50% lightness of green looks much brighter than 50% lightness of purple */
/* oklch 60% lightness is visually consistent */
Enter fullscreen mode Exit fullscreen mode

Firefox 113+.

Relative Color Syntax

Derive colors from other colors:

:root { --color: oklch(60% 0.2 230); }

.lighter { background: oklch(from var(--color) calc(l + 20%) c h); }
.darker  { background: oklch(from var(--color) calc(l - 20%) c h); }
.muted   { background: oklch(from var(--color) l calc(c * 0.5) h); }
Enter fullscreen mode Exit fullscreen mode

Firefox 128+. Replaces Sass color functions entirely.

text-wrap: balance and text-wrap: pretty

Prevent typographic widows and orphans:

h1, h2, h3 {
  text-wrap: balance; /* Equal line lengths (max 4 lines) */
}

p {
  text-wrap: pretty; /* No orphan words on last line */
}
Enter fullscreen mode Exit fullscreen mode

Firefox 128+.

Summary: What's Production-Ready in 2024

Feature Firefox Chrome Safari
CSS Nesting 117+ 112+ 16.5+
:has() 121+ 105+ 15.4+
Container queries 110+ 105+ 16+
subgrid 71+ 117+ 16+
@layer 97+ 99+ 15.4+
color-mix() 113+ 111+ 16.2+
@property 128+ 85+ 16.4+
oklch 113+ 111+ 15.4+

All of these are safe to use in production today without any build tools.

Top comments (0)