Сайдбар — боковая колонка страницы рядом с основным контентом. В неё выносят навигацию по разделам, поиск, подборку статей, фильтры каталога, форму подписки. В вёрстке сайдбар — это блок <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, плюс ограничение высоты для длинных меню.
Сайдбар не липнет: четыре причины и порядок проверки

Это самая частая поломка бокового блока, и почти всегда причина лежит в окружении блока. Проверять стоит по порядку — от дешёвого к дорогому.
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.
