CSS has evolved dramatically. These modern features replace entire JavaScript libraries.
1. CSS Container Queries
Responsive components based on their parent size, not the viewport.
.card-container {
container-type: inline-size;
container-name: card;
}
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 2fr 1fr;
}
}
Finally! Components that adapt to their context, not the screen size.
2. :has() — The Parent Selector
Style a parent based on its children. This replaces tons of JavaScript.
/* Style form when it contains an invalid input */
form:has(input:invalid) {
border: 2px solid red;
}
/* Style li that contains an img */
li:has(img) {
display: grid;
grid-template-columns: auto 1fr;
}
/* Style label when its checkbox is checked */
label:has(input:checked) {
background: #e0f2fe;
font-weight: bold;
}
3. CSS Nesting (Native)
No more Sass needed for basic nesting.
.card {
background: white;
padding: 16px;
.title {
font-size: 1.5rem;
font-weight: bold;
}
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 20px rgba(0,0,0,.1);
}
@media (max-width: 768px) {
padding: 12px;
}
}
4. CSS Custom Properties (the right way)
Variables with fallbacks and scoping:
:root {
--color-primary: #6366f1;
--color-primary-hover: #4f46e5;
--spacing-base: 1rem;
--radius: 8px;
}
.dark {
--color-primary: #818cf8;
--color-primary-hover: #6366f1;
}
.button {
background: var(--color-primary, #6366f1);
padding: calc(var(--spacing-base) * 0.75) var(--spacing-base);
border-radius: var(--radius);
&:hover {
background: var(--color-primary-hover);
}
}
5. Logical Properties
Write direction-agnostic CSS (better for i18n):
/* Instead of margin-left/right/top/bottom */
.element {
margin-inline: auto; /* left + right */
margin-block: 16px; /* top + bottom */
padding-inline-start: 16px; /* left in LTR, right in RTL */
border-inline-end: 1px solid; /* right in LTR, left in RTL */
inset-block-start: 0; /* top */
}
6. Grid subgrid
Align grid items across parent/child grid boundaries:
.cards-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.card {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid; /* Inherit parent's rows */
}
/* Now all card headers, bodies, and footers align */
7. color-mix()
Mix colors natively without preprocessors:
:root {
--brand: #6366f1;
--brand-light: color-mix(in srgb, var(--brand) 30%, white);
--brand-dark: color-mix(in srgb, var(--brand) 70%, black);
--brand-transparent: color-mix(in srgb, var(--brand) 50%, transparent);
}
8. @layer — Cascade Layers
Control specificity without !important wars:
@layer reset, base, components, utilities;
@layer reset {
* { box-sizing: border-box; margin: 0; }
}
@layer base {
body { font-family: system-ui; }
}
@layer components {
.button { padding: 8px 16px; }
}
@layer utilities {
.mt-4 { margin-top: 1rem; }
}
/* Utilities always win, regardless of specificity */
9. Scroll Snap
Silky smooth scroll containers, no JavaScript:
.carousel {
display: flex;
overflow-x: scroll;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
}
.slide {
min-width: 100%;
scroll-snap-align: start;
}
10. View Transitions
Animated page transitions with one line:
/* In your CSS */
::view-transition-old(root) {
animation: fade-out 300ms ease;
}
::view-transition-new(root) {
animation: fade-in 300ms ease;
}
// In your JS
document.startViewTransition(() => {
updateDOM();
});
11. oklch() Colors
Perceptually uniform color space — lighter on dark, darker on light:
:root {
/* oklch(lightness chroma hue) */
--blue: oklch(55% 0.2 264);
--blue-lighter: oklch(75% 0.15 264);
--blue-darker: oklch(35% 0.25 264);
}
/* Equal steps in oklch look visually equal (unlike hex/hsl) */
12. CSS Animations: @keyframes with timeline
Scroll-driven animations — no JavaScript!
@keyframes fade-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal {
animation: fade-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 30%;
}
Browser Support Quick Check
| Feature | Chrome | Firefox | Safari |
|---|---|---|---|
| Container Queries | ✅ 105+ | ✅ 110+ | ✅ 16+ |
| :has() | ✅ 105+ | ✅ 121+ | ✅ 15.4+ |
| CSS Nesting | ✅ 120+ | ✅ 117+ | ✅ 17.2+ |
| @layer | ✅ 99+ | ✅ 97+ | ✅ 15.4+ |
| Scroll Snap | ✅ | ✅ | ✅ |
| oklch() | ✅ 111+ | ✅ 113+ | ✅ 15.4+ |
CSS utility: DevToolkit
Need to convert colors or format your CSS? Check out DevToolkit — free browser tools for developers:
- CSS Formatter — beautify or minify CSS
- Color Converter — HEX/RGB/HSL/oklch
- Color Picker — with WCAG contrast checker
→ https://lucasmdevdev.github.io/devtoolkit/
Which CSS feature changed how you write code? Let me know in the comments!
Top comments (0)