How to Add a Sticky Sidebar to a Blog With CSS position: sticky

A CSS sticky sidebar is one of those small touches that instantly makes a blog feel more polished. Your table of contents, author box, or newsletter form follows the reader as they scroll, without any JavaScript. The problem? Most tutorials show you two lines of CSS and stop there. In real projects, position: sticky silently fails because of a parent container, an overflow rule, or a flex height issue you didn’t see coming.

In this tutorial, we’ll build a sticky sidebar for a blog layout using pure CSS, then walk through the real reasons it breaks and how to fix each one. We’ll also cover mobile behavior and a sensible fallback strategy.

What a CSS Sticky Sidebar Actually Does

A sticky element behaves like position: relative until its scroll offset threshold is crossed, then it behaves like position: fixed, but only within the bounds of its nearest scrolling ancestor. That last part is where most bugs live.

Unlike position: fixed, a sticky sidebar:

  • Stays inside its parent container and stops scrolling when the parent ends.
  • Doesn’t require you to reserve space with margins or padding hacks.
  • Works with normal document flow, so it plays well with responsive layouts.
blog sidebar layout

Step 1: The HTML Structure

Keep it simple. A blog post typically has a content column and a sidebar column inside a wrapper.

<div class="post-layout">
  <article class="post-content">
    <!-- Long blog content here -->
  </article>

  <aside class="post-sidebar">
    <div class="sidebar-inner">
      <h3>Table of Contents</h3>
      <!-- Links, author box, ads, newsletter... -->
    </div>
  </aside>
</div>

Step 2: The Core CSS (The Two Lines That Matter)

.post-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 3rem;
  align-items: start; /* critical, see below */
}

.post-sidebar {
  position: sticky;
  top: 1.5rem;
  align-self: start;
}

That’s the whole trick. position: sticky plus a top value tells the browser when to pin the element. But if you stop here, you’ll hit the classic bugs. Let’s fix them.

Step 3: Why Your Sticky Sidebar Isn’t Sticking

If your sidebar refuses to stick, one of these four things is almost always the cause.

1. The parent container has the same height as the sidebar

Sticky works while the parent is taller than the sticky element. In a flex or grid layout, children stretch to equal height by default. If your sidebar is stretched to match the article, there’s no room left to scroll past it, so it never sticks.

Fix: use align-items: start on the container, or align-self: start on the sidebar. This lets the article stay tall while the sidebar keeps its natural height.

2. An ancestor has overflow: hidden, auto, or scroll

This is the silent killer. If any ancestor up the DOM tree has an overflow value other than visible, sticky positions itself relative to that ancestor’s scroll container, which usually means it just doesn’t scroll at all.

Fix: inspect every ancestor in DevTools and make sure none of them have overflow set. If you need overflow for another reason (like clipping shadows), move it to a sibling or child element instead.

3. No top, bottom, left, or right value

position: sticky without a threshold does nothing. You must define at least one directional offset.

4. The parent is too short

If the article is only slightly taller than the sidebar, there’s very little scroll distance where the sticky behavior is visible. This isn’t a bug, but it looks like one. Test with real content length.

blog sidebar layout

Step 4: Handling Tall Sidebars

What if your sidebar is taller than the viewport? A pure top: 0 will cut off the bottom of the sidebar forever, since sticky only pins to one edge at a time. Originally covered on https://mimo.org.

For tall sidebars, allow the sidebar itself to scroll internally:

.post-sidebar {
  position: sticky;
  top: 1.5rem;
  align-self: start;
  max-height: calc(100vh - 3rem);
  overflow-y: auto;
}

Now the sidebar sticks, and if its contents exceed the viewport height, the user can scroll inside it.

Step 5: Mobile Behavior

On phones, a sticky sidebar next to content doesn’t make sense, the columns stack. You have two reasonable options:

  1. Disable sticky on mobile and let the sidebar sit naturally below the article.
  2. Keep sticky but pin a compact version, like a short table of contents at the top.

Here’s the disable approach:

@media (max-width: 900px) {
  .post-layout {
    grid-template-columns: 1fr;
  }
  .post-sidebar {
    position: static;
    max-height: none;
    overflow: visible;
  }
}

Step 6: Fallbacks for Old Browsers

As of 2026, position: sticky is supported by every modern browser, including all evergreen versions of Chrome, Edge, Firefox, and Safari. Global support is above 97%. You almost never need a JavaScript polyfill anymore.

That said, if you support very old enterprise browsers, the graceful fallback is simple: an unsupported browser will treat the property as invalid and the sidebar will scroll normally with the page. That’s an acceptable degradation for most blogs.

blog sidebar layout

Comparison: sticky vs fixed vs JavaScript

Approach Pros Cons
position: sticky No JS, respects parent bounds, responsive-friendly Breaks with overflow on ancestors
position: fixed Always visible, predictable Ignores parent, overlaps footer, harder on mobile
JavaScript Full control, works around edge cases Extra weight, scroll jank, more maintenance

Bonus: A Smooth Highlight Effect for a Table of Contents

If your sticky sidebar contains a table of contents, you can highlight the current section with a small scroll listener, or use the modern :target and scroll-behavior: smooth combo for a zero-JS version:

html {
  scroll-behavior: smooth;
  scroll-padding-top: 2rem;
}

The scroll-padding-top keeps anchor jumps from landing behind a fixed header. github.io published something useful on the subject.

Final Working Example

.post-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 3rem;
  align-items: start;
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem;
}

.post-sidebar {
  position: sticky;
  top: 1.5rem;
  align-self: start;
  max-height: calc(100vh - 3rem);
  overflow-y: auto;
}

@media (max-width: 900px) {
  .post-layout { grid-template-columns: 1fr; }
  .post-sidebar {
    position: static;
    max-height: none;
    overflow: visible;
  }
}

FAQ

Why is my CSS sticky sidebar not working?

Nine times out of ten it’s one of three things: an ancestor has overflow set to something other than visible, the parent container is the same height as the sidebar (fix with align-items: start), or you forgot to add a top value.

Do I need JavaScript for a sticky sidebar?

No. position: sticky is supported in every modern browser and handles the entire behavior natively. JavaScript is only needed for advanced features like syncing a table of contents with scroll position. A fuller account is out there.

What’s the difference between sticky and fixed positioning?

A fixed element is pinned to the viewport regardless of context. A sticky element is pinned only within its parent container, so it stops when the parent ends. Sticky is almost always the right choice for a blog sidebar.

Can I make only part of the sidebar sticky?

Yes. Wrap the sticky content in its own element and apply position: sticky to that inner wrapper instead of the entire sidebar column.

Does position: sticky affect SEO or Core Web Vitals?

Not directly. It’s a pure CSS layout technique with no impact on rendering performance, no layout shift, and no JavaScript execution cost, which actually helps CLS and INP compared to JS-based sticky implementations.

Recent Posts

No Posts Found!

Categories

Tags

    Subscribe

    You have been successfully Subscribed! Ops! Something went wrong, please try again.

    About Us

    Express Jam Studio was founded in 2004 by John Smith. John had previously worked for a courier company, but he saw an opportunity to start his own business in the web design and development industry.

    Contact Info

    Copyright © 2022 Express Jam Studio. All Rights Reserved.