В этой статье мы рассмотрим причины возникновения проблем с переполнением в CSS и способы их решения. Мы также рассмотрим, как современные инструменты разработчика могут облегчить процесс выявления этих проблем и отладки кода.
Если вы фронтэнд разработчик, то вы, возможно, уже сталкивались с проблемой появления нежелательной горизонтальной полосы прокрутки в различных элементах сайта, особенно при выводе его на мобильных устройствах. Поскольку существует множество причин возникновения подобной проблемы, простого ее решения не существует. Некоторые находятся и устраняются быстро, а некоторые требуют определенного навыка работы с инструментами отладки.
Что такое проблема переполнения?
Прежде чем обсуждать проблемы переполнения, необходимо выяснить, что это такое. Проблема переполнения (overflow) возникает, когда на веб-странице появляется нежелательная горизонтальная полоса прокрутки, позволяющая пользователю просматривать некий контент в горизонтальной плоскости. Возникновение подобного явления может обуславливаться самыми различными факторами.
Это может произойти из-за непредвиденно широкого содержимого или элемента фиксированной ширины, который шире окна просмотра. Мы рассмотрим все причины в этой статье.
Как выявить переполнение
Важная часть решения этой проблемы заключается в том, чтобы заметить ее в первую очередь. Если мы знаем, когда и где это происходит, мы можем сосредоточиться на изучении этой части веб-страницы. Существуют различные способы обнаружения переполнения: от прокрутки вручную влево или вправо или с помощью JavaScript.
Давайте рассмотрим способы выявления переполнения.
1. Прокрутка влево или вправо
Первый способ обнаружить проблему переполнения – попробовать прокрутить страницу по горизонтали. Если у вас это получилось, то это явное предупреждение о том, что со страницей что-то не так.
2. Использование JavaScript, чтобы найти элемент, который шире тела страницы
Можно добавить сниппет кода в консоль браузера, чтобы выявить любые элементы шире тела страницы. Это удобно для страниц с большим количеством элементов.
var docWidth = document.documentElement.offsetWidth;
[].forEach.call(
document.querySelectorAll('*'),
function(el) {
if (el.offsetWidth > docWidth) {
console.log(el);
}
}
);
3. CSS свойство outline
Применив CSS свойство outline
ко всем элементам на странице, мы получим подсветку элементов, которые выходят за границы тела страницы.
* {
outline: solid 1px red;
}
Можно сделать даже лучше. Есть скрипт, придуманный Эдди Османи (Addy Osmani), который добавляет к каждому элементу свойство outline
случайного цвета.
[].forEach.call($$("*"),function(a){a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)})
4. Пометка "OVERFLOW" в браузере Firefox
У браузера Firefox есть полезная функция, которая сигнализирует о том, что данный элемент испытывает проблему переполнения. Хочется надеяться, что другие браузеры тоже добавят такую функцию!
5. Удаление элементов веб-страницы
Еще один распространенный способ выявить проблемный элемент – это открыть инструмент разработчика браузера и начать удалять элементы один за другим. Как только переполнение исчезнет, то элемент, который вы только что удалили, скорее всего и содержит проблему. Этот метод может оказаться полезным в тех случаях, когда вы выявили проблему, но не знаете, с чем она связана.
Как только вы найдете, где происходит переполнение, вам будет легче сделать сокращенный тест для дальнейшей отладки.
Частые причины возникновения переполнения
Элементы фиксированной ширины
Одной из наиболее распространенных причин переполнения являются элементы фиксированной ширины. Строго говоря, не следует задавать фиксированную ширину тем элементам, которые должны отображаться в условиях изменяющегося размера окна просмотра.
.element {
/* Не делайте так */
width: 400px;
}
Использование flexbox без переноса
Как бы не был полезен flexbox, тем не менее, стремление предотвратить переход элементов на новую строку, когда для них недостаточно места, чревато неприятностями.
.parent {
display: flex;
}
Здесь флекс элементы могут вызвать горизонтальное переполнение, если для них будет мало места для размещения в одной строке: Обязательно используйте свойство flex-wrap: wrap
, если предполагается, что флекс элемент будет отображаться в окне просмотра с изменяющимся размером.
.parent {
display: flex;
/* Делайте так */
flex-wrap: wrap;
}
CSS Grid
Когда вы используете разметку CSS Grid, то очень важно учитывать адаптивность макета. Возьмем следующую разметку:
.wrapper {
display: grid;
grid-template-columns: 1fr 300px 1fr;
grid-gap: 1rem;
}
Данный код отлично работает, но только до тех пор, пока ширина окна просмотра не станет меньше 300px. Когда это случится, возникнет переполнение.
Чтобы избежать возникновения подобной ситуации, используйте гриды только тогда, когда достаточно места. Также, можно использовать CSS медиа запросы следующим образом:
.wrapper {
display: grid;
grid-template-columns: 1fr;
grid-gap: 1rem;
}
@media (min-width: 400px) {
.wrapper {
grid-template-columns: 1fr 300px 1fr;
}
}
Длинные слова
Еще одной распространенной причиной переполнения становятся длинные слова, которые не помещаются в окне просмотра. Чаще всего это происходит на мобильных устройствах из-за их малой ширины окна просмотра.
Чтобы исправить это, нужно использовать CSS свойство overflow-wrap
.
.article-content p {
overflow-wrap: break-word;
}
Это особенно полезно, когда контент вводит пользователь. Отличным примером такого контента являются комментарии. Пользователь может вставить длинный URL-адрес в свой комментарий, и это должно обрабатываться свойством overflow-wrap
.
Минимальный размер контента в CSS Flexbox
Еще одной интересной причиной переполнения является минимальный размер содержимого в Flexbox. Что это значит?
Согласно CSS спецификации:
По умолчанию флекс элементы не будут уменьшаться ниже минимального размера содержимого (длина самого длинного слова или элемента фиксированного размера). Чтобы изменить это, установите свойствоmin-width
илиmin-height
.
Это означает, что флекс элемент с длинным словом не будет уменьшаться ниже минимального размера содержимого.
Чтобы исправить это, для флекс элемента можно либо установить свойству overflow
любое значение кроме visible
, либо установить свойство min-width: 0
.
.card__name {
min-width: 0;
overflow-wrap: break-word;
}
Минимальный размер контента в CSS Grid
Как и в случае с CSS Flexbox, у CSS Grid действует та же концепция минимального размера контента. При этом решение проблема переполнения несколько другое.
Давайте исследуем проблему. Предположим, что у нас есть боковая и основная секции, разметка которых построена на CSS гридах.
.wrapper {
display: grid;
grid-template-columns: 248px 1fr;
grid-gap: 40px;
}
Также, у нас есть полоса с прокручиваемым контентом, расположенная в основной секции и с разметкой на флексбокс.
.section {
display: flex;
gap: 1rem;
overflow-x: auto;
}
Обратите внимание, что мы не используем свойство flex-wrap
, потому что нам нужно, чтобы флекс элементы оставались на одной линии. Тем не менее, это не работает и вызывает переполнение.
Чтобы это исправить, нужно использовать minmax()
вместо 1fr
. В этом случае минимальный размер контента основного элемента не будет рассчитываться автоматически.
.wrapper {
display: grid;
grid-template-columns: 248px minmax(0, 1fr);
grid-gap: 40px;
}
Отрицательные отступы
Элемент, расположенный за пределами экрана, может вызвать переполнение. Обычно это происходит потому, что у элемента установлены отрицательные отступы.
В следующем примере у нас есть элемент с отрицательным отступом, в документе с ориентацией текста слева направо.
.element {
position: absolute;
right: -100px;
}
Интересно, что если разместить элемент с другой стороны, то переполнения не будет. В чем же дело?
Вот что говорится в CSS спецификации:
Пользовательские программы просмотра должны обрезать прокручиваемую область переполнения контейнеров прокрутки со сторон начала блока и области начало контента (таким образом, их поведение должно быть таким, как если бы у них не было прокручиваемого переполнения на этой стороне).
Так, для документов с ориентацией текста слева направо левая сторона окна как раз и является областью начала контента. В результате любой элемент, расположенный за границей экрана слева, будет обрезан, и переполнение не возникнет.
Таким образом, если необходимо убрать элемент за пределы экрана, не забудьте установить свойство overflow: hidden
у его родителя, чтобы не было переполнения.
Изображения без свойства max-width
Если не позаботиться о больших изображениях заранее, то вы обязательно встретитесь с переполнением. Чтобы этого не происходило, убедитесь, что для всех изображений установлено свойство max-width: 100%
.
img {
max-width: 100%;
}
Единицы измерения относительно окна браузера
Использование единиц измерения ширины относительно окна браузера в 100vw
имеет оборотную сторону, которая выражается в возникновении переполнения, когда видна полоса прокрутки. На macOS значение 100vw
отработает вполне нормально и не вызовет горизонтальную прокрутку.
В Windows полосы прокрутки выводятся по умолчанию, поэтому возникает переполнение.
Причина этого заключается в том, что при значении 100vw
не учитывается ширина вертикальной полосы прокрутки браузера. В результате ширина будет равна 100vw
плюс ширина полосы прокрутки. К сожалению, исправить это средствами CSS невозможно.
Тем не менее, при помощи JavaScript мы можем измерить ширину окна просмотра, исключая полосу прокрутки.
function handleFullWidthSizing() {
const scrollbarWidth = window.innerWidth - document.body.clientWidth
document.querySelector('myElement').style.width = `calc(100vw - ${scrollbarWidth}px)`
}
Добавленные рекламные блоки
Добавленные на страницу рекламные блоки могут стать причиной переполнения, если их ширина больше ширины их родительского элемента. Чтобы предотвратить это, следует установить свойство overflow-x: hidden
у родительского элемента рекламного блока.
Тщательно проверяйте каждый рекламный блок на веб-сайте, чтобы он не стал причиной переполнения.
А хорошая ли идея устанавливать свойство overflow-x: hidden для тега body?
Установка свойства overflow-x: hidden
, подобна наложению повязки без решения проблемы. Если у вас есть переполнение, то лучше решить саму проблему.
Кроме того, применение overflow-x: hidden
к элементу body
не является хорошей идеей, потому что тогда не будет работать свойство position: sticky
.
Как избежать переполнения в CSS
Ниже представлены некоторые вещи, на которые следует обращать внимание, чтобы уменьшить вероятность возникновения проблемы переполнения в CSS.
Тестируйте с реальным контентом
Ничто не сравнится по эффективности с тестированием с реальным контентом. При этом вы сможете убедиться, что разметка сайта будет корректно работать с самыми различными типами контента.
Учитывайте пользовательский контент
Для таких компонентов, как комментарии, следует учитывать, как было описано выше, случаи, когда пользователь будет вставляет длинный URL-адрес или вводить длинные слова.
Осторожно используйте CSS Grid и Flexbox
Какими бы полезными ни были CSS grid и flexbox, при неправильном использовании они могут легко вызвать переполнение. Как мы уже обсуждали выше, если не использовать свойство flex-wrap: wrap
, то можно легко получить проблему переполнение. То же случится и при использовании grid-template-columns: 1fr 350px
, когда ширина экрана меньше 350px.