webdevpuneet.com

Sticky Sidebar — position:sticky Sidebar HTML CSS JS

Sticky Sidebar · Layouts · Plain HTML, CSS & JS · Live preview

CategoryLayouts

Copy & paste

Source Code

<div class="ss-page">
  <div class="ss-layout">
    <main class="ss-main">
      <h1>Scaling Postgres to 10TB</h1>
      <p class="ss-lead">A practical field guide. Scroll — the sidebar stays in view and tracks your position.</p>
      <section id="intro"><h2>Introduction</h2><p>Postgres scales further than most teams expect before they reach for a distributed store. The wins come from disciplined indexing, partitioning, and connection management long before sharding.</p><p>This guide walks through the levers in the order you should pull them.</p></section>
      <section id="indexing"><h2>Indexing</h2><p>The right index turns a sequential scan into an index scan. Cover your hottest WHERE and ORDER BY columns, watch for unused indexes, and prefer partial indexes for skewed predicates.</p><p>Every index costs write throughput, so measure before adding.</p></section>
      <section id="partitioning"><h2>Partitioning</h2><p>Range-partition large append-only tables by time. Old partitions detach and archive cheaply, and the planner prunes irrelevant partitions from queries.</p><p>Keep partition counts reasonable — thousands hurt planning time.</p></section>
      <section id="pooling"><h2>Connection pooling</h2><p>A pooler like PgBouncer in transaction mode lets thousands of clients share a small set of backend connections, which is the single biggest stability win under load.</p></section>
      <section id="scaling"><h2>Read scaling</h2><p>Stream to read replicas and route read-only traffic to them. Reserve the primary for writes and read-after-write consistency needs.</p><p>That's the playbook — in order.</p></section>
    </main>
    <aside class="ss-aside">
      <div class="ss-stick">
        <div class="ss-card">
          <h4>On this page</h4>
          <nav class="ss-toc" id="ssToc">
            <a href="#intro">Introduction</a>
            <a href="#indexing">Indexing</a>
            <a href="#partitioning">Partitioning</a>
            <a href="#pooling">Connection pooling</a>
            <a href="#scaling">Read scaling</a>
          </nav>
        </div>
        <div class="ss-card ss-cta"><strong>Get the full guide</strong><p>12 chapters, real benchmarks.</p><button type="button">Download PDF</button></div>
      </div>
    </aside>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

position:sticky sidebar
One CSS property pins the sidebar — no scroll listeners or fixed-position math.
Grid with align-items:start
Top-aligned columns give the sticky element room to travel within its parent.
IntersectionObserver scroll-spy
The active section is detected by a reading-band rootMargin, off the main thread.
Active TOC highlight
The link for the section in view lights up as you scroll.
Smooth in-page links
Clicking a TOC link smooth-scrolls with scrollIntoView.
scroll-margin-top offset
Sections land below the sticky offset, not flush against the top.
Responsive collapse
Single column on phones with the sidebar un-stuck and the CTA hidden.
No library
Pure HTML/CSS/JS using modern sticky + IntersectionObserver.

About this UI Snippet

Sticky Sidebar — A position:sticky Aside with Scroll-Spy Table of Contents

Screenshot of the Sticky Sidebar snippet rendered live

A sticky sidebar — one that scrolls with the page until it reaches the top, then stays pinned while the main content keeps moving — is the standard layout for documentation, long articles, and product pages. This snippet builds it with modern position: sticky (no scroll-listener hacks) and adds a table of contents that highlights the section you're currently reading, in plain HTML, CSS, and vanilla JavaScript.

Sticky with one CSS property

The sidebar column (.ss-aside) is set to position: sticky; top: 20px. That's the entire mechanism: the column scrolls normally until its top hits 20px from the viewport top, then it sticks there while the rest of the page scrolls past — and unsticks naturally when its container scrolls away. position: sticky replaced the old approach of listening to scroll and toggling position: fixed with manual offset math; it's smoother, jank-free, and a fraction of the code. The key requirement is that the sticky element's parent be tall enough to scroll within, which the grid layout provides.

Grid layout with top alignment

The page is a two-column grid (1fr 250px) with align-items: start, which is essential: without it, grid would stretch the sidebar column to the full height of the main content, and a sticky child can't stick inside a parent that's exactly as tall as the scroll area. Starting the items at the top lets the sidebar column be only as tall as its content, giving the sticky wrapper room to travel.

Scroll-spy with IntersectionObserver

The table of contents highlights the active section using an IntersectionObserver rather than scroll-position math. Each section is observed with a rootMargin that defines a "reading band" near the top of the viewport (-20% 0px -70% 0px); whichever section enters that band becomes active, and its TOC link lights up. Using IntersectionObserver is both more efficient (the browser does the work, off the main thread) and more accurate than computing offsets on every scroll event — the modern way to build scroll-spy.

Smooth in-page navigation

Clicking a TOC link smooth-scrolls to its section with scrollIntoView({ behavior: 'smooth' }), and scroll-margin-top on each section ensures the heading lands below the sticky offset rather than flush against the top. Together with the active-link highlight, the TOC both navigates and orients.

Responsive collapse

On narrow screens the grid collapses to one column, the sidebar becomes static (un-sticky), and the secondary CTA card hides — because a sticky sidebar makes no sense in a single-column phone layout. This keeps the reading experience clean on mobile while delivering the full sticky-and-spy behaviour on wider screens. It's a complete, drop-in reference for the sticky-sidebar pattern behind every docs site.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSAn article renders with a sidebar containing a table of contents and a CTA card.
  2. 2
    Scroll the pageThe sidebar follows until it reaches the top, then stays pinned while the article scrolls.
  3. 3
    Watch the active linkThe TOC highlights whichever section is currently in your reading band.
  4. 4
    Click a TOC linkIt smooth-scrolls to that section, landing the heading below the sticky offset.
  5. 5
    Resize narrowOn phones the layout collapses to one column and the sidebar becomes static.
  6. 6
    Adapt itChange the sticky top offset, column widths, or put your own content in the sidebar.

Real-world uses

Common Use Cases

Docs outline pinning
Pin a section TOC beside docs content with a table of contents style list, using one CSS position: sticky property and no scroll listener.
Long-form articles
Keep a reading progress outline in view with scroll progress, with align-items: start giving the sticky column room to travel.
Product and pricing pages
Stick a summary or call-to-action card beside the main content, so the purchase option stays visible as the reader scrolls.
Checkout and forms
Keep an order summary visible beside a checkout form, staying pinned as a long form moves.
Dashboards and scroll-spy learning
Pin filters or a legend while data scrolls, and pair with a scroll spy nav to learn how a reading-band observer detects the active section.

Got questions?

Frequently Asked Questions

position:sticky keeps the element in normal flow until it reaches a scroll threshold, then pins it — and automatically releases it when its container scrolls away. position:fixed requires a scroll listener to toggle it on/off and manual math to place it, which is jankier and far more code. Sticky is hardware-accelerated, handles the start and end of the sticky range for you, and needs just two CSS lines.

By default grid stretches items to fill the row's height. If the sidebar column stretches to match the tall main column, it becomes exactly as tall as the scroll area — and a sticky child has nowhere to travel, so it never appears to stick. align-items: start lets the sidebar column be only as tall as its content, leaving room for the sticky wrapper to move and then pin.

An IntersectionObserver watches each section with a rootMargin of "-20% 0px -70% 0px", which defines a thin band near the top of the viewport. When a section's top crosses into that band it reports as intersecting, and its matching TOC link gets the active class. This is more efficient and accurate than recomputing offsets on every scroll event, since the browser handles the detection off the main thread.

Because the sidebar sticks 20px from the top, an in-page link that scrolls a heading flush to the viewport top would tuck it under that offset. scroll-margin-top adds a buffer so scrollIntoView (and native anchor jumps) land the heading just below the sticky region, fully visible. It's the clean, CSS-only way to offset anchor targets.

The layout is pure CSS, so it ports as-is. For the scroll-spy, set up the IntersectionObserver in a useEffect (React), onMounted/onUnmounted (Vue), or ngAfterViewInit/ngOnDestroy (Angular), disconnecting it on cleanup, and track the active id in state to drive the link class. The sticky CSS and rootMargin logic are framework-agnostic.