09 / 30
All 30 in 30 CSS Sidebar Layouts
- 01Modern SaaS Dashboard Sidebar Menu with Native Dark Mode Switch
- 02Accessible Admin Panel Sidebar with CSS Tooltips and Icon Collapse
- 03Developer Documentation Sidebar with Scroll-Synced Nesting
- 04Mobile-First Responsive Sidebar to Bottom Navigation Switch Layout
- 05Data Analytics Sidebar Layout with CSS Subgrid Alignment
- 06Smooth Animated Collapsible Sidebar Menu with Icon-Only Mode
- 07CSS Position Sticky Sidebar Layout for E-Commerce and Blogs
- 08Pure CSS Collapsible Sidebar Drawer Menu without JavaScript
- 09CSS Fixed Sidebar Layout with Independent Scrollable Main Content
- 10Off-Canvas Navigation Drawer for Mobile & Desktop Web Apps
- 11Right-Aligned CSS Sidebar Layout for Secondary Tool Panels
- 12Two-Pane Webmail UI Layout with CSS Flexbox & Grid
- 13Dual Sidebar App Shell Layout with Left Nav and Right Context Panel
- 14Compact Mini Icon Rail Sidebar Navigation for SaaS Web Apps
- 15Responsive E-Commerce Product Filter Sidebar with Native Accordion Menu
- 16Modern Floating Glassmorphism Sidebar UI Component
- 17CSS Sidebar Menu with Sticky User Profile Footer
- 18Push Content Sidebar Navigation Layout with Smooth CSS Transitions
- 19Off-Canvas Sidebar Overlay Layout with Blur Backdrop
- 20Persistent Collapsible State Sidebar with CSS Variables
- 21App Sidebar Navigation with Integrated Sticky Search Bar
- 22Section-Grouped Sidebar Navigation Menu with Header Labels
- 23CSS Target Active Indicator Sidebar Menu without JavaScript
- 24Multi-Level Nested Tree Sidebar Navigation Layout
- 25Multi-Tab Sidebar UI Component with Dynamic Panel Switching
- 26Onboarding Wizard Sidebar Layout with Step Progress Tracking
- 27Pure CSS Resizable Sidebar Layout Using Resize Property
- 28Three-Pane Productivity Workspace Shell Layout
- 29Next-Gen Adaptive Sidebar Layout Using CSS Container Queries
- 30Frosted Glass Floating Sidebar Layout with Backdrop Blur
CSS Fixed Sidebar Layout with Independent Scrollable Main Content
The foundational app-shell every dashboard starts from — a locked left sidebar and a main pane that scrolls on its own — built the modern way: not position:fixed with magic margins, but a height-constrained grid where each pane owns its own overflow. Scrollbars stay where they belong, nothing overlaps, and the pattern nests cleanly inside any container.
Mosaic by Cruip: a complete Tailwind admin dashboard template in HTML, React, Next.js and Vue · $69
Cruip · Mosaic by Cruip · Affiliate link
The code
<section class="sbl-08">
<aside class="sbl-08__rail" aria-label="Workspace">
<div class="sbl-08__brand"><span aria-hidden="true"></span>Ledgerly</div>
<nav class="sbl-08__nav">
<a href="#" aria-current="page">Overview</a><a href="#">Transactions</a><a href="#">Invoices</a><a href="#">Recurring</a><a href="#">Vendors</a><a href="#">Categories</a><a href="#">Receipts</a><a href="#">Tax reports</a><a href="#">Bank feeds</a><a href="#">Rules</a><a href="#">Integrations</a><a href="#">Team</a><a href="#">Settings</a>
</nav>
</aside>
<main class="sbl-08__main">
<h1>Overview</h1>
<p>Both panes scroll independently. The sidebar nav is intentionally long — scroll it, then scroll this pane; neither moves the other.</p>
<div class="sbl-08__stack"><div></div><div></div><div></div><div></div><div></div><div></div></div>
</main>
</section><section class="sbl-08">
<aside class="sbl-08__rail" aria-label="Workspace">
<div class="sbl-08__brand"><span aria-hidden="true"></span>Ledgerly</div>
<nav class="sbl-08__nav">
<a href="#" aria-current="page">Overview</a><a href="#">Transactions</a><a href="#">Invoices</a><a href="#">Recurring</a><a href="#">Vendors</a><a href="#">Categories</a><a href="#">Receipts</a><a href="#">Tax reports</a><a href="#">Bank feeds</a><a href="#">Rules</a><a href="#">Integrations</a><a href="#">Team</a><a href="#">Settings</a>
</nav>
</aside>
<main class="sbl-08__main">
<h1>Overview</h1>
<p>Both panes scroll independently. The sidebar nav is intentionally long — scroll it, then scroll this pane; neither moves the other.</p>
<div class="sbl-08__stack"><div></div><div></div><div></div><div></div><div></div><div></div></div>
</main>
</section>.sbl-08,
.sbl-08 *,
.sbl-08 *::before,
.sbl-08 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.sbl-08 {
--panel: oklch(0.17 0.015 235);
--ink: oklch(0.93 0.005 235);
--mut: oklch(0.63 0.012 235);
--line: oklch(0.28 0.015 235);
--accent: oklch(0.72 0.13 210);
display: grid;
grid-template-columns: 260px 1fr;
height: 100vh;
height: 100dvh;
font-family: system-ui,'Segoe UI',sans-serif;
background: oklch(0.13 0.012 235);
color: var(--ink);
}
.sbl-08__rail {
display: flex;
flex-direction: column;
background: var(--panel);
border-right: 1px solid var(--line);
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
scrollbar-color: var(--line) transparent;
padding: 20px 12px;
}
.sbl-08__brand {
display: flex;
align-items: center;
gap: 10px;
font: 700 15px/1 system-ui,sans-serif;
padding: 2px 10px 18px;
}
.sbl-08__brand span {
width: 24px;
height: 24px;
border-radius: 7px;
background: conic-gradient(from 45deg,var(--accent),oklch(0.6 0.15 260));
}
.sbl-08__nav {
display: flex;
flex-direction: column;
gap: 2px;
}
.sbl-08__nav a {
padding: 10px 14px;
border-radius: 9px;
font: 500 13.5px/1 system-ui,sans-serif;
color: var(--mut);
text-decoration: none;
transition: background-color .18s ease,color .18s ease;
}
.sbl-08__nav a:hover {
color: var(--ink);
background: color-mix(in oklab,var(--ink) 6%,transparent);
}
.sbl-08__nav a[aria-current="page"] {
color: var(--ink);
background: color-mix(in oklab,var(--accent) 17%,transparent);
box-shadow: inset 2px 0 0 var(--accent);
}
.sbl-08__nav a:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.sbl-08__main {
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-gutter: stable;
padding: 32px;
}
.sbl-08__main h1 {
font: 600 22px/1.2 system-ui,sans-serif;
margin-bottom: 10px;
}
.sbl-08__main p {
color: var(--mut);
font-size: 14px;
line-height: 1.6;
max-width: 52ch;
margin-bottom: 24px;
text-wrap: pretty;
}
.sbl-08__stack {
display: grid;
gap: 16px;
}
.sbl-08__stack div {
height: 130px;
border-radius: 14px;
background: var(--panel);
border: 1px solid var(--line);
}
@media (prefers-reduced-motion: reduce) {
.sbl-08__nav a {
transition: none;
}
}.sbl-08,
.sbl-08 *,
.sbl-08 *::before,
.sbl-08 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.sbl-08 {
--panel: oklch(0.17 0.015 235);
--ink: oklch(0.93 0.005 235);
--mut: oklch(0.63 0.012 235);
--line: oklch(0.28 0.015 235);
--accent: oklch(0.72 0.13 210);
display: grid;
grid-template-columns: 260px 1fr;
height: 100vh;
height: 100dvh;
font-family: system-ui,'Segoe UI',sans-serif;
background: oklch(0.13 0.012 235);
color: var(--ink);
}
.sbl-08__rail {
display: flex;
flex-direction: column;
background: var(--panel);
border-right: 1px solid var(--line);
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
scrollbar-color: var(--line) transparent;
padding: 20px 12px;
}
.sbl-08__brand {
display: flex;
align-items: center;
gap: 10px;
font: 700 15px/1 system-ui,sans-serif;
padding: 2px 10px 18px;
}
.sbl-08__brand span {
width: 24px;
height: 24px;
border-radius: 7px;
background: conic-gradient(from 45deg,var(--accent),oklch(0.6 0.15 260));
}
.sbl-08__nav {
display: flex;
flex-direction: column;
gap: 2px;
}
.sbl-08__nav a {
padding: 10px 14px;
border-radius: 9px;
font: 500 13.5px/1 system-ui,sans-serif;
color: var(--mut);
text-decoration: none;
transition: background-color .18s ease,color .18s ease;
}
.sbl-08__nav a:hover {
color: var(--ink);
background: color-mix(in oklab,var(--ink) 6%,transparent);
}
.sbl-08__nav a[aria-current="page"] {
color: var(--ink);
background: color-mix(in oklab,var(--accent) 17%,transparent);
box-shadow: inset 2px 0 0 var(--accent);
}
.sbl-08__nav a:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.sbl-08__main {
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-gutter: stable;
padding: 32px;
}
.sbl-08__main h1 {
font: 600 22px/1.2 system-ui,sans-serif;
margin-bottom: 10px;
}
.sbl-08__main p {
color: var(--mut);
font-size: 14px;
line-height: 1.6;
max-width: 52ch;
margin-bottom: 24px;
text-wrap: pretty;
}
.sbl-08__stack {
display: grid;
gap: 16px;
}
.sbl-08__stack div {
height: 130px;
border-radius: 14px;
background: var(--panel);
border: 1px solid var(--line);
}
@media (prefers-reduced-motion: reduce) {
.sbl-08__nav a {
transition: none;
}
}/* No JavaScript — a height-constrained grid shell; each pane owns overflow-y:auto + overscroll-behavior:contain, so scrolling never couples. */
/* No JavaScript — a height-constrained grid shell; each pane owns overflow-y:auto + overscroll-behavior:contain, so scrolling never couples. */Here's a working CSS Sidebar Layout from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Fixed Sidebar Layout with Independent Scrollable Main Content
Source: https://codefronts.com/layouts/css-sidebar-layouts/fixed-sidebar/
The foundational app-shell every dashboard starts from — a locked left sidebar and a main pane that scrolls on its own — built the modern way: not position:fixed with magic margins, but a height-constrained grid where each pane owns its own overflow. Scrollbars stay where they belong, nothing overlaps, and the pattern nests cleanly inside any container.
## HTML
```html
<section class="sbl-08">
<aside class="sbl-08__rail" aria-label="Workspace">
<div class="sbl-08__brand"><span aria-hidden="true"></span>Ledgerly</div>
<nav class="sbl-08__nav">
<a href="#" aria-current="page">Overview</a><a href="#">Transactions</a><a href="#">Invoices</a><a href="#">Recurring</a><a href="#">Vendors</a><a href="#">Categories</a><a href="#">Receipts</a><a href="#">Tax reports</a><a href="#">Bank feeds</a><a href="#">Rules</a><a href="#">Integrations</a><a href="#">Team</a><a href="#">Settings</a>
</nav>
</aside>
<main class="sbl-08__main">
<h1>Overview</h1>
<p>Both panes scroll independently. The sidebar nav is intentionally long — scroll it, then scroll this pane; neither moves the other.</p>
<div class="sbl-08__stack"><div></div><div></div><div></div><div></div><div></div><div></div></div>
</main>
</section>
```
## CSS
```css
.sbl-08,
.sbl-08 *,
.sbl-08 *::before,
.sbl-08 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.sbl-08 {
--panel: oklch(0.17 0.015 235);
--ink: oklch(0.93 0.005 235);
--mut: oklch(0.63 0.012 235);
--line: oklch(0.28 0.015 235);
--accent: oklch(0.72 0.13 210);
display: grid;
grid-template-columns: 260px 1fr;
height: 100vh;
height: 100dvh;
font-family: system-ui,'Segoe UI',sans-serif;
background: oklch(0.13 0.012 235);
color: var(--ink);
}
.sbl-08__rail {
display: flex;
flex-direction: column;
background: var(--panel);
border-right: 1px solid var(--line);
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
scrollbar-color: var(--line) transparent;
padding: 20px 12px;
}
.sbl-08__brand {
display: flex;
align-items: center;
gap: 10px;
font: 700 15px/1 system-ui,sans-serif;
padding: 2px 10px 18px;
}
.sbl-08__brand span {
width: 24px;
height: 24px;
border-radius: 7px;
background: conic-gradient(from 45deg,var(--accent),oklch(0.6 0.15 260));
}
.sbl-08__nav {
display: flex;
flex-direction: column;
gap: 2px;
}
.sbl-08__nav a {
padding: 10px 14px;
border-radius: 9px;
font: 500 13.5px/1 system-ui,sans-serif;
color: var(--mut);
text-decoration: none;
transition: background-color .18s ease,color .18s ease;
}
.sbl-08__nav a:hover {
color: var(--ink);
background: color-mix(in oklab,var(--ink) 6%,transparent);
}
.sbl-08__nav a[aria-current="page"] {
color: var(--ink);
background: color-mix(in oklab,var(--accent) 17%,transparent);
box-shadow: inset 2px 0 0 var(--accent);
}
.sbl-08__nav a:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.sbl-08__main {
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-gutter: stable;
padding: 32px;
}
.sbl-08__main h1 {
font: 600 22px/1.2 system-ui,sans-serif;
margin-bottom: 10px;
}
.sbl-08__main p {
color: var(--mut);
font-size: 14px;
line-height: 1.6;
max-width: 52ch;
margin-bottom: 24px;
text-wrap: pretty;
}
.sbl-08__stack {
display: grid;
gap: 16px;
}
.sbl-08__stack div {
height: 130px;
border-radius: 14px;
background: var(--panel);
border: 1px solid var(--line);
}
@media (prefers-reduced-motion: reduce) {
.sbl-08__nav a {
transition: none;
}
}
```
## JavaScript
```js
/* No JavaScript — a height-constrained grid shell; each pane owns overflow-y:auto + overscroll-behavior:contain, so scrolling never couples. */
```Here's a working CSS Sidebar Layout from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Fixed Sidebar Layout with Independent Scrollable Main Content
Source: https://codefronts.com/layouts/css-sidebar-layouts/fixed-sidebar/
The foundational app-shell every dashboard starts from — a locked left sidebar and a main pane that scrolls on its own — built the modern way: not position:fixed with magic margins, but a height-constrained grid where each pane owns its own overflow. Scrollbars stay where they belong, nothing overlaps, and the pattern nests cleanly inside any container.
## HTML
```html
<section class="sbl-08">
<aside class="sbl-08__rail" aria-label="Workspace">
<div class="sbl-08__brand"><span aria-hidden="true"></span>Ledgerly</div>
<nav class="sbl-08__nav">
<a href="#" aria-current="page">Overview</a><a href="#">Transactions</a><a href="#">Invoices</a><a href="#">Recurring</a><a href="#">Vendors</a><a href="#">Categories</a><a href="#">Receipts</a><a href="#">Tax reports</a><a href="#">Bank feeds</a><a href="#">Rules</a><a href="#">Integrations</a><a href="#">Team</a><a href="#">Settings</a>
</nav>
</aside>
<main class="sbl-08__main">
<h1>Overview</h1>
<p>Both panes scroll independently. The sidebar nav is intentionally long — scroll it, then scroll this pane; neither moves the other.</p>
<div class="sbl-08__stack"><div></div><div></div><div></div><div></div><div></div><div></div></div>
</main>
</section>
```
## CSS
```css
.sbl-08,
.sbl-08 *,
.sbl-08 *::before,
.sbl-08 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.sbl-08 {
--panel: oklch(0.17 0.015 235);
--ink: oklch(0.93 0.005 235);
--mut: oklch(0.63 0.012 235);
--line: oklch(0.28 0.015 235);
--accent: oklch(0.72 0.13 210);
display: grid;
grid-template-columns: 260px 1fr;
height: 100vh;
height: 100dvh;
font-family: system-ui,'Segoe UI',sans-serif;
background: oklch(0.13 0.012 235);
color: var(--ink);
}
.sbl-08__rail {
display: flex;
flex-direction: column;
background: var(--panel);
border-right: 1px solid var(--line);
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
scrollbar-color: var(--line) transparent;
padding: 20px 12px;
}
.sbl-08__brand {
display: flex;
align-items: center;
gap: 10px;
font: 700 15px/1 system-ui,sans-serif;
padding: 2px 10px 18px;
}
.sbl-08__brand span {
width: 24px;
height: 24px;
border-radius: 7px;
background: conic-gradient(from 45deg,var(--accent),oklch(0.6 0.15 260));
}
.sbl-08__nav {
display: flex;
flex-direction: column;
gap: 2px;
}
.sbl-08__nav a {
padding: 10px 14px;
border-radius: 9px;
font: 500 13.5px/1 system-ui,sans-serif;
color: var(--mut);
text-decoration: none;
transition: background-color .18s ease,color .18s ease;
}
.sbl-08__nav a:hover {
color: var(--ink);
background: color-mix(in oklab,var(--ink) 6%,transparent);
}
.sbl-08__nav a[aria-current="page"] {
color: var(--ink);
background: color-mix(in oklab,var(--accent) 17%,transparent);
box-shadow: inset 2px 0 0 var(--accent);
}
.sbl-08__nav a:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.sbl-08__main {
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-gutter: stable;
padding: 32px;
}
.sbl-08__main h1 {
font: 600 22px/1.2 system-ui,sans-serif;
margin-bottom: 10px;
}
.sbl-08__main p {
color: var(--mut);
font-size: 14px;
line-height: 1.6;
max-width: 52ch;
margin-bottom: 24px;
text-wrap: pretty;
}
.sbl-08__stack {
display: grid;
gap: 16px;
}
.sbl-08__stack div {
height: 130px;
border-radius: 14px;
background: var(--panel);
border: 1px solid var(--line);
}
@media (prefers-reduced-motion: reduce) {
.sbl-08__nav a {
transition: none;
}
}
```
## JavaScript
```js
/* No JavaScript — a height-constrained grid shell; each pane owns overflow-y:auto + overscroll-behavior:contain, so scrolling never couples. */
```How this works
The classic recipe (position:fixed sidebar + margin-left:260px content) has sharp edges: fixed elements escape their container, break inside transformed ancestors, and need the margin kept in sync by hand. The grid version removes all of it: display:grid; grid-template-columns:260px 1fr; height:100dvh on the shell, then overflow-y:auto on each pane. The height constraint is what makes it work — panes can't grow past the viewport, so they scroll internally. The sidebar is effectively 'fixed' because the shell itself never scrolls.
Both scroll areas get the finishing details that read as native quality: overscroll-behavior:contain so a fast-scrolling sidebar doesn't chain-scroll the content behind it, scrollbar-width:thin + scrollbar-color for a rail-matched scrollbar (the standards-based replacement for ::-webkit-scrollbar), and scrollbar-gutter:stable on the main pane so content doesn't shift 15px when a scrollbar appears. The long nav here scrolls to prove the sidebar's independence.
Make it yours
- Width: 260px fits icon+label nav; use
clamp(220px, 18vw, 300px)for a fluid rail on ultrawide monitors. - The dvh unit (not vh) is deliberate — it tracks mobile browser chrome; keep the plain vh line before it as the fallback.
- Add a fixed header row by extending to
grid-template-rows:56px 1frwith the sidebar spanning both rows. - This shell is the base layer: demos 02, 09, 17 and 21 all assume exactly this structure underneath.
Gotchas — read before shipping
- Every ancestor between body and the shell must not constrain height, or 100dvh overflows — set
height:100%up the chain or mount the shell at body level. - overflow on the PANES, never the shell — shell-level scrolling recreates the coupled-scroll problem the grid exists to solve.
- scrollbar-color styles both rails; test contrast in light mode — a too-subtle thumb fails visible-affordance heuristics for long content.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 121+ | 18.2+ | 97+ | 121+ |
Versions gate scrollbar-color/width only — cosmetic. The grid shell itself works in every engine since 2017.