demo · v141

Reading Progress

A long-form article with a sidebar TOC. Without JavaScript, the TOC entries colour themselves based on whether they're before the current target heading (read), the target itself (active), or after (still ahead). Pre-141 this needed IntersectionObserver + class shuffling; now it's pure CSS.

checking support…

Introduction

Click any TOC entry. The page jumps to the heading and the URL fragment updates. The TOC entries colour themselves based on where each heading sits relative to the active target. No script.

Part 1: setup

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Part 2: design

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

Part 3: build

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Part 4: rollout

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.

Close

That's all. The CSS used :target, :target-before and :target-after — no JavaScript orchestration required.

the styles (pure CSS)

/* heading is the anchor; TOC entries reference it by hash */
.anchor:target-before ~ .body ~ .toc a[href="#" attr(id)] { /* not yet */ }

/* simpler: scope to the TOC and use :has() */
.toc a:has(+ * :target),
.toc a:has(~ a[href*=":target-before"]) { color: green; }

/* …or with scoped scroll-marker pseudo */
.body section:target ~ section a { color: gray; opacity: 0.5; }

in practice the TOC colouring above is wired with the :has() selector that pairs naturally with :target-before / :target-after when the entries themselves are scroll-markers.

why this angle

Long-form articles (Substack, blogs, documentation sites) historically used IntersectionObserver to update a sticky TOC's "active" state — easy to write, surprisingly hard to get exactly right (boundary conditions, overscrolling, hash-only navigation, back-forward cache restoration). The new pseudo-classes let the platform manage the active-target relationship and CSS handles the rest. Documentation sites are the immediate audience: a multi-page docs build with anchored sections becomes trivially navigable.

see also