• Чаще всего липкий элемент css не работает из-за отсутствия top, bottom или другого смещения.
  • Вторая типовая причина — overflow: hidden, auto или scroll у родителя.
  • Также мешают маленькая высота контейнера, растягивание в Grid/Flexbox и неверно выбранный контейнер прокрутки.
  • Проверяйте цепочку родителей, размеры блоков и отлаживайте sticky через DevTools.

position: sticky выглядит простым свойством, но на практике ломается чаще, чем кажется. Элемент должен «прилипнуть» при прокрутке, а вместо этого остаётся на месте, ведёт себя как relative или внезапно перестаёт работать только в одном шаблоне. Для SEO и UX это не мелочь: если у вас липкий фильтр, меню, CTA или навигация, ошибки в вёрстке ухудшают поведение страницы, мобильное восприятие и косвенно влияют на пользовательские сигналы.

В этой статье разберём, почему css position sticky не работает в реальных макетах, покажем типовые и неочевидные причины, сравним поведение внутри обычного потока, Grid и Flexbox. Отдельно пройдёмся по overflow, контейнерам прокрутки, размерам родителя и пошаговой отладке в браузере.

Материал особенно полезен SEO-специалисту, вебмастеру, frontend-разработчику и владельцу сайта, который проверяет шаблоны каталога, блога или лендинга. Если проблема вызвана не CSS, а JavaScript-плагином, кастомным скроллом на библиотеке или логикой фреймворка, эта инструкция даст направление, но не заменит разбор конкретного компонента.

Что такое position: sticky и как оно функционирует

position: sticky — это режим позиционирования, при котором элемент сначала ведёт себя как обычный участник потока, а затем фиксируется относительно ближайшего контейнера прокрутки, когда достигает заданной границы. Официальное поведение описано в MDN и CSS-спецификациях: sticky работает только при наличии порога смещения, например top: 0 или top: 24px MDN: position.

Главное отличие от relative в том, что sticky меняет поведение во время скролла. Отличие от fixed — липкое позиционирование не привязывается ко всему окну браузера навсегда, а ограничивается своим контейнером. Поэтому один и тот же блок может прилипать в колонке статьи, но не выходить за пределы сайдбара.

Как это понимать на практике:

  • relative — элемент просто остаётся в потоке.
  • fixed — элемент фиксируется относительно viewport.
  • sticky — элемент прилипает только при достижении порога и только в пределах своего контейнера.

Базовый рабочий пример выглядит так:

.sidebar {
  position: sticky;
  top: 16px;
}

Если этот код не срабатывает, причина почти всегда в окружении элемента, а не в самом свойстве.

Основные причины, из-за которых sticky не работает

Когда sticky не прилипает, проблему лучше искать не наугад, а по трём группам причин: нет порога смещения, sticky упирается в ограничения родителей, либо контейнер физически не даёт элементу пространства для прилипания. Именно эти сценарии вызывают большинство position sticky проблемы в продакшн-вёрстке.

Ниже — краткая диагностическая таблица. Она помогает быстро сопоставить симптом и вероятную причину, прежде чем открывать DevTools.

СимптомВозможная причинаЧто проверить / как исправить
Элемент вообще не прилипаетНе задан top, bottom, left или rightДобавьте top: 0 или другое смещение
Работает не на всех страницахУ родителя есть overflow: hidden или autoПроверьте всю цепочку родителей до контейнера прокрутки
Прилипает, но сразу «отлипает»Слишком маленькая высота родителяУвеличьте высоту контейнера или вынесите sticky выше по DOM
Не работает в колонке GridЭлемент растянут по высоте трекаПроверьте align-self, align-items и размеры треков
Не работает во FlexboxРастягивание или нестандартная ось прокруткиПроверьте направление flex и доступное пространство

Чаще всего sticky ломают такие факторы:

  • не задано смещение через top или аналог;
  • один из родителей получил overflow, создающий новый scroll-контекст;
  • высота родителя меньше, чем нужна для заметного прилипания;
  • элемент находится внутри Grid или Flexbox с растягиванием;
  • скролл происходит не в том контейнере, на который вы рассчитываете.

Есть и менее очевидные случаи. Например, sticky может «не работать», хотя технически работает правильно, но пользователь этого не видит. Так бывает, если:

  • смещение слишком маленькое, например top: 0, а сверху уже есть фиксированный хедер высотой 72 px;
  • липкий блок по высоте почти равен высоте родителя, поэтому диапазон прилипания минимален;
  • элемент находится в конце длинного контейнера и просто не успевает пройти путь до точки фиксации;
  • внутри шаблона есть кастомный скролл, а прокручивается не body, а вложенный контейнер;
  • на мобильной версии для того же блока переопределён position: static через media query.

Минимальный чек перед глубокой отладкой:

  1. Убедитесь, что у sticky-элемента есть position: sticky и порог, например top: 20px.
  2. Проверьте, какой именно контейнер реально прокручивается: окно браузера, main, .content или модальное окно.
  3. Посмотрите, нет ли у родителей overflow, height, max-height и ограничений по выравниванию.
  4. Сравните высоту sticky-блока и высоту его родителя.
  5. Отключите в DevTools подозрительные свойства по одному, а не все сразу.

Проблемы с позиционированием элементов могут влиять не только на визуальное восприятие, но и на SEO-показатели сайта. Используйте бесплатный аудит analito.ru, чтобы выявить технические ошибки и оптимизировать работу вашего сайта в целом. Проверьте SEO и технические параметры вашего сайта с помощью бесплатного аудита.

Как overflow у родительских элементов влияет на sticky

Самая частая причина, почему css sticky не работает overflow, — одно из родительских обёртываний создаёт собственный контейнер прокрутки или обрезает содержимое. Sticky ориентируется не на абстрактное «окно браузера», а на ближайший scrolling ancestor. Если выше по DOM есть overflow: hidden, auto, scroll или иногда overlay, логика прилипания меняется.

Это особенно часто встречается в шаблонах, где разработчик добавил overflow: hidden для обрезки теней, борьбы с горизонтальным скроллом или декоративных эффектов. Визуально страница выглядит нормально, но sticky уже привязан к другому контексту.

Почему это мешает:

  • overflow: hidden обрезает область и может лишить sticky ожидаемого поведения.
  • overflow: auto и scroll создают новый контейнер прокрутки.
  • Если этот контейнер почти не прокручивается, эффект прилипания незаметен.
  • Даже соседняя обёртка, добавленная CMS или конструктором, может стать причиной.

Пошаговая проверка overflow:

  1. Выделите sticky-элемент в DevTools.
  2. Поднимайтесь по дереву родителей и смотрите computed-значения overflow, overflow-x, overflow-y.
  3. Найдите первый элемент, у которого значение не равно visible.
  4. Проверьте, действительно ли именно он должен быть контейнером прокрутки.
  5. Временно отключите это свойство в DevTools и проверьте, начал ли sticky работать.

Типичный проблемный пример:

.page {
  overflow-x: hidden;
}

.layout {
  overflow: hidden;
}

.sidebar {
  position: sticky;
  top: 24px;
}

В такой схеме .layout часто ломает ожидаемое поведение. Если обёртка не должна быть scroll-контейнером, безопаснее убрать у неё overflow: hidden или перенести обрезку на более узкий декоративный блок.

Рабочий вариант после исправления:

.page {
  overflow-x: hidden;
}

.layout {
  overflow: visible;
}

.sidebar {
  position: sticky;
  top: 24px;
}

Если overflow нужен обязательно, например в модальном окне или панели с внутренним скроллом, sticky тоже может работать, но уже относительно этого контейнера. Тогда важно, чтобы прокрутка происходила именно внутри него:

.modal__body {
  max-height: 80vh;
  overflow-y: auto;
}

.modal__aside {
  position: sticky;
  top: 16px;
}

Здесь липкий блок будет прилипать не к окну браузера, а к области прокрутки .modal__body. Это нормальное поведение, но его часто принимают за баг, если ожидают фиксацию относительно viewport.

Где чаще всего прячется проблемный overflow:

  • у общего контейнера страницы: .wrapper, .layout, .page;
  • у колонки контента или сайдбара;
  • у блока, созданного визуальным редактором или page builder;
  • у секции с анимациями, слайдером, маской, скруглением или тенью;
  • у контейнера, которому задали overflow-x: hidden, а браузер вычислил связанное поведение по оси Y.

Практический совет: если вы не уверены, какой родитель ломает sticky, временно добавьте всем предкам рамки и подписи в DevTools, а затем по очереди отключайте overflow. На сложных страницах с 8–12 вложенными обёртками это быстрее, чем читать весь CSS-файл вручную.

Почему sticky не работает из-за размеров родителя и самого элемента

Даже при правильном top и отсутствии проблемного overflow липкое позиционирование может выглядеть сломанным из-за геометрии. Sticky нужен запас пространства: элемент должен успеть дойти до порога прилипания и при этом иметь область, в пределах которой он может оставаться зафиксированным.

Классический сценарий: сайдбар высотой 600 px помещён в родителя высотой 650 px. Формально sticky включён, но фактически диапазон его работы всего несколько десятков пикселей. Пользователь почти не замечает эффекта и делает вывод, что свойство не работает.

Проверяйте три размера:

  • высоту sticky-элемента;
  • высоту его непосредственного родителя;
  • высоту области, которая реально прокручивается.

Проблемный пример:

.sidebar-wrap {
  height: 500px;
}

.sidebar {
  position: sticky;
  top: 20px;
  height: 460px;
}

Здесь sticky почти не имеет пространства для работы. Если сверху и снизу есть ещё отступы, эффект будет минимальным.

Более реалистичное решение:

.sidebar-wrap {
  min-height: 1200px;
}

.sidebar {
  position: sticky;
  top: 20px;
}

Если увеличить высоту родителя нельзя, есть два рабочих пути:

  1. вынести sticky-элемент выше по DOM, чтобы его ограничивал более высокий контейнер;
  2. уменьшить высоту самого липкого блока, особенно на мобильных экранах.

Для длинных фильтров, меню и TOC полезно ограничивать высоту самого sticky-элемента и добавлять внутренний скролл:

.sidebar {
  position: sticky;
  top: 16px;
  max-height: calc(100vh - 32px);
  overflow-y: auto;
}

Такой паттерн особенно полезен в каталогах и блогах: блок прилипает, но его содержимое не вылезает за пределы экрана. Главное — не перепутать, где должен быть внутренний скролл. Обычно его задают самому липкому блоку, а не внешнему родителю.

Как быстро понять, что проблема именно в размерах:

  1. Откройте вкладку Layout или Box Model в DevTools.
  2. Сравните высоту sticky-элемента и его контейнера в пикселях.
  3. Временно уменьшите высоту sticky-блока, например отключите часть контента или задайте max-height.
  4. Если после этого прилипание стало заметным, причина найдена.

Sticky внутри Grid и Flexbox: частые ошибки и исправления

Отдельная группа проблем возникает, когда sticky находится не в обычном блочном потоке, а внутри CSS Grid или Flexbox. На таких макетах всё может быть синтаксически верно, но поведение ломается из-за растягивания элементов по высоте, особенностей осей и размеров треков.

В Grid частая причина — значение по умолчанию align-items: stretch. Колонка или сам sticky-элемент растягивается на всю высоту трека, и визуально прилипать уже некуда.

Проблемный пример в Grid:

.layout {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 32px;
}

.sidebar {
  position: sticky;
  top: 24px;
}

На первый взгляд код нормальный. Но если grid-элементы растянуты, sticky может вести себя нестабильно. Часто помогает явное выравнивание:

.layout {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 32px;
  align-items: start;
}

.sidebar {
  position: sticky;
  top: 24px;
  align-self: start;
}

Во Flexbox проблема похожая. Если родитель — flex-контейнер, а дочерние элементы растягиваются, sticky может не получить нормальную высоту для работы. Особенно это заметно в горизонтальных лэйаутах с сайдбаром.

Исправленный пример для Flexbox:

.layout {
  display: flex;
  align-items: flex-start;
  gap: 32px;
}

.content {
  flex: 1 1 auto;
}

.sidebar {
  flex: 0 0 320px;
  position: sticky;
  top: 24px;
  align-self: flex-start;
}

Что проверить в Grid и Flex в первую очередь:

  • align-items: stretch у родителя;
  • align-self у sticky-элемента;
  • нет ли у колонки фиксированной высоты, которая ограничивает прилипание;
  • совпадает ли ось прокрутки с тем направлением, где вы ждёте sticky;
  • не задан ли overflow самому grid/flex-контейнеру.

Отдельно проверьте адаптив. На десктопе sticky может работать в двухколоночной сетке, а на планшете ломаться после переключения на display: block или flex-direction: column. Часто проблема сидит в media query:

@media (max-width: 992px) {
  .sidebar {
    position: static;
  }
}

Или в другом варианте:

@media (max-width: 992px) {
  .layout {
    overflow: hidden;
  }
}

Поэтому проверяйте sticky не только в основном CSS, но и во всех брейкпоинтах.

Пошаговая отладка sticky в DevTools

Когда причина неочевидна, быстрее всего идти по короткому сценарию проверки. Он подходит для Chrome, Edge и Firefox.

  1. Проверьте computed-стили элемента. Убедитесь, что реально применились position: sticky и top. Иногда правило переопределено более специфичным селектором.
  2. Найдите scroll-контейнер. Прокрутите страницу и посмотрите, что именно двигается: body, main, модальное окно, колонка каталога.
  3. Пройдите по родителям. Ищите overflow, height, max-height, display: flex, display: grid.
  4. Проверьте размеры. Sticky-блок должен быть заметно ниже контейнера, иначе прилипание будет почти невидимым.
  5. Отключайте свойства по одному. Сначала overflow, потом выравнивание, потом ограничения высоты.
  6. Проверьте адаптивные стили. Переключитесь в режим устройства и повторите тест на нужной ширине экрана.

Удобный приём для диагностики — временно добавить заметные стили:

.sidebar {
  position: sticky;
  top: 20px;
  outline: 2px solid red;
  background: rgba(255, 0, 0, 0.08);
}

Так проще увидеть, действительно ли элемент меняет положение при прокрутке, или проблема только в том, что эффект визуально незаметен.

Если страница использует JavaScript-библиотеки для кастомного скролла, sticky может не работать ожидаемо даже при правильном CSS. Например, библиотеки, которые двигают контент через transform вместо нативного скролла, меняют контекст поведения. В таком случае нужно проверять документацию конкретного решения и искать нативную поддержку sticky или альтернативу на JS.

Короткий чек-лист: что делать, если css position sticky не работает

  • Добавьте top, bottom или другое смещение.
  • Проверьте всех родителей на overflow: hidden/auto/scroll.
  • Убедитесь, что прокручивается именно тот контейнер, относительно которого вы ждёте прилипание.
  • Сравните высоту sticky-элемента и высоту родителя.
  • В Grid/Flex отключите растягивание: проверьте align-items и align-self.
  • Посмотрите media query и стили мобильной версии.
  • Если используется кастомный скролл или JS-плагин, проверьте, не ломает ли он нативное поведение sticky.

В большинстве случаев ответ на вопрос, почему css position sticky не работает, находится в одном из трёх мест: нет порога смещения, родительский overflow создаёт другой контекст, либо контейнер не даёт элементу пространства для прилипания. Если последовательно проверить эти точки, проблема обычно находится за несколько минут даже в сложном шаблоне.

Частые вопросы

Почему элемент с position: sticky не прилипает, если не задан top?

Без порога смещения, например top: 0, элемент не знает, на какой границе должен прилипнуть. Проверьте в DevTools, что position: sticky и top действительно применяются и не переопределены другими правилами.

Почему overflow: hidden у родителя мешает position: sticky?

Sticky ориентируется на ближайшего предка с областью прокрутки, а не обязательно на окно браузера. Найдите у родителей overflow: hidden, auto или scroll: если обёртка не должна управлять прокруткой, уберите это свойство или перенесите обрезку на декоративный блок.

Почему sticky-элемент сразу перестаёт прилипать внутри родителя?

Прилипание ограничено размерами контейнера. Если родитель ненамного выше sticky-элемента, диапазон почти незаметен. Сравните их высоту; при необходимости уменьшите липкий блок или переместите его в более высокий контейнер.

Что проверить, если position: sticky не работает в CSS Grid или Flexbox?

Проверьте, не растягивается ли sticky-элемент по высоте из-за align-items: stretch. Попробуйте align-self: start для него или align-items: start для контейнера, затем проверьте высоту колонок и наличие overflow.

Почему position: sticky работает на компьютере, но не на мобильном экране?

Проверьте media query: на нужной ширине position может переопределяться на static, а у родителя может появляться overflow: hidden. Также сравните высоту липкого блока с доступной областью экрана и его контейнером.

Как быстро найти причину неработающего position: sticky в DevTools?

Начните с вычисленных значений position и top. Затем определите, какой блок реально прокручивается, пройдите по предкам в поисках overflow и ограничений высоты и временно отключайте подозрительные свойства по одному.