CSS следующего поколения: @container
Новое свойство @container дает нам возможность стилизовать элементы в зависимости от размера их родительского контейнера.
Вы можете думать об этом как о медиа-запросе (@media), но вместо того, чтобы полагаться на область просмотра (viewport) для настройки стилей, эти стили теперь могу зависеть от родительский контейнер целевого элемента.
Контейнерные запросы (@container) станут самым большим изменением в веб-стиле со времен CSS3, изменив наше представление о том, что означает «отзывчивый дизайн» (responsive design).
Область просмотра (viewport) и пользовательский агент больше не будут единственными целями, которые нам нужны для создания адаптивного макета и стилей пользовательского интерфейса. С контейнерными запросами элементы смогут нацеливаться на своих родителей и соответствующим образом применять собственные стили. Это означает, что один и тот же элемент, который находится на боковой панели (к примеру), в теле или на базовой панели, может выглядеть совершенно по-разному в зависимости от доступного размера.
@container в действие
В этом примере я использую две карточки в родительском элементе со следующей разметкой:
<div class="card-container"> <div class="card"> <figure> ... </figure> <div> <div class="meta"> <h2>...</h2> <span class="time">...</span> </div> <div class="notes"> <p class="desc">...</p> <div class="links">...</div> </div> <button>...</button> </div> </div> </div>
Затем я устанавливаю включение (свойство container-type
) для родителя, у которого я буду запрашивать стили контейнера (.card-container
). Я также устанавливаю относительный макет сетки для родителя .card-container
, поэтому его inline-size
будет меняться в зависимости от этой сетки. Вот что я запрашиваю с помощью @container
:
.card-container { container-type: inline-size; width: 100%; }
Теперь я могу использовать контейнерный запрос для настройки стилей! Это очень похоже на то, как вы устанавливаете стили, используя медиа запросы на основе ширины , используя max-width
для установки стилей, когда элемент меньше определенного размера, и min-width
, когда он больше.
/* when the parent container is smaller than 850px, remove the .links div and decrease the font size on the episode time marker */ @container (max-width: 850px) { .links { display: none; } .time { font-size: 1.25rem; } /* ... */ } /* when the parent container is smaller than 650px, decrease the .card element's grid gap to 1rem */ @container (max-width: 650px) { .card { gap: 1rem; } /* ... */ }
Контейнерные запросы + медиа-запросы
Одной из лучших функций контейнерных запросов является возможность отделять микро макеты от макро макетов. Вы можете стилизовать отдельные элементы с помощью контейнерных запросов, создавая детализированные микро-макеты, а также стилизовать целые макеты страниц с помощью медиа-запросов, макро макетов. Это создает новый уровень контроля, позволяющий создавать еще более отзывчивые интерфейсы.
Вот еще один пример, демонстрирующий возможности использования медиа-запросов для макро макетов (пример календаря, переходящего с одной панели на несколько панелей) и микро-макета (т. е. макета/размера даты и полей события/сдвига размера) для создания прекрасной коллекции запросов.
Контейнерные запросы + CSS Grid
Один из моих любимых способов увидеть влияние контейнерных запросов — это посмотреть, как они работают в grid. Возьмем следующий пример пользовательского интерфейса для торговли растениями:
На этом сайте вообще не используются медиа-запросы. Вместо этого мы используем контейнерные запросы только вместе с CSS grid для отображения компонента карты покупок в разных представлениях.
В сетке товара макет создается с помощью grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
. Это создает макет, который говорит cards занимать доступное дробное пространство, пока они не достигнут размера 230 пикселей, а затем перетекают в следующую строку. Ознакомьтесь с другими трюками с сеткой на 1linelayouts.com.
Затем у нас есть контейнерный запрос, который настраивает карточки так, чтобы они принимали вертикальный блочный макет, когда они имеют ширину менее 350 пикселей, и переходит к горизонтальному встроенному макету, применяя display: flex
(который по умолчанию имеет inline flow).
@container (min-width: 350px) { .product-container { padding: 0.5rem 0 0; display: flex; } /* ... */ }
Это означает, что каждая карточка имеет собственный адаптивный стиль. Это еще один пример того, как вы можете создать макро-макет с сеткой товаров и микро-макет с карточками товаров. Довольно круто!
Применение
Чтобы использовать @container
, сначала необходимо создать родительский элемент, содержащий контейнер. Для этого вам нужно установить в родительском элементе значение contain: layout inline-size
. Вы можете использовать inline-size
, поскольку в настоящее время мы можем применять контейнерные запросы только к inline. Это предотвратит разрыв вашего макета в блочном направлении.
Настройка contain: layout inline-size
создает новый содержащий блок и новый блочный контекст форматирования, позволяя браузеру отделить его от остальной части макета. Теперь мы можем строить запросы!
Ограничения
В настоящее время вы не можете использовать контейнерные запросы на основе высоты, используя только ось блока. Чтобы дочерние элементы сетки работали с @container
, вам нужно добавить элемент-оболочку. Несмотря на это, добавление оболочки позволяет получить желаемые эффекты.
Попробуйте
Вы можете поэкспериментировать со свойством @container
в Chromium уже сегодня, перейдя по адресу: chrome://flags
в Chrome Canary и включив флаг #experimental-container-queries.