How to create a sidebar that’s sticky but also scrolls
By Flavio Copes
Learn how to build a sidebar that stays sticky yet scrolls on short screens using CSS position sticky, top 0, height 100dvh, and overflow-y auto, or Tailwind.
To make a sidebar fixed but also accommodate screens that are not tall enough to contain the entire sidebar, use this CSS:
.sidebar {
position: sticky;
top: 0;
height: 100dvh;
overflow-y: auto;
}
Prefer 100dvh over 100vh. On mobile, the browser chrome shows and hides, and dvh tracks the visible viewport. More on those units in CSS units.
Using Tailwind CSS:
<div class='sticky top-0 h-dvh overflow-y-auto'>
...
</div>
h-dvh maps to height: 100dvh. The older h-screen utility is height: 100vh.
The problem this solves
A sidebar with lots of links has two competing needs.
You want it to stay visible while the main content scrolls. That’s what position: sticky with top: 0 does: the sidebar scrolls normally until it reaches the top of the viewport, then it stays pinned there.
But on a laptop screen, a long sidebar might be taller than the viewport. If it just sticks, the links at the bottom become unreachable. You can never scroll to them.
How the four properties work together
Each line has a job:
position: sticky makes the element stick within its parent as you scroll.
top: 0 sets where it sticks: flush against the top of the viewport.
height: 100dvh caps the sidebar at exactly one visible viewport height, so it never extends below the visible area.
overflow-y: auto is the trick that makes it work on short screens. If the sidebar content is taller than the viewport, the sidebar gets its own scrollbar. You scroll the page to move the content, and you scroll inside the sidebar to reach its bottom links.
When the content fits, auto shows no scrollbar at all, so tall screens are unaffected.
Why isn’t my sidebar sticking?
The most common failure happens in flex layouts, which is exactly where sidebars live.
By default, flex items stretch to the height of their container. If your sidebar is as tall as the whole page, there’s no room for it to move, so sticky does nothing. Setting height: 100dvh fixes this, which is another reason it’s in the snippet. You can also use align-self: flex-start.
The other thing to check: no ancestor between the sidebar and the page can have overflow: hidden. That changes which container the sidebar sticks inside, and the effect breaks. If sticky stops working after a refactor, walk up the tree and look at the overflow values.
Notice we used sticky instead of position: fixed. Fixed removes the element from the layout, so you’d have to compensate with margins on the content. Sticky keeps the sidebar in the normal flow, and the layout keeps working.
Want me to talk about your product? You can sponsor this site.