CSS-live.ru

CSS-выражения от контейнера для дизайнеров

Перевод статьи CSS Container Queries For Designers с сайта ishadeed.com, опубликован на CSS-live.ru с разрешения автора — Ахмада Шадида

При работе над дизайном для веба приходится иметь дело с макетами для разных размеров экрана. Опираясь на эти макеты, разработчик определяет ширину или высоту окна браузера медиазапросами, а затем, исходя из этого, меняет макет. Именно так мы верстали веб последние 10 лет, и вот-вот всё станет еще лучше. У меня для вас хорошие новости.

CSS-выражения от контейнера — долгожданная для веб-разработчиков фича — скоро появится в CSS и с ней уже можно поэкспериментировать в Chrome Canary. В этой статье мы познакомимся с этой фичей поближе, и узнаем, как она повлияет на вашу работу как дизайнера, и не только. Неважно, пишете ли вы код или нет, если увидите какой-то незнакомый CSS, то можете полностью игнорировать его и идти дальше.

Хватит слов, перейдём к делу!

Текущее состояние адаптивного дизайна

Сегодня по-прежнему можно работать с несколькими версиями одной страницы, чтобы показать, как меняется содержимое в зависимости от ширины окна браузера. Мы разрабатываем макеты под различные размеры, такие как мобильный, планшетный и десктопный.

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

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

Заметьте, что это один компонент, но с тремя вариантами: «По умолчанию», «Карточка» и «Полный вариант». Как дизайнер, вы использовали несколько версий макета, чтобы показать это. Это как сказать: «Вот так компонент статьи выглядит в мобильной версии, а так в планшетной»

В CSS разработчику нужно создать три варианта этого компонента, и каждый из них уникален. Рассмотрим следующие основные стили:

.c-media {
  /* Стили по умолчанию */
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

@media (min-with: 400px) {
  .c-media--card {
    display: block;
  }

  .c-media--card img {
    margin-bottom: 1rem;
  }
}

@media (min-with: 1300px) {
  .c-media--featured {
    position: relative;
    /* другие стили */
  }

  .c-media--featured .c-media__content {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
  }
}

Приведённые выше вариации зависят от медиазапросов или ширины окна браузера. Это означает, что мы не можем контролировать эти вариации на основе их родительской ширины. Вы можете подумать, а в чём тут проблема? Что ж, хороший вопрос.

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

Помимо этого мы можем столкнуться с проблемой, когда содержимое меньше ожидаемого. Иногда автор контента добавляет только одну статью, где по дизайну предусмотрено место для трех. В таком случае, либо появится пустое место, либо статья расширится, чтобы заполнить доступное пространство. Рассмотрим следующий рисунок:

В первом случае статья слишком широкая, отчего картинка в ней слишком растягивается. Во втором случае то же самое, но с добавочными пустыми ячейками сетки, растягивающимися на всю доступную ширину. Хорошего мало.

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

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

Что такое выражения от контейнера?

Во-первых, давайте определим контейнер. Это элемент, содержащий другой элемент (элементы), иногда еще его называют оберткой. Если хотите узнать больше о контейнерах, у меня есть детальная статья по теме.

Прототип выражений от контейнера теперь доступен за флагом в Chrome Canary. Благодаря усилиям таких умных людей, как Мириам Сюзанн и не только.

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

Заметьте, что у каждой карточки есть жёлтый контур, который обозначает родительский элемент для каждого компонента. С помощью CSS-выражений от контейнера можно изменять компонент в зависимости от ширины его родителя. Для ясности, вот HTML-разметка для вышеописанного:

<div class="o-grid">
  <div class="o-grid__item">
    <article class="c-media"></article>
  </div>
  <!-- + ещё элементы -->
</div>

Компонент — это элемент с классом .c-media, а его родительский элемент — это .o-grid__item. В CSS можно сделать следующее:

.o-grid__item {
  contain: layout inline-size style;
}

.c-media {
  /* Стили по умолчанию */
}

@container (min-width: 320px) {
  .c-media {
    /* Стили */
  }
}

@container (min-width: 450px) {
  .c-media {
    /* Стили */
  }
}

Во-первых, мы сообщили браузеру, что каждый элемент с классом .o-grid__item — это контейнер. Затем, что если ширина родителя равна или больше 320 пикселей, то компонент должен выглядеть иначе. То же самое для выражения на 450px. Вот как работают CSS-выражения от контейнера.

Кроме того, можно определить их где угодно, что означает, что можно запрашивать контейнер верхнего уровня, если нужно. Теперь, когда вы поняли основную идею CSS-выражений от контейнера, я хочу показать вам следующую схему:

Слева — окно браузера, размер которого изменяется. Справа — компонент, который изменяется в зависимости от ширины родителя. Вот насколько мощные и полезные выражения от контейнера.

Если хотите узнать больше о CSS-ных тонкостях выражений от контейнера, у меня есть подробная статья.

Дизайн с оглядкой на выражения от контейнера

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

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

Возьмём следующий дизайн:

Заметьте, что у нас есть заголовок, раздел статей, цитата и информационная рассылка. Каждый из них должен отталкиваться либо от ширины окна, либо от ширины их родителя.

Я могу представить себе разделение компонентов на следующее:

  • Окно (медиазапросы)
  • Родитель (выражения от контейнера)
  • Общее: компоненты, которые остаются неизменными: кнопки, теги, абзацы.

Для этого примера пользовательского интерфейса: вот как мы можем разделить компоненты.

Когда мы мыслим в таком ключе при работе над дизайном пользовательского интерфейса, можно начать думать о различных вариациях компонентов, которые зависят от ширины их родителя. Давайте изучим их.

На следующем рисунке заметьте, как каждая вариация компонентов статьи появляется при определённой ширине.

Для дизайнера думать о ширине родителя может звучать немного странно, но придется привыкнуть. Мы даём фронтенд-разработчикам детали и вариации каждого компонента, и они могут их использовать.

Кроме того, у нас может быть вариант компонента, который нужно показывать только в определённом контексте. К примеру, страницы со списком событий. В таком случае важно чётко указать, где использовать этот вариант.

Вопрос в том, как сказать дизайнерам, где они должны использовать эти компоненты?

Общение с разработчиками

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

Давайте применим это к компоненту статьи, который мы обсуждали ранее.

Заметьте, что я соотнёс каждую вариацию с конкретным контекстом, а не с размером окна браузера. Для большей убедительности, я покажу, как компонент ведёт себя иначе при использовании в связке с CSS-гридом.

В CSS-гридах можно ключевым словом auto-fit указать браузеру, что столбцы должны расширяться, если их меньше, чем ожидалось (вот тут можно прочитать об этом). Это мощная функция, поскольку она может помочь показать нам различные вариации в одном и том же контексте. Рассмотрим следующий рисунок.

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

Как избежать сложностей при разработке адаптивных компонентов.

Важно помнить, что внутренние части компонента похожи на конструктор «Лего». Вы можете упорядочивать их по-своему для каждой вариации, но без фанатизма. Иногда для фронтенд-разработчика лучше поработать над совершенно новым компонентом, чем создавать вариации с помощью выражений от контейнера.

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

У него есть вот что:

  • Аватар
  • Название
  • Кнопка
  • Пара ключ/значение

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

Применения для CSS-выражений от контейнера

Давайте рассмотрим некоторые применения, которые можно реализовать с помощью CSS-выражений от контейнера.

Список чатов

Я видел этот паттерн в мессенджере «Facebook». Список чатов изменяется на основе ширины окна браузера. Это можно сделать с помощью CSS-выражений от контейнера.

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

Вот как мы можем реализовать это в CSS.

<div class="content">
  <aside>
    <ul>
      <li>
        <img src="shadeed.jpg" alt="Ахмад Шадид" />
        <span class="name">Ахмад Шадид</span>
      </li>
    </ul>
  </aside>
  <main>
    <h2>Основной контент</h2>
  </main>
</div>
.content {
  display: grid;
  grid-template-columns: 0.4fr 1fr;
}

aside {
  contain: layout inline-size style;
}

@container (min-width: 180px) {
  .name {
    display: block;
  }
}

Заметьте, что ширина стороны равна 0.4f, поскольку это динамическая ширина. Элементу aside я добавил свойство contain. Затем, если ширина контейнера превысит 180 пикселей, то отобразится имя пользователя.

Другой похожий вариант использования — боковая навигация. Можно переключать положение подписи пункта меню, чтобы подпись находилась под иконкой или рядом с ней.

Заметьте, как подпись элемента навигации переключается из положения на новой строке, когда контейнер (боковая колонка) узкий, в положение рядом с иконкой, когда места достаточно.

Демо

Аккордеон

Паттерн аккордеона можно использовать для таких вещей, как часто задаваемые вопросы. Иногда хочется добавить список ЧАВО в боковую панель или в небольшую область пользовательского интерфейса. Выражения от контейнера могут помочь!

Вот как можно реализовать вышеописанное с помощью CSS-выражений от контейнера

@container (min-width: 180px) {
  .faq-title {
    display: flex;
    justify-content: space-between;
    font-size: 1.25rem;
  }

  .faq__icon {
    width: 60px;
    height: 60px;
    background-color: #4f96e7;
  }
}

Демо

Поле поиска

Это может быть очень полезно, когда у нас есть универсальное поле поиска, которое используется в нескольких местах. К примеру, его можно использовать в заглавном блоке сайта (справа) или в меньшем контексте вроде боковой панели (слева).

Список событий

Мне лично нравится это применение выражений от контейнера. У нас может быть один и тот же компонент в нескольких контекстах. На рисунке выше у нас есть простой, средний и большой размеры. Вот пример их применения:

Опять же, это один и тот же компонент, который адаптируется к ширине своего родителя. Разве это не здорово? По мне, да.

Об авторе

Компонент «Об авторе» очень распространён в блогах. Его можно использовать в различных контекстах, и поэтому он должен адаптироваться. На приведённом выше рисунке это показано.

Соцсети

Большую часть времени при внедрении компонента «Поделиться в соцсетях» мне нужно было создать версию, которая работает, когда окно браузера большое, а родительская область маленькая (к примеру, боковая панель). Выражения от контейнера это легко решают, заставив компонент адаптироваться к ширине его родителя.

Когда компонент находится в боковой панели (слева), то используется его уменьшенная версия. Когда родитель больше (например, основной раздел), то будет использоваться полная версия.

Спасибо за чтение :)

P.S. Это тоже может быть интересно:

5 комментариев

  1. Мертвая технология, которой в итоге может и не быть. Лишний засер. Пока не будет нормальной поддержки читать статью даже не имеет смысла

    1. Во всех Blink-браузерах уже есть за флагом (и >80% тикетов закрыто), в Safari TP без флага. Такими темпами приличная поддержка будет уже к концу года.

    2. Если вы не видите, как она вам может быть полезна — это не значит, что она мертвая.
      Я часто сталкиваюсь (например форма подписки), когда один и тот же компонент в зависимости от того, где он расположен, приходится сажать на модификаторы.
      Например форма обратной связи — на главной — это обычный блок в потоке.
      На контентной странице — это виджет сбоку на 1/4 — 2/3 ширины на десктопе и повторяет стили на мобильном, но с определенной ширины уходит вниз и повторяет стили обычного блока в потоке.
      С выражениями от контейнера мне не пришлось бы добавлять модификатор и следить за тем, чтоб никто не забыл его добавить. Ну а про лишние переопределения стилей я вообще молчу.

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

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