JUMP TO:
1. Container Queries
2. New color spaces & functions
3. :has() pseudo selector
4. New viewport units
5. accent-color
1. Container Queries
Container queries let a component adapt its styles based on the size of its container, not the viewport.
They solve the problem media queries never could.
Why they exist
Media queries answer:
“How big is the screen?”
Container queries answer:
“How much space does this component have?”
This is essential for:
- reusable components
- cards in grids
- sidebars vs main content
- CMS layouts (very relevant to WordPress)
Minimal example
.card {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: flex;
gap: 1rem;
}
}
If .card is wider than 400px, it changes layout — regardless of screen size.
Two steps you must remember
1️⃣ Declare a container
container-type: inline-size;
This opts the element into being a queryable container.
2️⃣ Query the container
@container (min-width: 400px) { ... }
Not @media.
Container types (quick)
inline-size→ respond to width (most common)size→ respond to both width and height
Naming containers (optional but useful)
.card {
container-type: inline-size;
container-name: card;
}
@container card (min-width: 400px) {
...
}
Prevents accidental matches.
What container queries replace
Before:
- viewport-based hacks
- duplicated components
- JS resize observers
Now:
- components are truly portable
- CSS stays declarative
2. Color Spaces and Functions
Why new CSS color spaces were added
Traditional CSS colors (rgb(), hex, hsl()) are based on sRGB, which:
- was designed for old monitors
- can’t represent many modern display colors
- interpolates colors poorly (muddy gradients)
Modern CSS color features solve this by:
- supporting wider gamuts
- using perceptually uniform color spaces
- giving better control and math
The big new color spaces
1️⃣ oklch() (most important)
color: oklch(60% 0.15 240);
What it is
- A perceptually uniform color space
- Based on how humans actually see color
Components
L→ lightness (0–100%)C→ chroma (color intensity)H→ hue (angle)
Why it matters
- Changing lightness doesn’t shift hue
- Gradients look natural
- Ideal for design systems
👉 This is the future default choice
2️⃣ oklab()
color: oklab(0.6 -0.1 -0.05);
- Same family as
oklch - Cartesian version (less intuitive)
- Mostly used internally or for math
Most people prefer oklch().
3️⃣ lab() / lch()
color: lch(65% 40 130);
- Older perceptual color spaces
- Still better than
hsl() - Slightly less accurate than OKLCH
Think of these as stepping stones.
4️⃣ Display color spaces (color())
color: color(display-p3 1 0 0);
Supported spaces:
display-p3rec2020a98-rgbprophoto-rgb
These unlock more vivid colors on modern screens (Apple devices especially).
New & updated color functions
1️⃣ Modern rgb() and hsl() syntax
color: rgb(255 0 0 / 50%);
color: hsl(0 100% 50% / 0.5);
- Spaces instead of commas
- Built-in alpha channel
- Matches other color functions
2️⃣ color-mix() (very useful)
background: color-mix(in oklch, red 70%, white);
Mixes colors correctly, in a chosen color space.
Better than manual rgba tricks.
3️⃣ Relative colors (powerful)
--brand: oklch(60% 0.2 250);
color: oklch(from var(--brand) calc(l + 10%) c h);
This means:
“Use the same color, but lighter”
Perfect for:
- hover states
- borders
- themes
4️⃣ color-contrast() (experimental)
color: color-contrast(white vs black, navy);
Chooses the best contrast color automatically.
Accessibility-focused, but still evolving.
Gamut awareness (important concept)
color: oklch(70% 0.3 30);
If the color:
- exists on the display → shown
- doesn’t exist → browser clips safely
This avoids broken colors.
When you should care
Use new color features if you:
- build design systems
- care about accessibility
- want consistent hover / active states
- design on modern displays
- want better gradients
You don’t need them for:
- quick one-off sites
- legacy browser support
Simple mental model
| Old world | New world |
|---|---|
hex | oklch() |
rgba() | color-mix() |
hsl() | perceptual lightness |
| guesswork | math-friendly colors |
Example: modern button (clean & future-proof)
:root {
--brand: oklch(60% 0.18 250);
}
button {
background: var(--brand);
}
button:hover {
background: color-mix(in oklch, var(--brand) 85%, black);
}
Predictable. Accessible. Maintainable.
3. :has() pseudo selector
:has()lets you style an element based on what it contains or what comes after it — effectively a “parent selector” in CSS.
Example:
.card:has(img) {
border: 2px solid green;
}
Means:
“Style
.cardif it contains an<img>.”
Common, practical uses
Style a parent when a child exists
form:has(input:invalid) {
border: 2px solid red;
}
Style based on sibling state
label:has(+ input:checked) {
font-weight: bold;
}
Layout adjustments
.article:has(.sidebar) {
grid-template-columns: 3fr 1fr;
}
Why it’s a big deal
Before :has():
- required JavaScript
- messy extra classes
- duplicated markup
Now:
- pure CSS
- declarative
- readable
Important rules
:has()is relational (looks inside or forward)- Cannot look up beyond the selected element
- Can be performance-heavy if overused
4. New viewport units
The new viewport units (svh, lvh, dvh) fix mobile vh bugs by defining viewport sizes that account for dynamic browser UI.
The problem with old viewport units
Traditional units:
vw→ 1% of viewport widthvh→ 1% of viewport height
On mobile, vh was unreliable because:
- browser address bars appear/disappear
- the “viewport” height changes while scrolling
100vhcould be taller than the visible screen
Result:
- content cut off
- unwanted scrolling
- broken full-height layouts
The new viewport units
CSS now defines three viewport concepts:
| Unit type | What it represents |
|---|---|
Large (lvh, lvw) | Maximum possible viewport size |
Small (svh, svw) | Minimum possible viewport size |
Dynamic (dvh, dvw) | Current visible viewport size |
1️⃣ svh — small viewport height
height: 100svh;
- Uses the smallest viewport
- Safe from content being hidden
- Best for layouts that must always fit
✅ Good for:
- full-screen forms
- login pages
- modals
2️⃣ lvh — large viewport height
height: 100lvh;
- Uses the largest possible viewport
- Can extend behind browser UI
- Matches old
100vhbehavior
⚠️ Rarely what you want now
3️⃣ dvh — dynamic viewport height (most useful)
min-height: 100dvh;
- Updates as the UI changes
- Tracks visible screen size
- Smoothly adapts on scroll
✅ Best for:
- hero sections
- full-height layouts
- modern responsive design
Safe modern pattern
.hero {
min-height: 100svh;
min-height: 100dvh;
}
Browsers that support dvh use it.
Others fall back to svh.
Width units too
Same idea applies to width:
svwlvwdvw
Less commonly needed, but useful for:
- side panels
- off-canvas menus
When you should switch
Replace this:
height: 100vh;
With one of:
100dvh→ flexible layouts100svh→ strict fit layouts
5. accent-color

accent-colorlets you set the color of built-in form controls (checkboxes, radio buttons, range sliders, progress bars) without fully restyling them.
What it affects
accent-color applies to native UI parts such as:
- checkboxes
- radio buttons
<input type="range"><progress>
It does not affect:
- text inputs
- buttons
- selects (beyond limited UA styling)
Minimal example
:root {
accent-color: #0066cc;
}
All supported form controls now use that color.
Per-element control
input[type="checkbox"] {
accent-color: green;
}
Why it’s useful
Before accent-color:
- full custom controls required
- lots of CSS
- accessibility pitfalls
With accent-color:
- native behavior preserved
- keyboard & screen-reader support stays intact
- theming is trivial
Works well with modern color features
:root {
accent-color: oklch(60% 0.18 250);
}
Matches your design system colors cleanly.
Best practices
- Prefer subtle, accessible colors
- Ensure sufficient contrast
- Use it as a theme hint, not full customization

Leave a Reply