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

На компьютере всё идеально. Открываешь на телефоне — страница елозит вправо-влево, справа полоса пустоты, а что её вызывает — не видно: виновник обычно прозрачный или уехал за экран.
Хорошая новость: причин, по сути, три, и находятся они за минуту. Плохая: самый популярный «фикс» в интернете ломает другие вещи — про него в конце.
Сначала найди виновника, не угадывай
Не начинай с правок 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.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





