Selector Intermediate

Scroll spy without IntersectionObserver

Highlighting navigation links based on scroll position used to require JavaScript IntersectionObserver or scroll event listeners. Now CSS can track which section is in view with scroll-target-group and the :target-current pseudo-class.

Modern
6 lines
1.scroller {
2  overflow-y: auto;
3}
4
5nav a:target-current {
6  color: var(--accent);
7}
Old 18 lines
1/* JS IntersectionObserver approach */
2const observer = new IntersectionObserver(
3  (entries) => {
4    entries.forEach(entry => {
5      const link = document
6        .querySelector(`a[href="#
7        ${entry.target.id}"]`);
8      link.classList.toggle(
9        'active',
10        entry.isIntersecting);
11    });
12  },
13  { threshold: 0.5 }
14);
15
16document.querySelectorAll('section')
17  .forEach(s =>
18    observer.observe(s));
Limited availability 48% global usage

This feature is not Baseline because it does not work in some of the most widely-used browsers.

135+
135+
scroll the box, nav highlights follow

Intro

This is the intro section content. Scroll to see the navigation highlight change as each section enters the viewport.

Features

This is the features section content. Scroll to see the navigation highlight change as each section enters the viewport.

Usage

This is the usage section content. Scroll to see the navigation highlight change as each section enters the viewport.

API

This is the api section content. Scroll to see the navigation highlight change as each section enters the viewport.

Kinsta

Your first month is free

Managed WordPress hosting for faster sites.

Learn more
⚑

Zero JavaScript

No IntersectionObserver, no scroll event listeners, no class toggling. The browser tracks which section is in view natively.

✦

Always in sync

The :target-current pseudo-class updates in real-time as the user scrolls. No timing bugs or threshold tuning.

∞

Works with CSS scroll-snap

Pairs naturally with scroll-snap for section-based layouts. The active indicator follows snap points automatically.

Lines Saved
18 β†’ 6
No JS required
Old Approach
IntersectionObserver
JS scroll tracking
Modern Approach
:target-current
CSS pseudo-class

How it works

Scroll spy navigation β€” highlighting the current section's link as the user scrolls β€” has always required JavaScript. The typical approach uses IntersectionObserver to watch each section, then toggles an 'active' class on the corresponding nav link. This works but requires careful threshold tuning, cleanup on unmount, and can fall out of sync with fast scrolling.

The CSS approach uses :target-current, a pseudo-class that matches anchor links pointing to the element currently in the scroll port. Combined with smooth scrolling and scroll-snap, you get a complete scroll-spy navigation with no JavaScript at all. The browser handles the tracking natively, so it's always perfectly in sync.

β™Ώ
Accessibility note: CSS scroll spy only changes the visual styling of the active link. Screen readers rely on aria-current="page" to identify the active item. Adding this dynamically requires JavaScript.

New CSS drops.

Join 600+ readers who've survived clearfix hacks.

ESC