Защитный CSS

Список защитных методов CSS, позволяющих избежать потенциальных проблем в будущем.

Часто нам хочется, чтобы был способ избежать определенных проблем с CSS поведением. Вы знаете, контент динамичен, и на веб-странице все может измениться, что повышает вероятность проблемы с CSS и его странного поведения.

Защитный CSS — это набор фрагментов, которые могут помочь вам в написании защищенного 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 в этой статье (smashingmagazine.com/2021/10/object-fit-background-size-css) на 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

Чтобы заранее избежать такого поведения, обязательно сбросьте 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 для разделения дочерних элементов друг от друга. При определенном количестве дочерних элементов макет будет выглядеть нормально. Однако, когда они увеличиваются или уменьшаются, макет будет выглядеть странно.

Рассмотрим следующий пример.

Использование justify-content: space-between

У нас есть гибкий контейнер с четырьмя элементами. Расстояние между каждым элементом не равно gap или margin, оно существует, потому что в контейнере есть justify-content: space-between.


.wrapper {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
}

Когда количество элементов меньше четырех, вот что произойдет.

Использование justify-content: space-between

Это нехорошо. Для этого есть разные решения:

  1. Поле
  2. Flexbox gap (используйте с осторожностью)
  3. Заполнение (может применяться к родительскому элементу каждого дочернего элемента)
  4. Добавление пустых элементов в качестве разделителя.

Для простоты я буду использовать gap.


.wrapper {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

Использование justify-content: space-between

Текст поверх изображений

При использовании текста вместо изображения важно учитывать случай, когда изображение не загружается. Как будет выглядеть текст?

Вот пример.

Текст поверх изображений

Текст выглядит читаемым, но когда изображение не загружается, оно не загружается.

Текст поверх изображений

Мы легко исправим это, добавив цвет фона к элементу 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;
}

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

Минимальный размер контента в CSS flexbox

Даже если мы используем 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

Как и в случае с flexbox, CSS-сетка имеет минимальный размер содержимого по умолчанию для своих дочерних элементов, который равен auto. Это означает, что если есть элемент, который больше, чем элемент сетки, он будет переполнен.

Минимальный размер содержимого в сетке CSS

В приведенном выше примере у нас есть карусель в основном разделе. Для контекста, вот 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;
}

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

Чтобы исправить это, у нас есть три разных решения:

В качестве защитного механизма CSS я бы выбрал первый, который использует функцию minmax().


@media (min-width: 1020px) {
    .wrapper {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 248px;
        grid-gap: 40px;
    }
}

Минимальный размер содержимого в сетке CSS

 

Автоматическая подгонка против автоматического заполнения

При использовании функции 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 с дочерним элементом контейнера сетки? По умолчанию элементы сетки растягиваются. В результате боковой элемент в приведенном ниже примере равен высоте основной секции.

Position: sticky CSS сетки

Чтобы заставить его работать должным образом, вам нужно сбросить свойство align-self.


aside {
    align-self: start;
    position: sticky;
    top: 1rem;
}

Position: sticky CSS сетки

 

Селекторы группировки

Не рекомендуется группировать селекторы, предназначенные для работы с разными браузерами. Например, для стилизации заполнителя ввода требуется несколько селекторов для каждого браузера. Если мы сгруппируем селекторы, все правило будет недействительным, согласно w3c (w3.org/TR/selectors/#grouping).


/* 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, которые я лично использую в зависимости от проекта, над которым работаю.

Ссылка на автора - twitter.com/shadeed9 !


Top

🔖 Выбор по тегам ×

💌 Написать сообщение ×

Все поля обязательны для заполнения!