Знакомая ситуация: сайт отлично выглядит на десктопе, но на мобильном при скролле справа появляется белая (или серая) вертикальная полоса. Страница как будто «шире» экрана.

Я недавно столкнулся с этой проблемой на собственном сайте и потратил немало времени, прежде чем нашёл все причины. Делюсь опытом — чтобы вы не повторяли мой путь.

Как выглядит проблема

При скролле на мобильном устройстве справа от контента видна тонкая вертикальная полоса. Иногда она белая (видно фон браузера), иногда серая (скроллбар внутреннего элемента). На десктопе всё идеально — проблема проявляется только на телефоне.

Главная подлость: в DevTools Chrome с включённой мобильной эмуляцией баг может не воспроизводиться. Нужно проверять на реальном устройстве.

Причина №1: таблицы с фиксированной минимальной шириной

Самая частая причина. Если в CSS есть:

table {
  min-width: 500px;
}

Таблица не сожмётся уже 500px, даже если экран телефона 375px. Она раздувает родительский контейнер и создаёт горизонтальный скролл.

Решение:

/* Обёртка с горизонтальным скроллом */
.prose table {
  display: block;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
}

/* Таблица без фиксированной минимальной ширины */
table {
  width: max-content;
  min-width: 100%;
  border-collapse: collapse;
}

/* Ячейки не переносят текст — таблица скроллится целиком */
th, td {
  white-space: nowrap;
}

Теперь таблица скроллится горизонтально внутри своего контейнера, а не раздувает всю страницу.

Причина №2: CSS Grid с 1fr без minmax(0, 1fr)

Если вы используете Grid-раскладку:

.article-layout {
  display: grid;
  grid-template-columns: 1fr;
}

Значение 1fr имеет неявный минимум — min-content. Если внутри грид-ячейки есть широкий элемент (таблица, картинка, длинное слово), ячейка раздувается шире экрана.

Решение:

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

minmax(0, 1fr) ставит минимум в 0, не давая контенту раздувать колонку.

Причина №3: overflow-x: hidden создаёт скроллбар

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

Когда вы пишете:

.content {
  overflow-x: hidden;
}

Вы ожидаете, что горизонтальный overflow будет скрыт. Но CSS работает иначе: когда overflow-x не visible, браузер автоматически меняет overflow-y с visible на auto.

А overflow-y: auto означает: «показывай вертикальный скроллбар, если контент не помещается». Контент статьи длиннее экрана — и вот вам серая полоса справа. Это не баг — это скроллбар внутреннего элемента.

Решение:

Убрать overflow-x: hidden с внутреннего контейнера. Вместо этого поставить overflow: hidden на внешний контейнер (например, на grid-обёртку):

/* ❌ Плохо — создаёт скроллбар */
.content {
  overflow-x: hidden;
}

/* ✅ Хорошо — overflow на внешнем контейнере */
.article-layout {
  overflow: hidden;
  max-width: 100%;
}

.content {
  min-width: 0; /* для Grid */
}

Причина №4: фиксированные элементы с border за пределами viewport

Мобильное бургер-меню, скрытое за правым краем экрана:

/* ❌ Может вызвать overflow */
.nav {
  position: fixed;
  right: -100%;
  border-left: 1px solid #333;
}

Даже скрытый за правым краем элемент может раздувать ширину документа. border-left торчит на 1px.

Решение:

Использовать display: none вместо смещения, или transform: translateX(110%) (transform не влияет на layout):

/* ✅ Скрыто полностью */
.nav {
  display: none;
}
.nav.open {
  display: flex;
}

/* ✅ Или через transform */
.nav {
  position: fixed;
  right: 0;
  transform: translateX(110%);
}
.nav.open {
  transform: translateX(0);
}

Причина №5: ::after с filter: blur() и отрицательным inset

Если вы делаете glow-эффект на карточках:

/* ❌ Вылезает за пределы viewport */
.card::after {
  position: absolute;
  inset: -1px;
  filter: blur(8px);
  background: linear-gradient(...);
}

inset: -1px + blur(8px) = элемент на 9px шире карточки. Если карточка у края экрана — привет, горизонтальный скролл.

Решение:

/* ✅ Glow внутри карточки */
.card {
  overflow: hidden;
}
.card::after {
  position: absolute;
  inset: 0; /* не -1px */
  background: linear-gradient(...);
  opacity: 0;
  /* без blur */
}
.card:hover::after {
  opacity: 0.06;
}

Как быстро найти виновника

Если не понятно, какой элемент вылезает, откройте DevTools и вставьте в консоль:

document.querySelectorAll('*').forEach(el => {
  if (el.offsetWidth > document.documentElement.clientWidth) {
    console.log('Overflow:', el.offsetWidth, el);
  }
});

Это покажет все элементы, которые шире viewport.

Страховка: тёмный фон на html

Даже если что-то чуть вылезает — пользователь не увидит белую полосу, если фон html совпадает с фоном сайта:

html {
  background: #09090b; /* ваш основной цвет фона */
  overflow-x: hidden;
}

Это не замена исправлению, но хорошая страховка.

Чек-лист перед релизом

  • Нет min-width на таблицах
  • Grid-колонки через minmax(0, 1fr), а не просто 1fr
  • overflow-x: hidden только на внешних контейнерах
  • Скрытые меню через display: none или transform
  • Декоративные ::after / ::before внутри overflow: hidden
  • html и body с overflow-x: hidden и правильным фоном
  • Проверка на реальном мобильном устройстве (не только эмулятор)

Итого

Вертикальная полоса справа — это почти всегда горизонтальный overflow. Элемент шире viewport → страница раздувается → за контентом виден фон.

Самые частые виновники: таблицы, Grid без minmax, и скрытый побочный эффект overflow-x: hidden. Последний — самый коварный, потому что вы ставите его именно для исправления overflow, а он создаёт новую проблему.

Если хотите, чтобы ваш сайт выглядел идеально на любом устройстве — напишите мне, помогу с адаптивной вёрсткой.

Автор материала

Антон Ветров Разработка сайтов, поисковая доступность, автоматизация и эксплуатация.