30 CSS Sidebar Layouts
29 / 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

Next-Gen Adaptive Sidebar Layout Using CSS Container Queries

A sidebar that responds to ITS OWN width, not the viewport: drag the demo's resize handle and watch the nav morph through three densities — full labels+meta, labels only, icon rail — driven entirely by @container rules. Drop this component into any column of any app and it self-adapts; media queries could never know.

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-29">
  <div class="sbl-29__frame">
    <aside class="sbl-29__rail" aria-label="Library">
      <div class="sbl-29__brand"><span class="sbl-29__mark" aria-hidden="true"></span><span class="sbl-29__name">Shelfspace</span></div>
      <nav class="sbl-29__nav">
        <a href="#" aria-current="page"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20V2H6.5A2.5 2.5 0 0 0 4 4.5zM4 19.5A2.5 2.5 0 0 0 6.5 22H20v-5"/></svg><span class="sbl-29__lbl">Reading now</span><small class="sbl-29__meta">3</small></a>
        <a href="#"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 2h12a2 2 0 0 1 2 2v18l-8-4-8 4V4a2 2 0 0 1 2-2z"/></svg><span class="sbl-29__lbl">Saved</span><small class="sbl-29__meta">47</small></a>
        <a href="#"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></svg><span class="sbl-29__lbl">History</span><small class="sbl-29__meta">210</small></a>
        <a href="#"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3m0 14v3M2 12h3m14 0h3M4.9 4.9l2.1 2.1m10 10 2.1 2.1m0-14.2-2.1 2.1m-10 10-2.1 2.1"/></svg><span class="sbl-29__lbl">Settings</span></a>
      </nav>
    </aside>
    <span class="sbl-29__grip" aria-hidden="true"><i></i><i></i><i></i></span>
  </div>
  <main class="sbl-29__main"><h1>Reading now</h1><p>Drag the dotted edge. Full → labels-only → icon rail: three densities from @container rules — the sidebar reads its OWN width, never the viewport's.</p></main>
</section>
.sbl-29,
.sbl-29 *,
.sbl-29 *::before,
.sbl-29 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.sbl-29 {
  --panel: oklch(0.17 0.016 155);
  --ink: oklch(0.94 0.005 155);
  --mut: oklch(0.64 0.013 155);
  --line: oklch(0.28 0.017 155);
  --accent: oklch(0.78 0.15 160);
  display: flex;
  height: 100vh;
  height: 100dvh;
  font-family: system-ui,'Segoe UI',sans-serif;
  background: oklch(0.13 0.012 155);
  color: var(--ink);
}

.sbl-29__frame {
  position: relative;
  flex: none;
  resize: horizontal;
  overflow: auto;
  width: 264px;
  min-width: 76px;
  max-width: 340px;
  container: sbl29/inline-size;
  background: var(--panel);
  border-right: 1px solid var(--line);
}

.sbl-29__rail {
  padding: 16px 10px;
  min-height: 100%;
}

.sbl-29__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 10px 16px;
  overflow: hidden;
}

.sbl-29__mark {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 9px;
  background: conic-gradient(from 250deg,var(--accent),oklch(0.6 0.14 220));
}

.sbl-29__name {
  font: 700 clamp(13px,6cqi,16px)/1 system-ui,sans-serif;
  white-space: nowrap;
}

.sbl-29__nav {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.sbl-29__nav a {
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 44px;
  padding: 0 12px;
  border-radius: 11px;
  font: 500 14px/1 system-ui,sans-serif;
  color: var(--mut);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color .18s ease,color .18s ease;
}

.sbl-29__nav svg {
  flex: none;
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

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

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

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

.sbl-29__meta {
  margin-left: auto;
  font: 600 11px/1 system-ui,sans-serif;
  color: var(--mut);
  background: color-mix(in oklab,var(--ink) 8%,transparent);
  border-radius: 999px;
  padding: 3px 8px;
}

@container sbl29 (max-width: 220px) {
  .sbl-29__meta {
    display: none;
  }
}

@container sbl29 (max-width: 120px) {
  .sbl-29__lbl,
    .sbl-29__name {
    display: none;
  }

  .sbl-29__nav a {
    justify-content: center;
    padding: 0;
    width: 44px;
    margin-inline: auto;
  }

  .sbl-29__brand {
    justify-content: center;
    padding-inline: 0;
  }
}

.sbl-29__grip {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 14px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: center;
  justify-content: center;
  cursor: col-resize;
  opacity: .5;
}

.sbl-29__grip:hover {
  opacity: 1;
}

.sbl-29__grip i {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--mut);
}

.sbl-29 > .sbl-29__frame + .sbl-29__main,
.sbl-29__main {
  flex: 1;
  min-width: 0;
  padding: 32px;
  overflow-y: auto;
}

.sbl-29__main h1 {
  font: 600 22px/1.2 system-ui,sans-serif;
  margin-bottom: 10px;
}

.sbl-29__main p {
  color: var(--mut);
  font-size: 14px;
  line-height: 1.65;
  max-width: 50ch;
  text-wrap: pretty;
}

@media (prefers-reduced-motion: reduce) {
  .sbl-29__nav a {
    transition: none;
  }
}
/* No JavaScript — container:sbl29/inline-size makes the rail's own width queryable; @container rules morph it through three densities as you drag. */
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: Next-Gen Adaptive Sidebar Layout Using CSS Container Queries
Source: https://codefronts.com/layouts/css-sidebar-layouts/adaptive-container-query/

A sidebar that responds to ITS OWN width, not the viewport: drag the demo's resize handle and watch the nav morph through three densities — full labels+meta, labels only, icon rail — driven entirely by @container rules. Drop this component into any column of any app and it self-adapts; media queries could never know.
## HTML
```html
<section class="sbl-29">
  <div class="sbl-29__frame">
    <aside class="sbl-29__rail" aria-label="Library">
      <div class="sbl-29__brand"><span class="sbl-29__mark" aria-hidden="true"></span><span class="sbl-29__name">Shelfspace</span></div>
      <nav class="sbl-29__nav">
        <a href="#" aria-current="page"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20V2H6.5A2.5 2.5 0 0 0 4 4.5zM4 19.5A2.5 2.5 0 0 0 6.5 22H20v-5"/></svg><span class="sbl-29__lbl">Reading now</span><small class="sbl-29__meta">3</small></a>
        <a href="#"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 2h12a2 2 0 0 1 2 2v18l-8-4-8 4V4a2 2 0 0 1 2-2z"/></svg><span class="sbl-29__lbl">Saved</span><small class="sbl-29__meta">47</small></a>
        <a href="#"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></svg><span class="sbl-29__lbl">History</span><small class="sbl-29__meta">210</small></a>
        <a href="#"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3m0 14v3M2 12h3m14 0h3M4.9 4.9l2.1 2.1m10 10 2.1 2.1m0-14.2-2.1 2.1m-10 10-2.1 2.1"/></svg><span class="sbl-29__lbl">Settings</span></a>
      </nav>
    </aside>
    <span class="sbl-29__grip" aria-hidden="true"><i></i><i></i><i></i></span>
  </div>
  <main class="sbl-29__main"><h1>Reading now</h1><p>Drag the dotted edge. Full → labels-only → icon rail: three densities from @container rules — the sidebar reads its OWN width, never the viewport's.</p></main>
</section>
```
## CSS
```css
.sbl-29,
.sbl-29 *,
.sbl-29 *::before,
.sbl-29 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.sbl-29 {
  --panel: oklch(0.17 0.016 155);
  --ink: oklch(0.94 0.005 155);
  --mut: oklch(0.64 0.013 155);
  --line: oklch(0.28 0.017 155);
  --accent: oklch(0.78 0.15 160);
  display: flex;
  height: 100vh;
  height: 100dvh;
  font-family: system-ui,'Segoe UI',sans-serif;
  background: oklch(0.13 0.012 155);
  color: var(--ink);
}

.sbl-29__frame {
  position: relative;
  flex: none;
  resize: horizontal;
  overflow: auto;
  width: 264px;
  min-width: 76px;
  max-width: 340px;
  container: sbl29/inline-size;
  background: var(--panel);
  border-right: 1px solid var(--line);
}

.sbl-29__rail {
  padding: 16px 10px;
  min-height: 100%;
}

.sbl-29__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 10px 16px;
  overflow: hidden;
}

.sbl-29__mark {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 9px;
  background: conic-gradient(from 250deg,var(--accent),oklch(0.6 0.14 220));
}

.sbl-29__name {
  font: 700 clamp(13px,6cqi,16px)/1 system-ui,sans-serif;
  white-space: nowrap;
}

.sbl-29__nav {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.sbl-29__nav a {
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 44px;
  padding: 0 12px;
  border-radius: 11px;
  font: 500 14px/1 system-ui,sans-serif;
  color: var(--mut);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color .18s ease,color .18s ease;
}

.sbl-29__nav svg {
  flex: none;
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

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

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

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

.sbl-29__meta {
  margin-left: auto;
  font: 600 11px/1 system-ui,sans-serif;
  color: var(--mut);
  background: color-mix(in oklab,var(--ink) 8%,transparent);
  border-radius: 999px;
  padding: 3px 8px;
}

@container sbl29 (max-width: 220px) {
  .sbl-29__meta {
    display: none;
  }
}

@container sbl29 (max-width: 120px) {
  .sbl-29__lbl,
    .sbl-29__name {
    display: none;
  }

  .sbl-29__nav a {
    justify-content: center;
    padding: 0;
    width: 44px;
    margin-inline: auto;
  }

  .sbl-29__brand {
    justify-content: center;
    padding-inline: 0;
  }
}

.sbl-29__grip {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 14px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: center;
  justify-content: center;
  cursor: col-resize;
  opacity: .5;
}

.sbl-29__grip:hover {
  opacity: 1;
}

.sbl-29__grip i {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--mut);
}

.sbl-29 > .sbl-29__frame + .sbl-29__main,
.sbl-29__main {
  flex: 1;
  min-width: 0;
  padding: 32px;
  overflow-y: auto;
}

.sbl-29__main h1 {
  font: 600 22px/1.2 system-ui,sans-serif;
  margin-bottom: 10px;
}

.sbl-29__main p {
  color: var(--mut);
  font-size: 14px;
  line-height: 1.65;
  max-width: 50ch;
  text-wrap: pretty;
}

@media (prefers-reduced-motion: reduce) {
  .sbl-29__nav a {
    transition: none;
  }
}
```

## JavaScript
```js
/* No JavaScript — container:sbl29/inline-size makes the rail's own width queryable; @container rules morph it through three densities as you drag. */
```

How this works

The wrapper declares itself a container: container:sbl29/inline-size. That one property makes the sidebar's own inline width queryable by every descendant. Three @container sbl29 (max-width:…) blocks then restyle internals: under 220px the meta line (item counts) hides; under 120px labels hide, links become centered 44px icon squares, and the brand collapses to its mark. The component carries its own responsive brain — the page it lands in needs zero knowledge of these breakpoints.

The demo makes the point tangible by wrapping the sidebar in demo 27's resize:horizontal container, so YOU are the layout engine: drag and watch the container queries fire. This is the architectural unlock of container queries — the same sidebar file serves the full-width app shell, a narrow split-view column, and a cramped embedded widget, adapting in each without props, JS, or viewport assumptions. Container units (cqi) scale the brand type with the rail for free.

Make it yours

  • Density thresholds (220/120px) are the component's API — document them like props.
  • Add a fourth ultra-wide tier (@container (min-width:320px)) that reveals recent-items sublists.
  • cqi units scale anything with the container — try padding:calc(8px + 2cqi) for fluid density.
  • In production the resize wrapper disappears — your app's real columns (grid tracks, split panes) become the containers.

Gotchas — read before shipping

  • A container CANNOT size itself by its contents in the queried axis — inline-size containment makes width come from the layout, which is exactly why the wrapper (not the sidebar) carries the resize.
  • Name your containers (@container sbl29) — unnamed queries match the NEAREST ancestor container, and a stray parent container silently hijacks the rules.
  • Container queries style DESCENDANTS only; the container itself can't respond to its own query — style the inner aside, not the wrapper.

Browser support

ChromeSafariFirefoxEdge
114+17.5+121+114+

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

Size container queries are baseline since Feb 2023 — fully production-ready. cqi units ship in the same versions.

Techniques used in this demo

Search CodeFronts

Loading…