Гайды

Почему страница ездит вбок на телефоне — и как за минуту найти виновника

Иллюстрация: доска на столе выдвинута вбок и выходит за край, за ней полоса пустоты

На компьютере всё идеально. Открываешь на телефоне — страница елозит вправо-влево, справа полоса пустоты, а что её вызывает — не видно: виновник обычно прозрачный или уехал за экран.

Хорошая новость: причин, по сути, три, и находятся они за минуту. Плохая: самый популярный «фикс» в интернете ломает другие вещи — про него в конце.

Сначала найди виновника, не угадывай

Не начинай с правок CSS. Открой страницу на телефоне (или в мобильном режиме браузера), прокрути до упора влево и выполни в консоли:

const w = document.documentElement.clientWidth;
document.querySelectorAll('*').forEach((el) => {
  const r = el.getBoundingClientRect();
  if (r.right > w + 1 || r.left < -1) console.log(Math.round(r.right), el);
});

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

Способ без консоли — временно подсветить всё:

* { outline: 1px solid red; }

Виновник сразу видно глазами: его красная рамка уходит за экран.

Причина 1. Что-то реально шире экрана

Самая частая. Кандидаты по убыванию популярности:

  • картинка без ограничения: img со своей натуральной шириной 1200 пикселей. Лечится одной глобальной строкой img, video { max-width: 100%; height: auto; };
  • жёсткая ширина в пикселях: width: 420px у карточки. На телефоне шириной 390 это сразу минус 30. Меняй на max-width: 420px — блок сузится, когда не влезает;
  • длинная неразрывная строка: email, ссылка, токен, путь к файлу. Браузеру негде перенести — он растягивает контейнер. Лечится overflow-wrap: anywhere (или word-break: break-word) на блоке с текстом;
  • широкая таблица или блок кода. Их не надо ужимать — их надо положить в обёртку с overflow-x: auto, чтобы листались они, а не вся страница.

Как проверить: сниппет выше называет элемент напрямую.

Причина 2. Виноват 100vw

Коварная. Кажется, что 100vw — это «ширина экрана», но по стандарту CSS единицы вьюпорта считаются так, будто полос прокрутки не существует.

На телефоне полосы наложенные (появляются поверх содержимого) и разницы нет. На десктопе и в некоторых Android-браузерах полоса занимает реальные 15–17 пикселей — и блок с width: 100vw оказывается на эти пиксели шире доступного места. Готова горизонтальная прокрутка на ровном месте.

Как проверить: поищи в стилях 100vw — особенно в приёме «растянуть секцию на всю ширину» вроде margin-left: calc(50% - 50vw).

Как починить: для блока внутри обычного потока почти всегда достаточно width: 100% — проценты считаются от родителя и про полосу знают. Если нужен именно полноэкранный разрыв, добавь родителю overflow-x: clip (не hidden, о разнице ниже).

Причина 3. Колонка отказывается сжиматься

Самая неочевидная — и очень частая в вёрстке от ИИ-помощников. Сетка выглядит безобидно:

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

А внутри колонки лежит что-то широкое: таблица, блок кода, длинная ссылка. Ожидание — колонка сожмётся. Реальность — сетка уедет за экран.

Причина в умолчании: у flex- и grid-элементов min-width равен auto, а это, по документации MDN, размер min-content — то есть колонка не может стать уже своего самого широкого неразрывного содержимого. Не ноль, как у обычных блоков.

Как починить — любым из двух способов:

/* в сетке */
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);

/* или элементу */
.col { min-width: 0; }

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

Про «фикс», который ломает другое

Первый совет, который выдаёт поиск: повесить на body строку overflow-x: hidden. Прокрутка правда исчезнет. Но hidden делает элемент контейнером прокрутки — и этим ломает position: sticky у всего внутри: липкие шапки и заголовки таблиц перестают прилипать. Ещё содержимое остаётся за кадром: до него можно доехать табом или скриптом, просто не видя.

Если пластырь всё-таки нужен, бери overflow-x: clip: он обрезает лишнее, но контейнером прокрутки не становится и липкие блоки не трогает. Поддержка — Chrome 90, Firefox 81, Safari 16.

И всё же порядок такой: сначала сниппет и реальная причина, потом (если совсем надо) clip. Спрятать симптом — значит оставить блок, который на чужом телефоне вылезет иначе. Общий подход к таким разборам — в как чинить баги вместе с ИИ.

Коротко: не «убрать прокрутку», а найти, кто шире экрана. Это один сниппет.

Почему в мобильном режиме DevTools баг не воспроизводится?

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

Можно ли просто поставить overflow-x: hidden и забыть?

Можно, если в проекте нет липких элементов и ты готов, что часть содержимого окажется недоступна глазу. В остальных случаях clip безопаснее, а починка причины — надёжнее обоих.

Прокрутка появилась после добавления padding — почему?

Потому что по умолчанию width не включает внутренние отступы: блок с width: 100% и padding: 20px шире родителя ровно на 40 пикселей. Лечится box-sizing: border-box, подробно — в блочной модели CSS.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →