Список защитных методов CSS, позволяющих избежать потенциальных проблем в будущем.
Часто нам хочется, чтобы был способ избежать определенных проблем с CSS поведением. Вы знаете, контент динамичен, и на веб-странице все может измениться, что повышает вероятность проблемы с CSS и его странного поведения.
Защитный CSS — это набор фрагментов, которые могут помочь вам в написании защищенного CSS. Другими словами, у вас будет меньше проблем в будущем. Если вы следите за моим блогом, вы можете прочитать статью, которую я написал вчера, которая называется «Настрой на всякий случай». Это построено на ней и будет постоянным списком фрагментов. Если у вас есть какие-либо предложения, пожалуйста, дайте мне знать об этом. 🤗
Оглавление
- Упаковка флексбокса
- Расстояние
- Длинный контент
- Предотвращение растяжения или сжатия изображения
- Заблокировать цепочку прокрутки
- Резервная переменная CSS
- Использование фиксированной ширины или высоты
- Забыть
background-repeat
- Вертикальные медиазапросы
- Использование
justify-content: space-between
- Пробел между Текст поверх изображений
- Будьте осторожны с фиксированными значениями в сетке CSS
- Показывать полосу прокрутки только тогда, когда это необходимо
- Проблема полосы прокрутки
- Минимальный размер контента в CSS flexbox
- Минимальный размер содержимого в сетке CSS
- Автоматическая подгонка против автоматического заполнения
- Максимальная ширина изображения
position: sticky
CSS сетки- Селекторы группировки
Упаковка флексбокса
CSS flexbox — одна из самых полезных функций компоновки CSS на сегодняшний день. Заманчиво добавить display: flex
к обертке и расположить дочерние элементы рядом друг с другом.
Дело в том, что когда места недостаточно, эти дочерние элементы по умолчанию не переносятся на новую строку. Нам нужно изменить это поведение с помощью flex-wrap: wrap
.
Вот типичный пример. У нас есть группа параметров, которые должны отображаться рядом друг с другом.
.options-list {
display: flex;
}
Когда места меньше, будет происходить горизонтальная прокрутка. Этого следует ожидать, и на самом деле это не является «проблемой».
Обратите внимание, как элементы все еще рядом друг с другом. Чтобы это исправить, нам нужно разрешить гибкую упаковку.
..options-list {
display: flex;
flex-wrap: wrap;
}
Общее практическое правило при использовании flexbox
— разрешать обертку, если вы не хотите использовать обертку с прокруткой. Это другое дело, но попробуйте использовать flex-wrap
, чтобы избежать неожиданного поведения макета (в нашем случае — горизонтальной прокрутки).
Расстояние
Мы, разработчики, должны учитывать разную длину контента. Это означает, что интервал должен быть добавлен к компоненту, даже если кажется, что он не нужен.
В этом примере у нас есть заголовок раздела и кнопка действия справа. В настоящее время выглядит нормально. Но давайте посмотрим, что происходит, когда заголовок длиннее.
Заметили, что текст расположен слишком близко к кнопке действия? Возможно, вы думаете о многострочном переносе, но я вернусь к этому в другом разделе. А пока давайте сосредоточимся на интервалах.
Если в заголовке есть пробелы и обрезание текста, мы не увидим такой проблемы.
.section__title {
margin-right: 1rem;
}
Длинный контент
Учет длинного контента важен при построении макета. Как вы могли видеть в предыдущем примере, название раздела обрезается, если оно слишком длинное. Это необязательно, но для некоторых интерфейсов это важно учитывать.
Для меня это защитный подход к CSS. Приятно решить «проблему» до того, как она действительно произойдет.
Вот список имен людей, и сейчас он выглядит идеально.
Однако, поскольку это контент, созданный пользователями, нам нужно быть осторожным с тем, как защитить макет на случай, если что-то будет слишком длинным.
См. следующий рисунок:
В таких планах важна согласованность. Для этого мы можем просто обрезать имя, используя text-overflow
и его друзей.
.username {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
Если вы хотите отточить свои навыки работы с длинным контентом в CSS, я написал подробную статью на эту тему.
Предотвращение растяжения или сжатия изображения
Когда у нас нет контроля над соотношением сторон изображения на веб-странице, лучше подумать заранее и предложить решение, когда пользователь загружает изображение, которое не соответствует соотношению сторон.
В следующем примере у нас есть компонент карты с фотографией. Это выглядит хорошо.
Когда пользователь загружает изображение другого размера, оно будет растянуто. Это нехорошо. Посмотрите, как растянуто изображение!
Самое простое решение для этого — использовать CSS object-fit
.
.card__thumb {
object-fit: cover;
}
На уровне проекта я предпочитаю добавлять object-fit
ко всем изображениям, чтобы избежать неожиданных результатов изображения.
img {
object-fit: cover;
}
Узнайте больше о object-fit
в этой статье на Smashing Magazine.
Заблокировать цепочку прокрутки
Вы когда-нибудь открывали модальное окно и начинали прокручивать, а затем, когда вы доходите до конца и продолжаете прокручивать, содержимое под модальным окном (элемент body) будет прокручиваться? Это называется цепочкой прокрутки.
В последние годы было несколько хаков, чтобы заставить это работать, но теперь мы можем сделать это только с помощью CSS, благодаря свойству CSS overscroll-behavior
.
На следующем рисунке вы видите поведение цепочки прокрутки по умолчанию.
Чтобы избежать этого раньше времени, мы можем добавить это к любому компоненту, который должен прокручиваться (например, компонент чата, мобильное меню и т. д.). Преимущество этого свойства в том, что оно не будет иметь эффекта, пока не будет прокрутки.
.modal__content {
overscroll-behavior-y: contain;
overflow-y: auto;
}
Если вы хотите узнать об этом больше, я написал об этом подробную статью.
Резервная переменная CSS
Переменные CSS все чаще используются в веб-дизайне. Существует метод, который мы можем применить, чтобы использовать их таким образом, чтобы не нарушать работу, если значение переменной CSS по какой-то причине было пустым.
Это особенно полезно при передаче значения переменной CSS через Javascript. Вот пример:
.message__bubble {
max-width: calc(100% - var(--actions-width));
}
Переменная --actions-width
используется в функции calc()
, и ее значение берется из Javascript. Предположим, что Javascript по какой-то причине дал сбой, что произойдет? Максимальная ширина будет равна none
.
Мы можем избежать этого заранее и добавить резервное значение в var()
.
.message__bubble {
max-width: calc(100% - var(--actions-width, 70px));
}
Таким образом, если переменная не определена, будет использован запасной вариант (70px
). Этот подход можно использовать в случае, если существует вероятность того, что переменная может выйти из строя (например, из Javascript). В противном случае он не нужен.
Использование фиксированной ширины или высоты
Одной из распространенных вещей, которые ломают макет, является использование фиксированной ширины или высоты с элементом, который имеет содержимое разной длины.
Фиксированная высота
Я часто вижу главный раздел с фиксированной высотой и содержимым, превышающим эту высоту, что приводит к нарушению макета. Не знаете, как это выглядит? Вот.
.hero {
height: 350px;
}
Чтобы контент не вытекал из основного, нам нужно использовать min-height
вместо height
.hero {
min-height: 350px;
}
Таким образом, если содержимое станет больше, макет не сломается.
Фиксированная ширина
Вы когда-нибудь видели кнопку, метка которой расположена слишком близко к левому и правому краям? Это связано с использованием фиксированной ширины.
.button {
width: 100px;
}
Если метка кнопки длиннее 100px
, она будет близко к краям. Если он слишком длинный, текст будет вытекать из него. Это нехорошо!
Чтобы исправить это, мы можем просто заменитьwidth
на min-width
.
Забыть background-repeat
Зачастую при использовании большого изображения в качестве фона мы забываем учитывать случай, когда дизайн просматривается на большом экране. Этот фон будет повторяться по умолчанию.
В основном это не будет видно на экране ноутбука, но его можно четко увидеть на больших экранах.
Чтобы заранее избежать такого поведения, обязательно сбросьте background-repeat
.
.hero {
background-image: url('..');
background-repeat: no-repeat;
}
Вертикальные медиазапросы
Иногда так заманчиво создать компонент и протестировать его, только изменив ширину браузера. Тестирование по высоте браузера может выявить некоторые интересные проблемы.
Вот тот, который я видел несколько раз. У нас есть компонент стороны с основными и второстепенными ссылками. Второстепенные ссылки должны располагаться в самом низу боковой секции.
Рассмотрим следующий пример. Основная и дополнительная навигация выглядят нормально. В примере, который я видел, разработчик добавил position: sticky
к вторичной навигации, чтобы она могла прилипать к нижней части.
Однако, если высота браузера меньше, все сломается. Обратите внимание, как две навигации перекрываются.
Используя вертикальные медиа-запросы CSS, мы можем избежать этой проблемы.
@media (min-height: 600px) {
.aside__secondary {
position: sticky;
bottom: 0;
}
}
Таким образом, вторичная навигация будет привязана к нижней части только в том случае, если высота области просмотра больше или равна 600 пикселей. Гораздо лучше, правда?
Вероятно, есть лучшие способы реализации такого поведения (например, использование margin-auto
), но в этом примере я сосредоточусь на вертикальном запросе.
Если я хочу объяснить использование CSS вертикального медиазапроса, мне нужно написать об этом целую статью. Хорошая новость в том, что я уже написал, если вам интересно.
Использование justify-content: space-between
Во гибком контейнере вы можете использовать justify-content
для разделения дочерних элементов друг от друга. При определенном количестве дочерних элементов макет будет выглядеть нормально. Однако, когда они увеличиваются или уменьшаются, макет будет выглядеть странно.
Рассмотрим следующий пример.
У нас есть гибкий контейнер с четырьмя элементами. Расстояние между каждым элементом не равно gap
или margin
, оно существует, потому что в контейнере есть justify-content: space-between
.
.wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
Когда количество элементов меньше четырех, вот что произойдет.
Это нехорошо. Для этого есть разные решения:
- Поле
- Flexbox gap (используйте с осторожностью)
- Заполнение (может применяться к родительскому элементу каждого дочернего элемента)
- Добавление пустых элементов в качестве разделителя.
Для простоты я буду использовать gap
.
.wrapper {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
Текст поверх изображений
При использовании текста вместо изображения важно учитывать случай, когда изображение не загружается. Как будет выглядеть текст?
Вот пример.
Текст выглядит читаемым, но когда изображение не загружается, оно не загружается.
Мы легко исправим это, добавив цвет фона к элементу img
. Этот фон будет виден только в том случае, если изображение не загрузится. Разве это не круто?
.card__img {
background-color: grey;
}
Будьте осторожны с фиксированными значениями в сетке CSS
Скажем, у нас есть сетка, которая содержит стороны и основные. CSS выглядит так:
.wrapper {
display: grid;
grid-template-columns: 250px 1fr;
gap: 1rem;
}
Это сломается при небольших размерах окна просмотра из-за нехватки места. Чтобы избежать такой проблемы, всегда используйте медиа-запрос при использовании сетки CSS, как показано выше.
@media (min-width: 600px) {
.wrapper {
display: grid;
grid-template-columns: 250px 1fr;
gap: 1rem;
}
}
Показывать полосу прокрутки только тогда, когда это необходимо
К счастью, мы можем управлять отображением полосы прокрутки или ее отсутствием только в случае длинного контента. При этом настоятельно рекомендуется использовать auto
в качестве значения для overflow
.
Рассмотрим следующий пример.
Обратите внимание, что даже если содержимое короткое, полоса прокрутки видна. Это плохо для пользовательского интерфейса. Как дизайнер, я просто сбиваюсь с толку, видя полосу прокрутки, когда она не нужна.
.element {
overflow-y: auto;
}
С overflow-y: auto
полоса прокрутки будет видна только в том случае, если содержимое длинное. Иначе его там не будет. Вот обновленная цифра.
Проблема полосы прокрутки
Еще одна вещь, связанная с прокруткой, — полоса прокрутки. Взяв предыдущий пример, когда содержимое становится длиннее, добавление полосы прокрутки вызовет сдвиг макета. Причина смены макета заключается в том, чтобы зарезервировать место для полосы прокрутки.
Рассмотрим следующий рисунок.
Обратите внимание, как изменилось содержимое, когда оно стало длиннее в результате отображения полосы прокрутки. Мы можем избежать такого поведения, используя свойство scrollbar-gutter
.
.element {
scrollbar-gutter: stable;
}
Минимальный размер контента в CSS flexbox
Если у гибкого элемента есть текстовый элемент или изображение, которое больше, чем длина самого элемента, браузер не будет их уменьшать. Это поведение по умолчанию для flexbox.
Рассмотрим следующий пример.
.card {
display: flex;
}
Если в заголовке очень длинное слово, оно не будет переноситься на новую строку.
Даже если мы используем overflow-wrap: break-word
, это не сработает.
.card__title {
overflow-wrap: break-word;
}
Чтобы изменить это поведение по умолчанию, нам нужно установить min-width
гибкого элемента на 0
. Это происходит из-за того, что значение по умолчанию min-width
равно auto
, и происходит переполнение.
.card__title {
overflow-wrap: break-word;
min-width: 0;
}
То же самое относится и к гибкой обертке столбца, но вместо этого мы будем использовать min-height: 0
.
Минимальный размер содержимого в сетке CSS
Как и в случае с flexbox, CSS-сетка имеет минимальный размер содержимого по умолчанию для своих дочерних элементов, который равен auto
. Это означает, что если есть элемент, который больше, чем элемент сетки, он будет переполнен.
В приведенном выше примере у нас есть карусель в основном разделе. Для контекста, вот HTML и CSS.
<div class="wrapper">
<main>
<section class="carousel"></section>
</main>
<aside></aside>
</div>
@media (min-width: 1020px) {
.wrapper {
display: grid;
grid-template-columns: 1fr 248px;
grid-gap: 40px;
}
}
.carousel {
display: flex;
overflow-x: auto;
}
Поскольку карусель — это гибкий контейнер, который не сворачивает, его ширина больше, чем основная секция, и, таким образом, элемент сетки учитывает это. В результате есть горизонтальная прокрутка.
Чтобы исправить это, у нас есть три разных решения:
- Использование
minmax()
- Применение
min-width
к элементу сетки - Добавление
overflow: hidden
в элемент сетки
В качестве защитного механизма CSS я бы выбрал первый, который использует функцию minmax()
.
@media (min-width: 1020px) {
.wrapper {
display: grid;
grid-template-columns: minmax(0, 1fr) 248px;
grid-gap: 40px;
}
}
Автоматическая подгонка против автоматического заполнения
При использовании функции CSS grid minmax()
важно решить, использовать ли ключевые слова auto-fit
или auto-fill
. При неправильном использовании это может привести к неожиданным результатам.
При использовании функции minmax()
ключевое слово auto-fit
расширяет элементы сетки, чтобы заполнить доступное пространство. В то время как auto-fill
сохранит доступное пространство зарезервированным без изменения ширины элементов сетки.
При этом использование auto-fit
может привести к тому, что элементы сетки будут слишком широкими, особенно если они меньше ожидаемого. Рассмотрим следующий пример.
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-gap: 1rem;
}
Если есть только один элемент сетки и используется auto-fit
, элемент будет расширяться, чтобы заполнить ширину контейнера.
В большинстве случаев такое поведение не требуется, поэтому, на мой взгляд, лучше использовать auto-fill
.
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-gap: 1rem;
}
Максимальная ширина изображения
Как правило, не забудьте установить max-width: 100%
для всех изображений. Это можно добавить к используемому вами сбросу CSS.
img {
max-width: 100%;
object-fit: cover;
}
Position: sticky CSS сетки
Вы когда-нибудь пробовали использовать position: sticky
с дочерним элементом контейнера сетки? По умолчанию элементы сетки растягиваются. В результате боковой элемент в приведенном ниже примере равен высоте основной секции.
Чтобы заставить его работать должным образом, вам нужно сбросить свойство align-self
.
aside {
align-self: start;
position: sticky;
top: 1rem;
}
Селекторы группировки
Не рекомендуется группировать селекторы, предназначенные для работы с разными браузерами. Например, для стилизации заполнителя ввода требуется несколько селекторов для каждого браузера. Если мы сгруппируем селекторы, все правило будет недействительным, согласно w3c.
/* Don't do this, please */
input::-webkit-input-placeholder,
input:-moz-placeholder {
color: #222;
}
Вместо этого сделайте так:
input::-webkit-input-placeholder {
color: #222;
}
input:-moz-placeholder {
color: #222;
}
Это не конец!
Это не конец, но мне очень понравилось документировать все эти техники. Это постоянный список защитных техник CSS, которые я лично использую в зависимости от проекта, над которым работаю.