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.
Top comments (0)