# Modern CSS Features (2023–2025) — Deep Dive
> Powerful, under-the-radar CSS features that many developers haven't adopted yet.
---
## 1. CSS Nesting (Native, 2024+)
Built-in nesting — no preprocessor needed.
```css
.card {
padding: 1rem;
border-radius: 8px;
&__title {
font-size: 1.5rem;
&:hover {
text-decoration: underline;
}
}
&__body {
color: #555;
}
/* Nested media queries */
@media (min-width: 768px) {
padding: 2rem;
font-size: 1.25rem;
}
}
```
> **Support:** Chrome 120+, Safari 16.6+, Firefox 128+
---
## 2. `:has()` — The "Parent Selector"
Match elements based on their descendants.
```css
/* Style a card containing an image */
article:has(> img) { border: 2px solid #0af; }
/* Style fieldset when input is focused */
fieldset:has(input:focus) {
border-color: #0066ff;
box-shadow: 0 0 0 3px rgba(0, 102, 255, 0.15);
}
/* Form validation — disable submit if invalid */
form:has(input:invalid) .submit-btn {
opacity: 0.5;
pointer-events: none;
}
/* No-children pattern */
.section:not(:has(*)) { display: none; }
```
> **Support:** Chrome 105+, Safari 15.4+, Firefox 121+
---
## 3. CSS Custom Properties Deep Dive
### Inheritance
```css
:root {
--brand-hue: 210;
--brand-saturation: 80%;
--brand-lightness: 55%;
}
.card {
--brand-lightness: 70%; /* Override for subtree */
}
.card__header {
background: hsl(var(--brand-hue) var(--brand-saturation) var(--brand-lightness));
}
```
### `@property` — Typed Custom Properties (No Safari)
```css
@property --progress {
syntax: "<percentage>";
inherits: false;
initial-value: 0%;
}
@property --hue {
syntax: "<number>";
inherits: true;
initial-value: 0;
}
/* Now animatable! */
.progress-bar { animation: load 2s linear forwards; }
@keyframes load { to { --progress: 100%; } }
@keyframes hue-cycle { to { --hue: 360; } }
.rainbow {
background: hsl(var(--hue), 70%, 60%);
animation: hue-cycle 5s linear infinite;
}
```
### Fallback Chain
```css
.color {
color: var(--primary, var(--secondary, blue));
}
```
---
## 4. CSS Color Functions
### `color-mix()` — Mix Two Colors
```css
.button {
background: color-mix(in srgb, red 80%, blue);
background: color-mix(in hsl, #3498db, #e74c3c 30%);
background: color-mix(in srgb, #2196f3, transparent 50%);
}
```
### `oklch()` — Perceptually Uniform Color Space
```css
:root {
--brand: oklch(70% 0.15 220); /* Lightness, Chroma, Hue */
--text: oklch(20% 0.01 220);
}
/* Seamless lightness-only gradient */
.palette {
background: linear-gradient(
to right,
oklch(95% 0.1 200),
oklch(85% 0.1 200),
oklch(75% 0.1 200),
oklch(65% 0.1 200),
oklch(55% 0.1 200),
oklch(45% 0.1 200)
);
}
```
### Relative Notation — `rgb(from ...)`
```css
:root { --original: rgb(100 150 200); }
.element {
color: rgb(from var(--original) r + 20 g b);
background: rgb(from var(--original) calc(255 - r) g b);
}
/* Works with oklch too */
.element {
color: oklch(from var(--original) calc(L + 0.1) C calc(H + 10));
}
```
### `color-contrast()` — Auto Accessibility
```css
.dynamic-card {
--bg: oklch(80% 0.2 180);
color: color-contrast(var(--bg) vs white, black, #333);
}
```
> **Support (color-mix, oklch, relative notation):** Chrome 119+, Safari 17+, Firefox 128+
---
## 5. CSS Animations
### Scroll-Driven Animations
```css
/* Hero fades as you scroll */
.hero {
animation: fade-out linear;
animation-timeline: scroll();
}
@keyframes fade-out {
to { opacity: 0; transform: scale(0.8); }
}
/* Progress bar fills as you scroll */
.scroll-progress {
position: fixed;
top: 0; left: 0;
height: 4px;
background: #3498db;
animation: progress linear;
animation-timeline: scroll(root);
}
@keyframes progress { to { width: 100%; } }
/* Animate when element enters viewport */
.card {
animation: slide-up linear both;
animation-timeline: view();
animation-range: entry 0% entry 40%;
}
@keyframes slide-up {
from { opacity: 0; transform: translateY(100px); }
to { opacity: 1; transform: translateY(0); }
}
```
### View Transitions
```css
.photo-card { view-transition-name: photo-card; }
::view-transition-old(root) { animation: fade-out 0.3s ease-in; }
::view-transition-new(root) { animation: fade-in 0.3s ease-out; }
```
---
## 6. CSS Layers (`@layer`)
Control cascade priority without `!important`.
```css
/* First declared = lowest priority */
@layer reset, base, components, utilities;
@layer reset {
* { margin: 0; padding: 0; box-sizing: border-box; }
}
@layer base {
body { font-family: system-ui, sans-serif; }
}
@layer components {
.card { padding: 1.5rem; border-radius: 8px; }
}
@layer utilities {
.mt-2 { margin-top: 0.5rem; }
}
/* Import framework at lowest priority */
@layer framework { @import "tailwind.css"; }
```
---
## 7. Advanced Selectors
### `:is()` — Forgiving Selector List
```css
:is(h1, h2, h3) { font-weight: 700; }
:is(article, section) :is(h1, h2) { color: var(--heading-color); }
```
### `:where()` — Zero Specificity
```css
:where(h1, h2, h3, h4, h5, h6) { margin: 0; }
:where(button, input, textarea, select) { font-family: inherit; }
```
### `:not()` — Multiple Selectors
```css
li:not(:first-child, :last-child) { border-top: 1px solid #eee; }
.card:not(:has(.featured-badge)) { opacity: 0.7; }
```
### Advanced `:nth-child()`
```css
li:nth-child(3n + 2) { color: red; } /* Every 3rd starting from 2nd */
li:nth-last-child(3) { background: yellow; }
```
---
## 8. CSS Logical Properties
Map physical properties to logical directions — automatic RTL/writing-mode support.
```css
.card {
margin-block: 1rem; /* replaces margin-top/bottom */
margin-inline: 2rem; /* replaces margin-left/right */
padding-block-start: 0.5rem;
padding-inline: 1.5rem;
border-start-start-radius: 8px; /* border-top-left */
border-end-end-radius: 8px; /* border-bottom-right */
inset-block-start: 0; /* replaces top */
inset-inline-start: 1rem; /* replaces left */
block-size: 200px; /* replaces height */
inline-size: 300px; /* replaces width */
}
/* Writing mode */
.vertical-text {
writing-mode: vertical-rl;
margin-block: 2rem;
padding-inline: 1rem;
}
```
---
## 9. CSS Scroll Snap
Native carousels without JavaScript.
```css
.carousel {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
}
.carousel__slide {
flex: 0 0 100%;
scroll-snap-align: start;
}
/* Center snap */
.gallery {
scroll-snap-type: x mandatory;
padding-inline: 10%;
}
.gallery__item {
scroll-snap-align: center;
scroll-snap-stop: always; /* Never skip items */
}
```
---
## 10. CSS `@scope` (2024+)
Scoped styles without Shadow DOM.
```css
@scope (.sidebar) to (.sidebar__content) {
h2 { color: blue; font-size: 1.2rem; } /* Only inside .sidebar */
a { color: purple; }
p { font-size: 0.9rem; }
}
h2 { color: black; font-size: 2rem; } /* Global, not affected */
/* Component isolation */
@scope (.modal) {
button {
background: #0066ff;
color: white;
border: none;
}
}
```
> **Support:** Chrome 125+, Safari 18+
---
## 11. Text Features
```css
/* Balance heading lines */
h1, h2, h3 { text-wrap: balance; }
/* Prevent widows (single word on last line) */
p { text-wrap: pretty; }
/* Prevent iOS font scaling */
html { text-size-adjust: none; }
/* Break long words */
.code { overflow-wrap: break-word; word-break: break-all; }
/* Automatic hyphenation */
article { hyphens: auto; }
```
---
## 12. `@starting-style` — Entry Animations
```css
.modal {
opacity: 0;
transition: opacity 0.3s ease;
}
.modal.is-open { opacity: 1; }
@starting-style {
.modal.is-open { opacity: 0; } /* Starting state for first render */
}
/* Slide-in notification */
.toast {
transform: translateX(100%);
transition: transform 0.3s ease-out;
}
.toast.visible { transform: translateX(0); }
@starting-style {
.toast.visible { transform: translateX(100%); }
}
```
> **Support:** Chrome 118+, Edge 118+
---
## 13. `accent-color` — Restyle Form Controls
```css
:root { accent-color: #6366f1; }
input[type="checkbox"] { accent-color: #10b981; }
input[type="radio"] { accent-color: #f43f5e; }
input[type="range"] { accent-color: #8b5cf6; }
progress { accent-color: #06b6d4; }
```
---
## 14. `color-scheme` — Automatic Dark Mode
```css
:root { color-scheme: light dark; }
/* Browser auto-styles form controls, scrollbars, cursor */
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a2e;
--text: #e0e0e0;
}
}
::selection { background: #0066ff; color: white; }
@media (prefers-color-scheme: dark) {
::selection { background: #6366f1; color: white; }
}
```
---
## Browser Support Matrix (2025)
| Feature | Chrome | Firefox | Safari |
|---------|--------|---------|--------|
| CSS Nesting | ✅ 120+ | ✅ 128+ | ✅ 16.6+ |
| `:has()` | ✅ 105+ | ✅ 121+ | ✅ 15.4+ |
| `@property` | ✅ 85+ | ✅ 128+ | ❌ |
| `color-mix()` | ✅ 119+ | ✅ 128+ | ✅ 17+ |
| `oklch()` | ✅ 119+ | ✅ 128+ | ✅ 17+ |
| Scroll-driven anims | ✅ 115+ | ✅ 128+ | ❌ |
| View transitions | ✅ 111+ | ✅ 128+ | ❌ |
| `@layer` | ✅ 99+ | ✅ 97+ | ✅ 16+ |
| `@scope` | ✅ 125+ | ❌ | ✅ 18+ |
| `text-wrap: balance` | ✅ 117+ | ✅ 128+ | ✅ 17.2+ |
| `@starting-style` | ✅ 118+ | ❌ | ❌ |
| `accent-color` | ✅ 93+ | ✅ 127+ | ✅ 16.4+ |
| Logical properties | ✅ 87+ | ✅ 114+ | ✅ 15.4+ |
| Scroll snap | ✅ 69+ | ✅ 68+ | ✅ 15+ |