Sidebar layout

Макет «фиксированный сайдбар + растягивающийся контент» — основа для дашбордов, CMS и admin-панелей.

Задача

Нужна страница с левым навигационным сайдбаром фиксированной ширины и основной областью контента, занимающей оставшееся пространство. На мобильных сайдбар должен скрываться.

Решение

<div class="app">
  <aside class="sidebar" id="sidebar">
    <div class="sidebar__logo">MyApp</div>
    <nav class="sidebar__nav">
      <a class="sidebar__link active" href="#">Дашборд</a>
      <a class="sidebar__link" href="#">Пользователи</a>
      <a class="sidebar__link" href="#">Настройки</a>
    </nav>
  </aside>

  <div class="content-area">
    <header class="topbar">
      <button class="topbar__toggle" id="sidebarToggle" aria-label="Открыть меню">
        &#9776;
      </button>
      <h1 class="topbar__title">Дашборд</h1>
    </header>
    <main class="main">
      <p>Основной контент</p>
    </main>
  </div>
</div>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

.app {
  display: flex;
  min-height: 100vh;
}

/* Сайдбар */
.sidebar {
  width: 240px;
  flex-shrink: 0;
  background: #1e293b;
  color: #fff;
  display: flex;
  flex-direction: column;
  transition: transform 0.3s ease;
}

.sidebar__logo {
  padding: 20px 24px;
  font-size: 1.2rem;
  font-weight: 700;
  border-bottom: 1px solid #334155;
}

.sidebar__nav { display: flex; flex-direction: column; padding: 16px 0; }

.sidebar__link {
  padding: 10px 24px;
  color: #94a3b8;
  text-decoration: none;
  transition: background 0.15s, color 0.15s;
}

.sidebar__link:hover,
.sidebar__link.active { background: #334155; color: #fff; }

/* Контентная область */
.content-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0; /* важно для flex + overflow */
}

.topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 24px;
  height: 60px;
  background: #fff;
  border-bottom: 1px solid #e2e8f0;
}

.topbar__toggle { display: none; background: none; border: none; font-size: 1.4rem; cursor: pointer; }
.main { padding: 24px; flex: 1; }

/* Адаптив */
@media (max-width: 768px) {
  .sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 200;
    transform: translateX(-100%);
  }

  .sidebar.open() { transform: translateX(0); }

  .topbar__toggle { display: block; }
}
const toggle = document.getElementById('sidebarToggle');
const sidebar = document.getElementById('sidebar');

toggle.addEventListener('click', () => {
  sidebar.classList.toggle('open');
});

// Закрыть при клике на overlay
document.addEventListener('click', (e) => {
  if (!sidebar.contains(e.target) && !toggle.contains(e.target)) {
    sidebar.classList.remove('open');
  }
});

Ключевые моменты

  • flex: 1 на .content-area — занимает всё оставшееся место; flex-shrink: 0 на .sidebar — не сжимается.
  • min-width: 0 на flex-элементе с контентом — предотвращает выход длинного текста за пределы.
  • На мобильных сайдбар — position: fixed с transform для плавного слайда; JS только добавляет/убирает класс.
  • Закрытие по клику вне сайдбара — стандартное UX-поведение для мобильных.

Варианты

  • Сайдбар справа: поменяй порядок flex-элементов или используй flex-direction: row-reverse.
  • Сворачиваемый сайдбар (только иконки): анимируй width между 240px и 60px.

Связанные рецепты / темы