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.

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));
Modern
6 lines
1.scroller {
2  overflow-y: auto;
3}
4
5nav a:target-current {
6  color: var(--accent);
7}
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.

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.

Browser Support
48%
Chrome Edge
View on caniuse.com →
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.

ESC