← All Concepts
Modern CSS

An Interactive Journey

CSS has
changed.

What required JavaScript libraries two years ago now runs natively in the browser. Hardware-accelerated. Zero bundle cost. Here is what you are missing — demonstrated live on this page.

01

oklch()

One color. Infinite palette.

02

Container Queries

Components that know their context.

03

:has()

The parent selector CSS never had.

04

Scroll-Driven

Animation without JavaScript.

05

@starting-style

Elements that arrive with grace.

06

text-wrap

Typography that cares.

Scroll to begin
01

oklch()

One color. Infinite palette.

Traditional approach: manually pick 12+ hex colors and hope they look good together. New approach: define one hue value, and derive your entire palette mathematically using oklch(). Perceptually uniform — meaning equal steps in lightness actually look equal to human eyes.

bg
surface
surfaceHover
border
muted
text
heading
primary
primaryDim
primaryBright
accent
complement
Creative Page

Portfolio

Design that breathes

Every pixel considered. Every interaction intentional.

View WorkAbout
SaaS Dashboard

Team Progress

Q2 2026
Skills completed73%
Knowledge reviewed58%
Goals on track91%

24

Active

8

Completed

3

At Risk

One hue value. 12 derived colors. Two completely different UIs. Change the slider and watch both adapt — the relationships between colors stay harmonious because oklch is perceptually uniform.
02

Container Queries

Components that know their context.

Media queries ask: how wide is the viewport? Container queries ask: how wide is my parent? Same component, different context, automatically different layout. No JavaScript. No props. Pure CSS.

Container width400px

Sarah Chen

Production Lead

Camera Skills: Intermediate

Drag the slider. Below ~350px the card stacks vertically. Above 350px it goes horizontal with a larger avatar. Above 500px, action buttons appear. One component, zero media queries, zero JavaScript — the component adapts to its container.
03

:has()

The parent selector CSS never had.

Style a parent based on the state of its children. The form border changes when the input has focus. Turns green when valid. Turns red when invalid. The label moves. The checkmark appears. All pure CSS. Zero JavaScript state management for the visual effects.

Live Demo — click the input
The CSS (no JS needed)
/* Parent reacts to child state */ .form:has(input:focus) { border-color: teal; box-shadow: 0 0 0 3px teal / 15%; } .form:has(input:valid) { border-color: green; } .form:has(input:valid) .icon { opacity: 1; }
Focus the input — the entire form card gets a teal glow. Type a valid email — it turns green and a checkmark appears. The parent styles itself based on child state. Previously this required useState, onChange, conditional classNames. Now it is three lines of CSS.
04

Scroll-Driven Animations

You are watching this right now.

This page has been demonstrating scroll-driven animations since you started scrolling. The progress bar at the top. Each section fading and blurring in. The parallax glow on the hero. All pure CSS — animation-timeline: scroll() and animation-timeline: view(). Zero JavaScript. Hardware-accelerated on the compositor thread.

scroll() — tied to page scroll

Progress bar (top of this page)

Parallax layers at different speeds

Background rotation:

view() — tied to element visibility

Each section on this page fades and unblurs as it enters the viewport. Scroll up and down to see sections animate in.

Previously this required IntersectionObserver + JS animation libraries. Now:

animation: fadeIn linear; animation-timeline: view(); animation-range: entry 0% entry 30%;
The rotating square above is driven by your scroll position — pure CSS, running on the GPU compositor thread. No requestAnimationFrame, no scroll event listeners, no JavaScript at all. This is the single biggest new capability in CSS.
05

@starting-style

Elements that arrive with grace.

When an element appears in the DOM, it needs an entry animation. Before @starting-style, this required Framer Motion, React Transition Group, or manual className toggling with setTimeout. Now CSS handles it natively.

@starting-style { .card { opacity: 0; transform: translateY(20px) scale(0.95); } } /* The card just needs a transition */ .card { transition: opacity 0.5s, transform 0.5s; }
Click the buttons. Each card slides up and scales in with a spring curve. Click again to remove it. The entry animation is pure CSS — no useState for animation state, no Framer Motion, no className toggling. The browser handles it.
06

text-wrap

Typography that cares.

Orphan words — a single word alone on the last line — look sloppy. text-wrap: pretty eliminates them automatically. text-wrap: balance makes multi-line headings visually even. Zero effort, instant quality upgrade.

Without text-wrap

Building effective learning experiences for teams

Our platform helps organisations develop their workforce through AI-powered interventions that close capability gaps and measure real outcomes.

With text-wrap: balance + pretty

Building effective learning experiences for teams

Our platform helps organisations develop their workforce through AI-powered interventions that close capability gaps and measure real outcomes.

Look at the headings. The balanced version distributes words more evenly across lines. The body text avoids leaving a single word orphaned on the last line. One CSS property. No JavaScript. No manual line breaks.

End of journey

This entire page
is mostly CSS.

No animation libraries. No GSAP. No Framer Motion. The scroll progress bar, the section reveals, the parallax, the form validation styling, the entry animations — all native CSS running on the browser compositor. The only JavaScript is React state for the interactive demos.

These capabilities are available in every modern browser today. The gap between what CSS can do and what most teams actually ship has never been wider. Close it.