Запросы контейнера CSS позволяют применять стили на основе размера контейнера компонента, а не всей области просмотра.

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

Для решения этой проблемы были введены контейнерные запросы. Они также выросли благодаря популярности таких фреймворков, как React и Vue.js, которые работают, создавая модульные «компоненты» пользовательского интерфейса. Узнайте, как использовать контейнерные запросы для создания адаптивных элементов в CSS.

Код, используемый в этой статье, доступен в этом Репозиторий GitHub и вы можете использовать его бесплатно по лицензии MIT.

Почему вы должны использовать контейнерные запросы CSS?

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

Репозиторий GitHub.

После того, как вы успешно клонировали репозиторий, запустите код. Вы найдете веб-страницу, похожую на следующее изображение:

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

Макет адаптивный. Когда вы свернете окно браузера, вы увидите, что карточка превращается в вертикальный столбец:

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

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

@СМИ(Максимальная ширина: 800 пикселей) {
.карта {
flex-направление: столбец;
}
.card-header {
ширина: 100%;
}
}

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

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

.сайдбар.карта {
/* Уменьшаем боковую панель */
}

@СМИ(Максимальная ширина: 800 пикселей) {
/* Стиль страницы, когда экран уже 800 пикселей */
}

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

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

Как создать контейнерный запрос

Чтобы создать запрос-контейнер, вы должны начать с выбора элемента, который хотите использовать в качестве контейнера (в данном случае, основного раздела и боковой панели). Внутри блока нужно установить контейнерного типа к встроенный размер:

основной, .сайдбар {
контейнерного типа: встроенный размер
}

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

@контейнер(Максимальная ширина: 500 пикселей) {
.карта {
flex-направление: столбец;
}
.card-header {
ширина: 100%;
}
}

Это будет работать как обычный медиа-запрос. Но вместо того, чтобы измерять размер экрана, вы измеряете размер контейнеров (главной и боковой панели). Итак, теперь, когда ваш контейнер имеет размер 500 пикселей и более, вы используете горизонтальный вид. В противном случае вы используете вертикальную (по умолчанию для flexbox).

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

Запрос контейнера невероятно эффективен, потому что он позволяет вам изменять размер вещей на основе контейнера, а не всей ширины браузера. Это особенно полезно при работе с компонентами (например, в React или Vue).

С помощью контейнерных запросов вы можете легко изменять размер компонентов пользовательского интерфейса в зависимости от их контейнера, что позволяет создавать полностью автономные компоненты.

Именование контейнеров

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

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

В следующем примере мы превратили элемент body в контейнер:

тело {
контейнерного типа: встроенный размер;
}

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

Чтобы переопределить это поведение, вам нужно сделать две вещи. Во-первых, вам нужно дать вашему элементу body имя контейнера:

тело {
контейнерного типа: встроенный размер;
имя-контейнера: тело;
}

Затем, когда вы создаете свой контейнерный запрос, вам нужно указать имя контейнера после @контейнер.

@контейнер тело (Максимальная ширина:1000 пикселей){
/* Правила CSS, предназначенные для контейнера body */
}

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

Контейнерные блоки

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

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