30 CSS Sidebar Layouts
18 / 30

All 30 in 30 CSS Sidebar Layouts

  1. 01Modern SaaS Dashboard Sidebar Menu with Native Dark Mode Switch
  2. 02Accessible Admin Panel Sidebar with CSS Tooltips and Icon Collapse
  3. 03Developer Documentation Sidebar with Scroll-Synced Nesting
  4. 04Mobile-First Responsive Sidebar to Bottom Navigation Switch Layout
  5. 05Data Analytics Sidebar Layout with CSS Subgrid Alignment
  6. 06Smooth Animated Collapsible Sidebar Menu with Icon-Only Mode
  7. 07CSS Position Sticky Sidebar Layout for E-Commerce and Blogs
  8. 08Pure CSS Collapsible Sidebar Drawer Menu without JavaScript
  9. 09CSS Fixed Sidebar Layout with Independent Scrollable Main Content
  10. 10Off-Canvas Navigation Drawer for Mobile & Desktop Web Apps
  11. 11Right-Aligned CSS Sidebar Layout for Secondary Tool Panels
  12. 12Two-Pane Webmail UI Layout with CSS Flexbox & Grid
  13. 13Dual Sidebar App Shell Layout with Left Nav and Right Context Panel
  14. 14Compact Mini Icon Rail Sidebar Navigation for SaaS Web Apps
  15. 15Responsive E-Commerce Product Filter Sidebar with Native Accordion Menu
  16. 16Modern Floating Glassmorphism Sidebar UI Component
  17. 17CSS Sidebar Menu with Sticky User Profile Footer
  18. 18Push Content Sidebar Navigation Layout with Smooth CSS Transitions
  19. 19Off-Canvas Sidebar Overlay Layout with Blur Backdrop
  20. 20Persistent Collapsible State Sidebar with CSS Variables
  21. 21App Sidebar Navigation with Integrated Sticky Search Bar
  22. 22Section-Grouped Sidebar Navigation Menu with Header Labels
  23. 23CSS Target Active Indicator Sidebar Menu without JavaScript
  24. 24Multi-Level Nested Tree Sidebar Navigation Layout
  25. 25Multi-Tab Sidebar UI Component with Dynamic Panel Switching
  26. 26Onboarding Wizard Sidebar Layout with Step Progress Tracking
  27. 27Pure CSS Resizable Sidebar Layout Using Resize Property
  28. 28Three-Pane Productivity Workspace Shell Layout
  29. 29Next-Gen Adaptive Sidebar Layout Using CSS Container Queries
  30. 30Frosted Glass Floating Sidebar Layout with Backdrop Blur
Pure CSSMIT licensed

Push Content Sidebar Navigation Layout with Smooth CSS Transitions

The drawer that pushes instead of covering: when it opens, the entire canvas slides right by exactly the drawer's width, staying fully visible — the interaction pattern of Material's 'standard drawer' — with both elements sharing one width variable and one transition curve so they can never drift out of sync.

Live Demo
Plain CSSTailwind v4
Try it

Mosaic by Cruip: a complete Tailwind admin dashboard template in HTML, React, Next.js and Vue · $69

Cruip · Mosaic by Cruip · Affiliate link

View Mosaic dashboard

The code

<section class="sbl-18">
  <input type="checkbox" id="sbl18-p" class="sbl-18__state">
  <aside class="sbl-18__drawer" aria-label="Layers">
    <h2>Layers</h2>
    <nav><a href="#" aria-current="page">Base map</a><a href="#">Traffic density</a><a href="#">Transit lines</a><a href="#">Bike network</a><a href="#">3D buildings</a></nav>
  </aside>
  <div class="sbl-18__canvas">
    <header class="sbl-18__bar"><label for="sbl18-p" class="sbl-18__toggle"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg><span>Layers</span></label><strong>Metroview</strong></header>
    <main class="sbl-18__map"><p>Open Layers — the whole canvas slides right by exactly 280px (one shared variable), never squeezing. Both moves are GPU transforms.</p></main>
  </div>
</section>
.sbl-18,
.sbl-18 *,
.sbl-18 *::before,
.sbl-18 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.sbl-18 {
  --w: 280px;
  --panel: oklch(0.18 0.015 220);
  --ink: oklch(0.94 0.005 220);
  --mut: oklch(0.64 0.012 220);
  --line: oklch(0.29 0.016 220);
  --accent: oklch(0.75 0.13 220);
  position: relative;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  font-family: system-ui,'Segoe UI',sans-serif;
  background: oklch(0.14 0.012 220);
  color: var(--ink);
}

.sbl-18__state {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.sbl-18__drawer {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--w);
  background: var(--panel);
  border-right: 1px solid var(--line);
  padding: 20px 14px;
  transform: translate3d(-100%,0,0);
  transition: transform .32s cubic-bezier(.4,0,.2,1);
  z-index: 2;
}

.sbl-18:has(#sbl18-p:checked) .sbl-18__drawer {
  transform: translate3d(0,0,0);
}

.sbl-18__drawer h2 {
  font: 600 12px/1 system-ui,sans-serif;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--mut);
  padding: 0 10px 14px;
}

.sbl-18__drawer nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.sbl-18__drawer a {
  padding: 11px 14px;
  border-radius: 10px;
  font: 500 14px/1 system-ui,sans-serif;
  color: var(--mut);
  text-decoration: none;
  transition: background-color .18s ease,color .18s ease;
}

.sbl-18__drawer a:hover {
  color: var(--ink);
  background: color-mix(in oklab,var(--ink) 6%,transparent);
}

.sbl-18__drawer a[aria-current="page"] {
  color: var(--accent);
  background: color-mix(in oklab,var(--accent) 14%,transparent);
}

.sbl-18__drawer a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.sbl-18__canvas {
  height: 100%;
  display: grid;
  grid-template-rows: auto 1fr;
  transform: translate3d(0,0,0);
  transition: transform .32s cubic-bezier(.4,0,.2,1);
}

.sbl-18:has(#sbl18-p:checked) .sbl-18__canvas {
  transform: translate3d(var(--w),0,0);
}

.sbl-18__bar {
  display: flex;
  align-items: center;
  gap: 14px;
  height: 54px;
  padding: 0 16px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  font: 600 15px/1 system-ui,sans-serif;
}

.sbl-18__toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 13px;
  margin-left: -4px;
  border-radius: 10px;
  border: 1px solid var(--line);
  font: 500 13px/1 system-ui,sans-serif;
  color: var(--ink);
  cursor: pointer;
  transition: background-color .2s ease;
}

.sbl-18__toggle:hover {
  background: color-mix(in oklab,var(--ink) 7%,transparent);
}

.sbl-18:has(#sbl18-p:focus-visible) .sbl-18__toggle {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.sbl-18__toggle svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
}

.sbl-18__map {
  display: grid;
  place-items: center;
  background: repeating-linear-gradient(0deg,transparent 0 39px,oklch(0.2 0.014 220) 39px 40px),repeating-linear-gradient(90deg,transparent 0 39px,oklch(0.2 0.014 220) 39px 40px),oklch(0.16 0.012 220);
}

.sbl-18__map p {
  color: var(--mut);
  font-size: 14px;
  line-height: 1.6;
  max-width: 40ch;
  text-align: center;
  padding: 0 24px;
  text-wrap: pretty;
}

@media (prefers-reduced-motion: reduce) {
  .sbl-18__drawer,
    .sbl-18__canvas,
    .sbl-18__toggle {
    transition: none;
  }
}
/* No JavaScript — drawer and canvas move as one welded unit: both transition translate3d over the same curve, displaced by one shared --w variable. */
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
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: Push Content Sidebar Navigation Layout with Smooth CSS Transitions
Source: https://codefronts.com/layouts/css-sidebar-layouts/push-content-sidebar/

The drawer that pushes instead of covering: when it opens, the entire canvas slides right by exactly the drawer's width, staying fully visible — the interaction pattern of Material's 'standard drawer' — with both elements sharing one width variable and one transition curve so they can never drift out of sync.
## HTML
```html
<section class="sbl-18">
  <input type="checkbox" id="sbl18-p" class="sbl-18__state">
  <aside class="sbl-18__drawer" aria-label="Layers">
    <h2>Layers</h2>
    <nav><a href="#" aria-current="page">Base map</a><a href="#">Traffic density</a><a href="#">Transit lines</a><a href="#">Bike network</a><a href="#">3D buildings</a></nav>
  </aside>
  <div class="sbl-18__canvas">
    <header class="sbl-18__bar"><label for="sbl18-p" class="sbl-18__toggle"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg><span>Layers</span></label><strong>Metroview</strong></header>
    <main class="sbl-18__map"><p>Open Layers — the whole canvas slides right by exactly 280px (one shared variable), never squeezing. Both moves are GPU transforms.</p></main>
  </div>
</section>
```
## CSS
```css
.sbl-18,
.sbl-18 *,
.sbl-18 *::before,
.sbl-18 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.sbl-18 {
  --w: 280px;
  --panel: oklch(0.18 0.015 220);
  --ink: oklch(0.94 0.005 220);
  --mut: oklch(0.64 0.012 220);
  --line: oklch(0.29 0.016 220);
  --accent: oklch(0.75 0.13 220);
  position: relative;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  font-family: system-ui,'Segoe UI',sans-serif;
  background: oklch(0.14 0.012 220);
  color: var(--ink);
}

.sbl-18__state {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.sbl-18__drawer {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--w);
  background: var(--panel);
  border-right: 1px solid var(--line);
  padding: 20px 14px;
  transform: translate3d(-100%,0,0);
  transition: transform .32s cubic-bezier(.4,0,.2,1);
  z-index: 2;
}

.sbl-18:has(#sbl18-p:checked) .sbl-18__drawer {
  transform: translate3d(0,0,0);
}

.sbl-18__drawer h2 {
  font: 600 12px/1 system-ui,sans-serif;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--mut);
  padding: 0 10px 14px;
}

.sbl-18__drawer nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.sbl-18__drawer a {
  padding: 11px 14px;
  border-radius: 10px;
  font: 500 14px/1 system-ui,sans-serif;
  color: var(--mut);
  text-decoration: none;
  transition: background-color .18s ease,color .18s ease;
}

.sbl-18__drawer a:hover {
  color: var(--ink);
  background: color-mix(in oklab,var(--ink) 6%,transparent);
}

.sbl-18__drawer a[aria-current="page"] {
  color: var(--accent);
  background: color-mix(in oklab,var(--accent) 14%,transparent);
}

.sbl-18__drawer a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.sbl-18__canvas {
  height: 100%;
  display: grid;
  grid-template-rows: auto 1fr;
  transform: translate3d(0,0,0);
  transition: transform .32s cubic-bezier(.4,0,.2,1);
}

.sbl-18:has(#sbl18-p:checked) .sbl-18__canvas {
  transform: translate3d(var(--w),0,0);
}

.sbl-18__bar {
  display: flex;
  align-items: center;
  gap: 14px;
  height: 54px;
  padding: 0 16px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  font: 600 15px/1 system-ui,sans-serif;
}

.sbl-18__toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 13px;
  margin-left: -4px;
  border-radius: 10px;
  border: 1px solid var(--line);
  font: 500 13px/1 system-ui,sans-serif;
  color: var(--ink);
  cursor: pointer;
  transition: background-color .2s ease;
}

.sbl-18__toggle:hover {
  background: color-mix(in oklab,var(--ink) 7%,transparent);
}

.sbl-18:has(#sbl18-p:focus-visible) .sbl-18__toggle {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.sbl-18__toggle svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
}

.sbl-18__map {
  display: grid;
  place-items: center;
  background: repeating-linear-gradient(0deg,transparent 0 39px,oklch(0.2 0.014 220) 39px 40px),repeating-linear-gradient(90deg,transparent 0 39px,oklch(0.2 0.014 220) 39px 40px),oklch(0.16 0.012 220);
}

.sbl-18__map p {
  color: var(--mut);
  font-size: 14px;
  line-height: 1.6;
  max-width: 40ch;
  text-align: center;
  padding: 0 24px;
  text-wrap: pretty;
}

@media (prefers-reduced-motion: reduce) {
  .sbl-18__drawer,
    .sbl-18__canvas,
    .sbl-18__toggle {
    transition: none;
  }
}
```

## JavaScript
```js
/* No JavaScript — drawer and canvas move as one welded unit: both transition translate3d over the same curve, displaced by one shared --w variable. */
```

How this works

The naive push transitions margin-left on the content — a layout property, re-flowing every frame, visibly janky on complex pages. The performant push moves BOTH elements with transform:translate3d(): the drawer sits absolutely at translate3d(-100%,0,0), the main pane at zero; opening moves drawer to 0 and main to translate3d(var(--w),0,0). Transforms don't reflow — the entire push is compositor-side, and because both movements are the same distance on the same 320ms curve, drawer edge and content edge travel as one welded unit.

The single source of truth is --w:280px, consumed by the drawer's width AND the canvas displacement — change one variable, the whole mechanism recalibrates. The pushed pane keeps its own width (it slides off-edge rather than squeezing), which is what distinguishes push from demo 02/09's shrink-collapse: push preserves the canvas layout exactly, making it right for editors and maps where mid-animation reflow would be disruptive.

Make it yours

  • Squeeze instead of slide: swap the transform displacement for a grid track (demo 09) when content should REFLOW into the reduced width.
  • Partial push: displace by calc(var(--w) / 2) while the drawer overlaps the rest — the hybrid feel of iPad split view.
  • The same variable can drive a matching topbar shift for full-shell coherence.
  • Add inertia with linear() easing: linear(0, 1.05 70%, 1) gives the push a physical settle.

Gotchas — read before shipping

  • Transformed ancestors capture position:fixed descendants — anything fixed inside the pushed main (modals, toasts) will travel with the push. Portal them outside or use top-layer popovers.
  • The pushed content's right edge goes off-viewport — acceptable for temporary drawers, but keep critical actions on the left half or use squeeze-collapse instead.
  • overflow-x:hidden on the shell is mandatory or the displaced canvas creates a horizontal scrollbar.

Browser support

ChromeSafariFirefoxEdge
114+17.5+121+114+

Floor set by :has(), oklch(), color-mix(), text-wrap as this demo is written. The core technique itself goes back further — Chrome 105+.

:has() gates the state wiring; the translate3d push itself works in every engine since 2013.

Techniques used in this demo

Search CodeFronts

Loading…