CSSには、スクロール位置が対象コンテンツの「前か」「後か」を判定するのに役立つものがあります。:target-before、:target-after、:target-currentの3つの疑似クラス、scroll-target-groupプロパティを使うと、今までJavaScriptを必要としていたスクロール連動のインタラクションをCSSだけで実現できます。
この記事ではそれぞれのCSSの使い方と、CSSだけで実装したインタラクションのデモを紹介します。
※注意:本記事のデモは、Chrome・Edge 142以上でご覧ください。
スクロールに連動させるCSSの基本の使い方
ウェブサイトの「目次」を例に基本的な使い方を説明します。スクロールに連動して目次のスタイルが切り替わるインタラクションをCSSだけで実装してみます。
スクロールが通過したコンテンツは「通過ずみ」のスタイル、今表示しているところは「強調」、これから表示するところは「未到達」のスタイルを設定します。

1. 外側にscroll-target-groupプロパティを設定
まずはスクロールに応じたスタイルを設定したい要素の外側の要素にscroll-target-group: autoを記述します。scroll-target-groupはautoまたはnoneのどちらかを指定します。スクロールに連動させたい場合はautoを使います。
この例では目次を<ol>要素と<li>要素でマークアップしています。外側である<ol>要素にscroll-target-group: autoを設定します。
<ol class="list">
<li>目次1</li>
<li>目次2</li>
<li>目次3</li>
</ol>
.list {
scroll-target-group: auto;
}
2. リストの中に<a>要素を配置する
scroll-target-group: autoを設定したコンテナーの子孫に<a>要素を配置します。
<a>要素にhref="#section1"を設定します。:target-beforeなどの疑似クラスは、リンク先の要素(<section id="section1">)の表示位置と連動して有効化されるため、現在のスクロール位置にもとづいた表現が可能になります。
<ol class="list">
<li><a href="#section1">目次1</a></li>
<li><a href="#section2">目次2</a></li>
<li><a href="#section3">目次3</a></li>
</ol>
<section id="section1">
目次1の内容です
</section>
3. 疑似クラスにスタイルを記述する
スクロールに連動したスタイルで使える疑似クラスは以下の3つです。それぞれの疑似クラスに異なるスタイルを記述してみます。
:target-current:現在表示中の状態:target-before:スクロール通過ずみの状態:target-after:スクロール未到達の状態
:target-current疑似クラスに関しては『JavaScript不要! HTMLとCSSでつくるカルーセルUI』でも紹介しているのであわせてご確認ください。
.list {
/* 省略 */
/* スクロール通過ずみ: 薄いグレー */
a:target-before {
color: #999;
}
/* 現在表示中: 強調表示 */
a:target-current {
color: #0066cc;
font-weight: bold;
}
/* スクロール未到達: 濃いグレー */
a:target-after {
color: #333;
}
}
最小限の実装でスクロールと連動したインタラクションを実装できました。
デモの紹介
使い方がわかったところでデモを紹介します。いずれもスタイルはCSSのみで記述しています。
デモ①:目次
使い方の説明で実装した目次とほぼ同じ仕組みですが、ヘッダーのメニューに適用した例です。
.nav__list {
/* 省略 */
scroll-target-group: auto;
}
.nav__link {
/* 省略 */
/* スクロール通過ずみ */
&:target-before {
color: var(--color-text-muted);
}
/* 現在表示中 */
&:target-current {
color: var(--color-primary);
text-decoration: underline;
}
/* スクロール未到達 */
&:target-after {
color: var(--color-secondary);
}
}
デモ②:進捗を表示
スクロールの状態に応じて進捗をわかりやすく表示したデモです。申し込みフォームなどにも応用できそうです。
.progress__item {
/* 省略 */
/* スクロール通過ずみ */
/* step間の縦線を表示 */
&:has(.progress__link:target-before)::after {
height: 100%;
}
}
.progress__link {
/* 省略 */
/* スクロール通過ずみ */
&:target-before {
color: var(--color-text-muted);
/* ✔️アイコンを表示 */
.progress__text::after {
content: "✔️";
position: absolute;
top: 0;
right: -18px;
}
.progress__badge {
color: var(--color-text-muted);
}
}
/* 現在表示中 */
&:target-current {
color: var(--color-primary);
.progress__badge {
background-color: var(--color-primary);
color: var(--color-white);
border-color: transparent;
}
}
/* スクロール未到達 */
&:target-after {
color: var(--color-text);
}
}
:has()疑似クラスを使うと、リッチなスタイルも簡潔に記述できます。:has()疑似クラスの使い方は『has()疑似クラスでコーディングが変わる! CSS最新スタイリング』で詳しく解説しています。
デモ③:横スクロールと組み合わせた例
縦スクロールだけでなく横スクロールでも使えます。旅程を表示した以下のデモでは横のスクロール位置に応じてヘッダーのスタイルが変わります。
.nav__list {
&::after {
/* バスのアイコンをアンカーポジショニングで表示 */
top: anchor(top);
right: anchor(right);
height: anchor-size(height);
width: calc(anchor-size(width) + 24px);
position-anchor: --current-city;
/* 省略 */
}
}
.nav__item {
/* 省略 */
/* 現在表示中 */
&:has(.nav__link:target-current) {
border-bottom: 1px solid var(--color-border);
}
/* スクロール未到達 */
&:has(.nav__link:target-after) {
border-bottom: 1px solid var(--color-border);
}
}
.nav__link {
/* 省略 */
/* スクロール通過ずみ */
&:target-before {
color: var(--color-text-muted);
}
/* 現在表示中 */
&:target-current {
color: var(--color-primary);
/* 現在表示中の要素をアンカーとして指定。バスのアイコンを移動させる */
anchor-name: --current-city;
}
}
バスのアイコンが移動するスタイルはCSSのアンカーポジショニングを使用しています。詳しくは『CSSアンカーポジショニング入門 anchor()・anchor-size()の使い方』をご確認ください。
対応ブラウザ
:target-before、:target-after疑似クラスは、Chrome・Edge 142(2025年10月)以上で利用可能です。
参照:Can I use…
まとめ
:target-before、:target-after疑似クラスを使うことで、JavaScriptなしでインタラクティブなUIを簡単に実装できるようになりました。現在はChromeとEdgeだけの機能ですが、今後他のブラウザにも広がることを期待したいですね!

