<main>
	<div>
		<h1>Smooth Scrolling Sticky ScrollSpy Navigation</h1>
		<p><em>Want an explanation of how this works?<br />&rarr; <a href="https://www.bram.us/2020/01/10/smooth-scrolling-sticky-scrollspy-navigation/" target="_top">https://www.bram.us/2020/01/10/smooth-scrolling-sticky-scrollspy-navigation/</a><br />&rarr; <a href="https://www.bram.us/2021/03/04/the-future-of-css-scroll-linked-animations-part-2/" target="_top">https://www.bram.us/2021/03/04/the-future-of-css-scroll-linked-animations-part-2/</a></em></p>
		<section id="introduction">
			<h2>Introduction</h2>
			<p>…</p>
		</section>
		<section id="request-response">
			<h2>Request &amp; Response</h2>
			<p>…</p>
		</section>
		<section id="authentication">
			<h2>Authentication</h2>
			<p>…</p>
		</section>
		<section id="endpoints">
			<h2>Endpoints</h2>
			<section id="endpoints--root">
				<h3>Root</h3>
				<p>…</p>
			</section>
			<section id="endpoints--cities-overview">
				<h3>Cities Overview</h3>
				<p>…</p>
			</section>
			<section id="endpoints--city-detail">
				<h3>City Detail</h3>
				<p>…</p>
			</section>
			<section id="endpoints--city-config">
				<h3>City Config</h3>
				<p>…</p>
			</section>
			<section id="endpoints--city-spots-overview">
				<h3>City Spots Overview</h3>
				<p>…</p>
			</section>
			<section id="endpoints--city-spot-detail">
				<h3>City Spot Detail</h3>
				<p>…</p>
			</section>
			<section id="endpoints--city-icons-overview">
				<h3>City Icons Overview</h3>
				<p>…</p>
			</section>
			<section id="endpoints--city-icon-detail">
				<h3>City Icon Detail</h3>
				<p>…</p>
			</section>
		</section>
		<section id="links">
			<h2>Links</h2>
			<p>…</p>
		</section>
		<section id="expanders">
			<h2>Expanders</h2>
			<p>…</p>
		</section>
		<section id="filters">
			<h2>Filters</h2>
			<p>…</p>
		</section>
	</div>
	<nav class="section-nav">
		<ol>
			<li><a href="#introduction">Introduction</a></li>
			<li><a href="#request-response">Request &amp; Response</a></li>
			<li><a href="#authentication">Authentication</a></li>
			<li><a href="#endpoints">Endpoints</a>
				<ul>
					<li class=""><a href="#endpoints--root">Root</a></li>
					<li class=""><a href="#endpoints--cities-overview">Cities Overview</a></li>
					<li class=""><a href="#endpoints--city-detail">City Detail</a></li>
					<li class=""><a href="#endpoints--city-config">City Config</a></li>
					<li class=""><a href="#endpoints--city-spots-overview">City Spots Overview</a></li>
					<li class=""><a href="#endpoints--city-spot-detail">City Spot Detail</a></li>
					<li class=""><a href="#endpoints--city-icons-overview">City Icons Overview</a></li>
					<li class=""><a href="#endpoints--city-icon-detail">City Icon Detail</a></li>
				</ul>
			</li>
			<li class=""><a href="#links">Links</a></li>
			<li class=""><a href="#expanders">Expanders</a></li>
			<li class=""><a href="#filters">Filters</a></li>
		</ol>
	</nav>
</main>


<div class="warning">
	<p>⚠️ Your browser does not support CSS Scroll-Linked Animations, so this demo won't work.<br />If you're feeling adventurous use Chrome 89+ with “Experimental Web Platform Features” enabled.<br />Alternatively, you can try <a href="https://codepen.io/bramus/pen/ExaEqMJ" target="_top">this JS-based version</a></p>
</div>
/* 1. Enable smooth scrolling */
html {
	scroll-behavior: smooth;
}

/* 2. Make nav sticky */
main > nav {
	position: sticky;
	top: 2rem;
	align-self: start;
}

/* 3. ScrollSpy active styles */
@keyframes activate-on-enter {
	to {
		color: #333;
	}
}
@keyframes deactivate-on-leave {
	to {
		color: #ccc;
	}
}




@supports (animation-timeline: works) {
	/* Hide warning */
	.warning {
		display: none;
	}

	/* Hook Animations */
	.section-nav li > a {
		animation:
			1s activate-on-enter linear forwards,
			1s deactivate-on-leave linear forwards;
	}

}

/* The code below was autogenerated using a little helper script:
   https://gist.github.com/bramus/600dd1bc3745b3b441375e68362e9a0e
*/
@scroll-timeline section-introduction-enter {
	source: auto;
	start: selector(#introduction) end 0;
	end: selector(#introduction) end 1;
	scroll-offsets: selector(#introduction) end 0, selector(#introduction) end 1;
	time-range: 1s;
}

@scroll-timeline section-introduction-leave {
	source: auto;
	start: selector(#introduction) start 1;
	end: selector(#introduction) start 0;
	scroll-offsets: selector(#introduction) start 1,
		selector(#introduction) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#introduction"] {
	animation-timeline: section-introduction-enter, section-introduction-leave;
}

@scroll-timeline section-request-response-enter {
	source: auto;
	start: selector(#request-response) end 0;
	end: selector(#request-response) end 1;
	scroll-offsets: selector(#request-response) end 0,
		selector(#request-response) end 1;
	time-range: 1s;
}

@scroll-timeline section-request-response-leave {
	source: auto;
	start: selector(#request-response) start 1;
	end: selector(#request-response) start 0;
	scroll-offsets: selector(#request-response) start 1,
		selector(#request-response) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#request-response"] {
	animation-timeline: section-request-response-enter,
		section-request-response-leave;
}

@scroll-timeline section-authentication-enter {
	source: auto;
	start: selector(#authentication) end 0;
	end: selector(#authentication) end 1;
	scroll-offsets: selector(#authentication) end 0,
		selector(#authentication) end 1;
	time-range: 1s;
}

@scroll-timeline section-authentication-leave {
	source: auto;
	start: selector(#authentication) start 1;
	end: selector(#authentication) start 0;
	scroll-offsets: selector(#authentication) start 1,
		selector(#authentication) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#authentication"] {
	animation-timeline: section-authentication-enter, section-authentication-leave;
}

@scroll-timeline section-endpoints-enter {
	source: auto;
	start: selector(#endpoints) end 0;
	end: selector(#endpoints) end 1;
	scroll-offsets: selector(#endpoints) end 0, selector(#endpoints) end 1;
	time-range: 1s;
}

@scroll-timeline section-endpoints-leave {
	source: auto;
	start: selector(#endpoints) start 1;
	end: selector(#endpoints) start 0;
	scroll-offsets: selector(#endpoints) start 1, selector(#endpoints) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#endpoints"] {
	animation-timeline: section-endpoints-enter, section-endpoints-leave;
}

@scroll-timeline section-endpoints--root-enter {
	source: auto;
	start: selector(#endpoints--root) end 0;
	end: selector(#endpoints--root) end 1;
	scroll-offsets: selector(#endpoints--root) end 0,
		selector(#endpoints--root) end 1;
	time-range: 1s;
}

@scroll-timeline section-endpoints--root-leave {
	source: auto;
	start: selector(#endpoints--root) start 1;
	end: selector(#endpoints--root) start 0;
	scroll-offsets: selector(#endpoints--root) start 1,
		selector(#endpoints--root) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#endpoints--root"] {
	animation-timeline: section-endpoints--root-enter,
		section-endpoints--root-leave;
}

@scroll-timeline section-endpoints--cities-overview-enter {
	source: auto;
	start: selector(#endpoints--cities-overview) end 0;
	end: selector(#endpoints--cities-overview) end 1;
	scroll-offsets: selector(#endpoints--cities-overview) end 0,
		selector(#endpoints--cities-overview) end 1;
	time-range: 1s;
}

@scroll-timeline section-endpoints--cities-overview-leave {
	source: auto;
	start: selector(#endpoints--cities-overview) start 1;
	end: selector(#endpoints--cities-overview) start 0;
	scroll-offsets: selector(#endpoints--cities-overview) start 1,
		selector(#endpoints--cities-overview) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#endpoints--cities-overview"] {
	animation-timeline: section-endpoints--cities-overview-enter,
		section-endpoints--cities-overview-leave;
}

@scroll-timeline section-endpoints--city-detail-enter {
	source: auto;
	start: selector(#endpoints--city-detail) end 0;
	end: selector(#endpoints--city-detail) end 1;
	scroll-offsets: selector(#endpoints--city-detail) end 0,
		selector(#endpoints--city-detail) end 1;
	time-range: 1s;
}

@scroll-timeline section-endpoints--city-detail-leave {
	source: auto;
	start: selector(#endpoints--city-detail) start 1;
	end: selector(#endpoints--city-detail) start 0;
	scroll-offsets: selector(#endpoints--city-detail) start 1,
		selector(#endpoints--city-detail) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#endpoints--city-detail"] {
	animation-timeline: section-endpoints--city-detail-enter,
		section-endpoints--city-detail-leave;
}

@scroll-timeline section-endpoints--city-config-enter {
	source: auto;
	start: selector(#endpoints--city-config) end 0;
	end: selector(#endpoints--city-config) end 1;
	scroll-offsets: selector(#endpoints--city-config) end 0,
		selector(#endpoints--city-config) end 1;
	time-range: 1s;
}

@scroll-timeline section-endpoints--city-config-leave {
	source: auto;
	start: selector(#endpoints--city-config) start 1;
	end: selector(#endpoints--city-config) start 0;
	scroll-offsets: selector(#endpoints--city-config) start 1,
		selector(#endpoints--city-config) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#endpoints--city-config"] {
	animation-timeline: section-endpoints--city-config-enter,
		section-endpoints--city-config-leave;
}

@scroll-timeline section-endpoints--city-spots-overview-enter {
	source: auto;
	start: selector(#endpoints--city-spots-overview) end 0;
	end: selector(#endpoints--city-spots-overview) end 1;
	scroll-offsets: selector(#endpoints--city-spots-overview) end 0,
		selector(#endpoints--city-spots-overview) end 1;
	time-range: 1s;
}

@scroll-timeline section-endpoints--city-spots-overview-leave {
	source: auto;
	start: selector(#endpoints--city-spots-overview) start 1;
	end: selector(#endpoints--city-spots-overview) start 0;
	scroll-offsets: selector(#endpoints--city-spots-overview) start 1,
		selector(#endpoints--city-spots-overview) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#endpoints--city-spots-overview"] {
	animation-timeline: section-endpoints--city-spots-overview-enter,
		section-endpoints--city-spots-overview-leave;
}

@scroll-timeline section-endpoints--city-spot-detail-enter {
	source: auto;
	start: selector(#endpoints--city-spot-detail) end 0;
	end: selector(#endpoints--city-spot-detail) end 1;
	scroll-offsets: selector(#endpoints--city-spot-detail) end 0,
		selector(#endpoints--city-spot-detail) end 1;
	time-range: 1s;
}

@scroll-timeline section-endpoints--city-spot-detail-leave {
	source: auto;
	start: selector(#endpoints--city-spot-detail) start 1;
	end: selector(#endpoints--city-spot-detail) start 0;
	scroll-offsets: selector(#endpoints--city-spot-detail) start 1,
		selector(#endpoints--city-spot-detail) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#endpoints--city-spot-detail"] {
	animation-timeline: section-endpoints--city-spot-detail-enter,
		section-endpoints--city-spot-detail-leave;
}

@scroll-timeline section-endpoints--city-icons-overview-enter {
	source: auto;
	start: selector(#endpoints--city-icons-overview) end 0;
	end: selector(#endpoints--city-icons-overview) end 1;
	scroll-offsets: selector(#endpoints--city-icons-overview) end 0,
		selector(#endpoints--city-icons-overview) end 1;
	time-range: 1s;
}

@scroll-timeline section-endpoints--city-icons-overview-leave {
	source: auto;
	start: selector(#endpoints--city-icons-overview) start 1;
	end: selector(#endpoints--city-icons-overview) start 0;
	scroll-offsets: selector(#endpoints--city-icons-overview) start 1,
		selector(#endpoints--city-icons-overview) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#endpoints--city-icons-overview"] {
	animation-timeline: section-endpoints--city-icons-overview-enter,
		section-endpoints--city-icons-overview-leave;
}

@scroll-timeline section-endpoints--city-icon-detail-enter {
	source: auto;
	start: selector(#endpoints--city-icon-detail) end 0;
	end: selector(#endpoints--city-icon-detail) end 1;
	scroll-offsets: selector(#endpoints--city-icon-detail) end 0,
		selector(#endpoints--city-icon-detail) end 1;
	time-range: 1s;
}

@scroll-timeline section-endpoints--city-icon-detail-leave {
	source: auto;
	start: selector(#endpoints--city-icon-detail) start 1;
	end: selector(#endpoints--city-icon-detail) start 0;
	scroll-offsets: selector(#endpoints--city-icon-detail) start 1,
		selector(#endpoints--city-icon-detail) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#endpoints--city-icon-detail"] {
	animation-timeline: section-endpoints--city-icon-detail-enter,
		section-endpoints--city-icon-detail-leave;
}

@scroll-timeline section-links-enter {
	source: auto;
	start: selector(#links) end 0;
	end: selector(#links) end 1;
	scroll-offsets: selector(#links) end 0, selector(#links) end 1;
	time-range: 1s;
}

@scroll-timeline section-links-leave {
	source: auto;
	start: selector(#links) start 1;
	end: selector(#links) start 0;
	scroll-offsets: selector(#links) start 1, selector(#links) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#links"] {
	animation-timeline: section-links-enter, section-links-leave;
}

@scroll-timeline section-expanders-enter {
	source: auto;
	start: selector(#expanders) end 0;
	end: selector(#expanders) end 1;
	scroll-offsets: selector(#expanders) end 0, selector(#expanders) end 1;
	time-range: 1s;
}

@scroll-timeline section-expanders-leave {
	source: auto;
	start: selector(#expanders) start 1;
	end: selector(#expanders) start 0;
	scroll-offsets: selector(#expanders) start 1, selector(#expanders) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#expanders"] {
	animation-timeline: section-expanders-enter, section-expanders-leave;
}

@scroll-timeline section-filters-enter {
	source: auto;
	start: selector(#filters) end 0;
	end: selector(#filters) end 1;
	scroll-offsets: selector(#filters) end 0, selector(#filters) end 1;
	time-range: 1s;
}

@scroll-timeline section-filters-leave {
	source: auto;
	start: selector(#filters) start 1;
	end: selector(#filters) start 0;
	scroll-offsets: selector(#filters) start 1, selector(#filters) start 0;
	time-range: 1s;
}
.section-nav li > a[href="#filters"] {
	animation-timeline: section-filters-enter, section-filters-leave;
}

/* Sidebar Navigation */
.section-nav {
	padding-left: 0;
	border-left: 1px solid #efefef;
}

.section-nav a {
	text-decoration: none;
	display: block;
	padding: 0.125rem 0;
	color: #ccc;
	transition: all 50ms ease-in-out; /* 💡 This small transition makes setting of the active state smooth */
}

.section-nav a:hover,
.section-nav a:focus {
	color: #666;
}


/* Warning Box */
.warning {
	position: fixed;
	bottom: 1em;
	right: 1em;
	left: 1em;
	padding: 1em;
	border: 1px solid #ccc;
	z-index: 1;
	text-align: center;
	background: rgba(255 255 205 / 0.8);
	color: #000;
	line-height: 1.42;
}

.warning p {
	margin: 0;
	padding: 0;
}



/** Poor man's reset **/
* {
	box-sizing: border-box;
}

html,
body {
	background: #fff;
}

body {
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
		"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}

ul,
ol {
	list-style: none;
	margin: 0;
	padding: 0;
}
li {
	margin-left: 1rem;
}

h1 {
	font-weight: 300;
}

/** page layout **/
main {
	display: grid;
	grid-template-columns: 1fr 15em;
	max-width: 100em;
	width: 90%;
	margin: 0 auto;
}

/** enlarge the sections for this demo, so that we have a long scrollable page **/
section {
	padding-bottom: 20rem;
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.