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 */ } } 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); } 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 */ } 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%); } 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; } } 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; } } 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; } 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 */ 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 */ 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); } 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 */ } 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.
