Содержание
  1. Какие бывают сайдбары и когда какой брать
  2. Разметка: почему сайдбар — это <aside>
  3. Сетка: как поставить сайдбар рядом с контентом на CSS Grid
  4. Липкий сайдбар: position: sticky и его условия
  5. Сайдбар не липнет: четыре причины и порядок проверки
  6. Мобильный сайдбар: выезжающая панель на <dialog>
  7. Как выбрать способ вёрстки сайдбара
  8. Сайдбар в WordPress: где он живёт
  9. Чек-лист: что проверить перед сдачей сайдбара
  10. Частые вопросы про сайдбар
  11. Что в итоге с вёрсткой сайдбара
ГайдыОбновлено · 08.2026

Верстка сайдбаров: эффективная навигация и оформление контента

28 августа 2023 · 15 минут чтения

Сайдбар — боковая колонка страницы рядом с основным контентом. В неё выносят навигацию по разделам, поиск, подборку статей, фильтры каталога, форму подписки. В вёрстке сайдбар — это блок <aside> во второй колонке сетки, который на десктопе стоит сбоку, на планшете сужается, а на телефоне уезжает за край экрана и открывается по кнопке.

Дальше — разбор именно вёрстки: разметка, сетка на CSS Grid, прилипание при прокрутке, мобильная панель и доступность. Ниже коротко то, что заберёте из статьи:

  • сетку «контент + сайдбар» собирают одной строкой grid-template-columns; проценты и float для этого больше не нужны;
  • прилипание даёт position: sticky — но только вместе с top и без предков с overflow: hidden;
  • на мобильных сайдбар превращают в выезжающую панель, и удобнее всего на нативном <dialog>;
  • <aside> — это ориентир complementary для скринридера, поэтому у навигации внутри должна быть подпись;
  • горизонтальной «боковой панели» не бывает: то, что лежит сверху или снизу, — это шапка и подвал.

Какие бывают сайдбары и когда какой брать

По способу поведения сайдбар бывает трёх видов, и вёрстка у них разная.

Статичный

Колонка едет вместе со страницей. Подходит блогу и статье, где в сайдбаре пара блоков: автор, оглавление, подписка. Самый дешёвый вариант — одна строка в описании сетки.

Прилипающий

Колонка прокручивается вместе с текстом, а дойдя до заданной границы, фиксируется. Нужен там, где боковой блок должен быть под рукой всё время чтения: оглавление лонгрида, фильтры каталога, корзина. Делается на position: sticky.

Выезжающий (off-canvas)

Панель лежит за краем экрана и выезжает по кнопке поверх контента. Стандартное решение для мобильных и для админок, где боковое меню длинное.

Отдельно про «горизонтальные сайдбары», которые кочуют по старым статьям: элемент во всю ширину сверху — это <header>, снизу — <footer>. Смысл слова «сайдбар» в том, что он сбоку. Про нижнюю часть страницы у нас есть отдельный разбор — вёрстка футера.

Разметка: почему сайдбар — это <aside>

Контейнер боковой колонки размечают тегом <aside>. По документации MDN этот элемент «представляет собой часть документа, чьё содержимое только косвенно связано с основным содержимым документа» и «чаще всего представлен в виде боковой панели, сносок или меток». Там же указано, что <aside> имеет ARIA-роль complementary — то есть скринридер объявляет его как отдельный ориентир и позволяет перепрыгнуть к нему одной командой.

Из этого следуют два практических правила. Первое: в <aside> не кладут основной текст страницы — только сопутствующее. Второе: если внутри сайдбара есть меню, его оборачивают в <nav> с подписью, иначе на странице окажется два безымянных ориентира «навигация» и пользователь скринридера не поймёт, в какой из них он попал.

<div class="layout">
  <main id="main">
    <h1>Заголовок статьи</h1>
  </main>

  <aside class="sidebar" aria-label="Дополнительные материалы">
    <nav aria-label="Разделы блога">
      <ul>
        <li><a href="/css/">CSS</a></li>
        <li><a href="/html/">HTML</a></li>
        <li><a href="/js/">JavaScript</a></li>
      </ul>
    </nav>
  </aside>
</div>

Порядок в разметке важнее визуального: <main> идёт первым, потому что так его читают скринридер и поисковый робот. Если дизайн требует сайдбар слева, колонки меняют местами средствами сетки — блок в разметке остаётся на своём месте — как именно, разобрано в статье про перестановку элементов в зависимости от размера экрана.

Коротко: сайдбар — это <aside> с подписью, меню внутри — <nav> с собственной подписью, порядок в HTML диктует смысл, а не картинка.

Сетка: как поставить сайдбар рядом с контентом на CSS Grid

Старый способ — float или два блока по 20% и 80% внутри display: flex. Он живёт до первого длинного слова в меню: колонка распирается, вёрстка едет. Современный вариант — Grid с фиксированной шириной боковой колонки и резиновой основной.

.layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  gap: 32px;
  max-width: 1200px;
  margin-inline: auto;
  padding-inline: 16px;
}

Что здесь важно. 280px — ширина сайдбара, она не пляшет от размера экрана и от длины ссылок. minmax(0, 1fr) для основной колонки снимает классическую проблему Grid: у элемента сетки минимальная ширина по умолчанию равна auto, то есть содержимому, и одна широкая таблица или блок кода растягивает колонку за пределы контейнера. У боковой колонки этой проблемы нет: её трек задан фиксированными 280px, а автоматический минимальный размер грид-элемента возникает только там, где в минимальной функции трека стоит auto. Ставить ей min-width: 0 незачем.

gap задаёт зазор между колонками без отступов на самих блоках — не нужно вычитать margin из ширины и держать в голове схлопывание отступов.

Сайдбар слева без правки HTML

Колонки меняются местами в описании сетки, разметка остаётся прежней. В CSS правится одна строка — список треков — и добавляется правило из двух свойств у сайдбара:

.layout {
  grid-template-columns: 280px minmax(0, 1fr);
}

.sidebar {
  grid-column: 1;
  grid-row: 1;
}

Одной перестановки треков здесь не хватает. <main> стоит в разметке первым и по правилам автоматического размещения занимает первую свободную ячейку — то есть узкий трек 280px. Сайдбар, которому задали только колонку, уходит во вторую строку под него, и широкий трек остаётся пустым. grid-row: 1 удерживает сайдбар в первой строке, и <main> достаётся вторая ячейка той же строки — колонка шириной 280px слева, контент справа.

Переключение на одну колонку

Точку переключения выбирают по макету, общего стандарта здесь нет: в примере ниже сайдбар уходит под контент на ширине меньше 1024px. Медиазапрос перестраивает сетку целиком:

@media (max-width: 1024px) {
  .layout {
    grid-template-columns: 1fr;
  }

  .sidebar {
    grid-row: auto;
  }
}

Правило для .sidebar нужно тем, кто выше поставил сайдбар слева: grid-row: 1 действует и в одноколоночной сетке, поэтому на узком экране сайдбар оказался бы над контентом. grid-row: auto возвращает ему обычный порядок — контент первым, сайдбар под ним.

Перед сеткой имеет смысл выровнять базовые стили браузера — про это отдельная статья о сбросе стилей через reset.css.

Коротко: сайдбар — фиксированная колонка, контент — minmax(0, 1fr); эта пара не ломается ни от длинных слов, ни от широких вставок.

Липкий сайдбар: position: sticky и его условия

Прилипание делается двумя строками — без JavaScript и без пересчёта координат на скролле.

.sidebar__inner {
  position: sticky;
  top: 24px;
  max-height: calc(100vh - 48px);
  overflow-y: auto;
}

Работает это так. В документации MDN по свойству position сказано: элемент «позиционируется в соответствии с нормальным потоком документа, а затем смещается относительно его ближайшего прокручивающего предка… на основе значений top, right, bottom и left», причём «смещение не влияет на положение любых других элементов». То есть место в потоке за элементом сохраняется, и соседняя колонка не прыгает. С position: fixed, на котором липкий сайдбар собирали раньше, элемент выпадал из потока, и высоту приходилось компенсировать вручную.

Второе условие оттуда же: «вы должны указать порог с по крайней мере одним из top, right, bottom или left для того, чтобы липкое позиционирование могло вести себя так, как ожидалось. В противном случае он будет неотличим от относительного позиционирования».

Поддержка на сегодня закрывает практически весь трафик: по данным caniuse — около 96% браузеров (95,65% полная поддержка плюс 0,35% частичная), Chrome и Edge с 91-й версии, Firefox с 59-й, Safari с 7.1. Отдельная ветка кода под старые браузеры не нужна: там, где sticky не понят, сайдбар просто останется статичным.

Зачем max-height и overflow-y

Если содержимое сайдбара выше экрана, прилипший блок обрежется снизу и нижние ссылки станут недоступны. Ограничение по высоте вьюпорта плюс собственная прокрутка внутри колонки лечат это. Обратите внимание: overflow-y: auto здесь стоит на самом липком элементе, и это безопасно — опасен overflow на его предках, о чём следующий раздел.

Коротко: липкий сайдбар — это position: sticky плюс обязательный top, плюс ограничение высоты для длинных меню.

Сайдбар не липнет: четыре причины и порядок проверки

Порядок проверки, когда position: sticky не срабатывает
Порядок проверки, когда position: sticky не срабатывает

Это самая частая поломка бокового блока, и почти всегда причина лежит в окружении блока. Проверять стоит по порядку — от дешёвого к дорогому.

1. Не задан порог

Есть position: sticky, нет top. По MDN такой элемент ведёт себя как position: relative, то есть никак. Лечится одной строкой.

2. У предка есть механизм прокрутки

Формулировка MDN: липкий элемент «прилипает к его ближайшему предшественнику, имеющему механизм прокрутки (созданный при overflow равном hidden, scroll, auto или overlay), даже если тот не является ближайшим фактически прокручивающим предком». Практический смысл: если на .layout, на body или на любом промежуточном контейнере висит overflow: hidden — а его часто ставят, чтобы победить горизонтальную прокрутку, — сайдбар будет липнуть к этому контейнеру, а не к экрану, и визуально не сдвинется вообще.

Проверяется в консоли браузера за один запрос: пройти вверх по цепочке родителей и посмотреть вычисленное значение overflow.

let el = document.querySelector('.sidebar__inner');
while (el = el.parentElement) {
  const o = getComputedStyle(el).overflow;
  if (o !== 'visible') console.log(el, o);
}

Всё, что попало в вывод, — кандидаты на удаление overflow. Горизонтальную прокрутку правильнее лечить точечно: overflow-x: clip вместо hidden не создаёт контейнер прокрутки для sticky.

3. Родительский элемент ровно по высоте сайдбара

Липкий блок ездит только внутри своего родителя. Если <aside> обнимает содержимое вплотную, ездить некуда — прилипание есть, но незаметно. Родителем должна быть колонка сетки во всю высоту контента.

4. Выравнивание сжало колонку

Элемент сетки по умолчанию растягивается на всю высоту строки (align-items: stretch), и это как раз то, что нужно. Ломает эффект align-self: start на самом <aside>: колонка сжимается по содержимому, и липкому блоку внутри снова некуда ехать. А height: 100% на самом <aside> высоту не схлопывает: процент разрешается против грид-области и даёт ровно ту же полную высоту строки, что и растяжка по умолчанию. Отсюда приём с внутренней обёрткой .sidebar__inner: липким делают её, а не саму колонку.

Коротко: порог, overflow у предков, высота родителя, выравнивание в сетке — четыре проверки закрывают почти все случаи «сайдбар не прилипает».

Мобильный сайдбар: выезжающая панель на <dialog>

Три состояния сайдбара при адаптиве: от двух колонок до выезжающей панели
Три состояния сайдбара при адаптиве: от двух колонок до выезжающей панели

На узком экране боковая колонка не помещается, и её прячут за кнопку. Раньше это собирали на скрытом чекбоксе или на самописном скрипте с классом .is-open. Обе схемы приходится дописывать вручную: закрытие по Esc, возврат фокуса на кнопку, блокировка контента за панелью. Нативный <dialog> отдаёт это браузеру.

<button type="button" aria-haspopup="dialog" id="menu-open">Меню</button>

<dialog class="drawer" id="drawer" aria-label="Разделы блога">
  <button type="button" autofocus id="menu-close">Закрыть</button>
  <nav>
    <ul>
      <li><a href="/css/">CSS</a></li>
      <li><a href="/html/">HTML</a></li>
    </ul>
  </nav>
</dialog>

<script>
  const drawer = document.getElementById('drawer');
  document.getElementById('menu-open')
    .addEventListener('click', () => drawer.showModal());
  document.getElementById('menu-close')
    .addEventListener('click', () => drawer.close());
</script>

Что здесь берётся из платформы, по документации MDN: showModal() показывает диалог «в верхнем слое вместе с псевдоэлементом ::backdrop», а «элементы внутри того же документа, кроме диалога и его потомков, становятся инертными (как если бы был задан атрибут inert)» — то есть табом за панель не выйти и кликом сквозь неё не попасть. Там же: «модальные диалоги можно закрыть нажатием клавиши Esc», и это поведение «предоставляется браузером». Атрибут autofocus MDN рекомендует ставить на кнопку закрытия, если внутри нет элемента с более срочным взаимодействием.

Остаётся оформление — прижать панель к краю и растянуть по высоте:

.drawer {
  box-sizing: border-box;
  margin: 0 auto 0 0;
  height: 100dvh;
  max-height: 100dvh;
  width: min(320px, 85vw);
  border: 0;
  padding: 24px;
}

.drawer::backdrop {
  background: rgb(0 0 0 / 0.5);
}

box-sizing: border-box в этом правиле обязателен. По умолчанию действует content-box, и тогда padding: 24px прибавляется к заданной высоте сверху и снизу: панель выходит на 48 пикселей выше экрана. С border-box отступы укладываются внутрь заданной высоты, и высота панели равна той, что написана в правиле.

Единица dvh здесь вместо vh: 100vh равен большому вьюпорту — высоте экрана в том состоянии, когда адресная строка и панели браузера убраны. Пока адресная строка показана, видимая область меньше этой величины, и панель на 100vh уходит нижним краем за экран вместе с последними пунктами меню. dvh берёт динамическую высоту вьюпорта — ту, что видна прямо сейчас.

Коротко: мобильный сайдбар — это <dialog> с showModal(); фокус, инертный фон и закрытие по Esc достаются бесплатно.

Как выбрать способ вёрстки сайдбара

Задача Приём Ключевые свойства Чего опасаться
Колонка едет со страницей CSS Grid, две колонки grid-template-columns: minmax(0, 1fr) 280px ширина в процентах вместо фиксированной
Блок фиксируется при прокрутке position: sticky sticky + top + max-height overflow у предков, низкий родитель
Панель поверх контента на мобильном <dialog> + showModal() ::backdrop, autofocus, 100dvh атрибут open вместо метода
Смена стороны сайдбара порядок колонок сетки grid-column и grid-row у сайдбара явная колонка без явной строки: <main> займёт узкий трек
Сайдбар скрыт на узком экране медиазапрос grid-template-columns: 1fr display: none для важной навигации

Сайдбар в WordPress: где он живёт

Если сайт на WordPress, вёрстка боковой колонки — только половина работы: содержимое туда попадает не из шаблона, а из системы виджетов. Область регистрируется в файле темы functions.php функцией register_sidebar(), выводится в шаблоне через dynamic_sidebar(), а наполняется в админке в разделе «Внешний вид → Виджеты». Тема может объявить несколько таких областей — например, отдельную для записей блога и отдельную для страниц каталога.

Отсюда практическое следствие: если в теме сайдбар не появляется, сначала проверяют, зарегистрирована ли область и вызывается ли dynamic_sidebar() в нужном шаблоне, и только потом лезут в CSS. Разбор состава боковой колонки со стороны содержания — в статье Sidebar: важная информационная область на вашем веб-сайте.

Коротко: в WordPress сайдбар — это зарегистрированная область виджетов, а не просто блок в шаблоне.

Чек-лист: что проверить перед сдачей сайдбара

  • Контейнер размечен как <aside> с атрибутом aria-label, меню внутри — <nav> со своей подписью.
  • <main> идёт в разметке раньше сайдбара; сторона колонки задана сеткой.
  • Основная колонка описана как minmax(0, 1fr), иначе широкая таблица или блок кода растянут её за пределы контейнера.
  • У липкого блока есть top, и ни у одного предка нет лишнего overflow.
  • Длинное меню ограничено по высоте и прокручивается внутри себя.
  • Сетка переключается на одну колонку на выбранном пороге (в примере — 1024px), важная навигация не спрятана насовсем.
  • Выезжающая панель открывается через showModal(), закрывается по Esc и по кнопке, фокус после закрытия возвращается на кнопку вызова.
  • Панель проверена клавиатурой: таб не уходит на контент за подложкой.
  • Высоты на мобильном заданы в dvh, а не в vh, а у панели с внутренними отступами стоит box-sizing: border-box.
  • Ссылки в сайдбаре дополняют главное меню, а не дублируют его.

Частые вопросы про сайдбар

Что такое сайдбар простыми словами?

Сайдбар — боковая колонка сайта рядом с основным содержимым. В ней размещают навигацию, поиск, подборки материалов, фильтры и формы подписки. В HTML это элемент <aside>, который по документации MDN имеет ARIA-роль complementary.

Каким тегом верстают сайдбар?

Тегом <aside>. Меню внутри оборачивают в <nav> с подписью через aria-label. Обычный <div> тоже отрисуется, но не даст скринридеру ориентира и лишит блок смысла в структуре документа.

Почему не работает position: sticky у сайдбара?

Четыре причины. Не задан порог top — по MDN тогда поведение неотличимо от position: relative. У одного из предков стоит overflow со значением hidden, scroll, auto или overlay — липкий элемент прилипает к нему. Родительский контейнер по высоте равен самому блоку, и ездить некуда. На <aside> задан align-self: start — колонка сжалась по содержимому вместо полной высоты строки.

Какая ширина у сайдбара считается нормальной?

Нормативного значения нет, числа ниже — ходовая практика вёрстки без стандарта под ней. На десктопе обычно берут фиксированные 240–320 пикселей: этого хватает на пункт меню в одну строку и на карточку с анонсом, а основная колонка остаётся резиновой. Проценты не берут, потому что на широком мониторе они дают избыточно широкую колонку, а на ноутбуке — слишком узкую.

Как сделать сайдбар на мобильном?

Переключить сетку на одну колонку медиазапросом и вынести навигацию в выезжающую панель на элементе <dialog>, открывая её методом showModal(). Браузер сам делает фон инертным, добавляет ::backdrop и закрывает панель по Esc.

Что в итоге с вёрсткой сайдбара

Сайдбар перестал быть отдельной задачей вёрстки и стал частью описания сетки. Две колонки задаются одной строкой grid-template-columns, прилипание — двумя строками sticky, мобильная панель — нативным <dialog> без библиотек. Основное время уходит на четыре проверки из раздела про «не липнет» и на клавиатурный проход по готовой панели. Материал обновлён в августе 2026 года: примеры приведены к CSS Grid, position: sticky и <dialog> вместо прежней схемы на процентных ширинах внутри flex.

Читайте также

3 материала