Когда и как выбирать между медиа запросами и контейнерными запросами
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов CSS меняет правила игры. Это самое интересное, что произошло с момента появления медиа-запросов.
Но что такое контейнерный запрос? Почему контейнерные запросы важны и как их можно использовать?
В этой статье мы собираемся ответить на все эти и другие вопросы в следующих разделах:
- Что такое медиа-запрос в CSS?
- Проблема с медиазапросами
- Когда и как использовать медиа-запросы
- Когда и как использовать контейнерные запросы
Не теряя больше времени, давайте приступим к делу.
Что такое медиа-запрос в CSS?
Давным-давно у большинства веб-сайтов было много проблем с отображением компонентов на экранах разных размеров, особенно с революцией мобильных телефонов. Большинство веб-сайтов исправляли эту проблему, создав новый веб-сайт с доменом m.. Если вы когда-либо использовали m.facebook.com, то сталкивались с подобным подходом.
Но, это было до медиазапросов. С помощью медиа-запросов веб-сайты можно создавать в соответствии с определенным окном просмотра viewport, поэтому прошли те времена, когда приходилось увеличивать масштаб на смартфоне, чтобы увидеть, что находится на веб-сайте.
Медиа-запросы предоставляют условный оператор для некоторых стилей, которые затем реализуются или нет в зависимости от того, выполняются условия или нет.
Проблема с медиазапросами
Хотя медиа-запросы сильно изменились, у них осталась одна проблема: их нельзя использовать повторно. С помощью медиа-запросов вы можете создать адаптивный элемент и реализовать его, и хотя он хорошо выглядит в стандартном случае использования, он, вероятно, не будет работать так же хорошо, если он будет перемещен в другой контейнер со свойствами CSS, влияющими на размеры элемента. Чтобы он работал правильно, вам нужно добавить еще много свойств CSS.
Вот тут-то и появляются контейнерные запросы. Теперь с контейнерными запросами вы можете сами нацеливаться на отдельные элементы и позволять им адаптироваться практически к любому заданному контейнеру или макету.
Контейнерные запросы похожи на медиа-запросы; единственная разница в том, что они делают контейнер или элемент отзывчивым на основе пространства, доступного для контейнера, а не области просмотра всего экрана. Но возникает вопрос: нужны ли нам тогда вообще медиа-запросы?
Когда и как использовать медиа-запросы
Ответ на поставленный выше вопрос – да! По-прежнему существует множество вариантов использования медиа-запросов, несмотря на то, что контейнерные запросы устраняют их значительные ограничения.
Медиа-запросы можно и нужно использовать для макетов страниц, которые обычно находятся на самом верхнем уровне DOM и не вложены в другой контейнер. Они лучше всего подходят для этого, потому что макет главной страницы не должен адаптироваться ни к чему, кроме области просмотра.
Медиа-запросы также можно использовать для стилизации глобальных элементов, таких как интервалы, размер шрифта или цвета. Например, если вы создаете веб-сайт с большими размерами шрифта, скорее всего, шрифт и интервал будут слишком большими для экрана мобильного устройства. Это можно исправить с помощью медиа-запросов, например:
:root { --font-size-hl: 20px; --font-size-h2: 15px; --font-size-h3: 12px; --font-size-p: 8px; --letter-spacing: 8px; } @media (min-width: 300px) { :root { --font-size-hl: 13px; --font-size-h2: 10; --font-size-h3: 8px; --font-size-p: 5pxrem; --letter spacing: 4px; } }
Один из базовых примеров использование медиа-запросов, — это когда вам нужно удалить компонент со страницы. Например, посмотрите на эту домашнюю страницу Instagram:
На рабочем столе панель сообщений выглядит очень хорошо, но большинство мобильных устройств не имеют большого размера экрана, чтобы отображать ее должным образом. С помощью медиа-запросов можно удалить всю вкладку сообщения, и та же страница будет отображаться следующим образом.
Стоит отметить, что медиа-запросы предназначены не только для определения размеров экрана и того, как они влияют на компоненты.
Медиа-запросы также можно использовать для различных запросов, связанных с предпочтениями пользователя, например:
- prefers-reduced-motion
- prefers-contrast
- prefers-reduced-transparency
- prefers-color-scheme
- pointer accuracy
Когда и как использовать контейнерные запросы
Контейнерные запросы позволяют настроить таргетинг на конкретный контейнер и настроить его отображение в зависимости от ширины и высоты контейнера без использования медиазапросов. Он в основном используется для компонентов списков, но он гибкий, поэтому вы можете использовать его для нескольких компонентов.
С чистом CSS свойства, используемые в контейнерных запросах, имеют много общего со свойствами, которые вы использовали в медиа-запросах. Единственные отличительные свойства, которые вам нужно изучить, это:
container-type
: Используется для объявления элемента в качестве контейнера запросов, что позволяет дочернему компоненту запрашивать его.container-name
: Используется для присвоения имени контейнеру для дальнейшей фильтрации
Давайте посмотрим на быстрый пример карточки. Во-первых, давайте набросаем карточку с помощью HTML.
<div class="container"> <div class="contain-container contain-container--small"> <h2>first example</h2> <div class="contain"> <div class="contain__thumbnail"></div> <div class="contain__content"> <h3 class="contain__title">Lorem Ipsium in english</h3> <p class="contain__description">But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. .</p> </div> </div> </div> <div class="contain-container contain-container--large"> <h2>Second example</h2> <div class="contain"> <div class="contain__thumbnail"></div> <div class="contain__content"> <h3 class="contain__title">Lorem Ipsium in english</h3> <p class="contain__description">To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure.</p> </div> </div> </div> </div>
Текст-пустышка — это просто переведенная версия lorem ipsum.
Далее добавим CSS.
body { background: #5f64e2; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; color: #fdf2f2; } .container { padding: 16px; margin: auto; display: flex; gap: 16px; } .contain-container { margin: 16px auto; flex-grow: 0; contain: layout inline-size; container-type: inline-size; --css-contain: layout inline-size; } .contain-container--small { width: 300px; } .contain-container--large { width: 600px; } .contain { padding: 16px; border-radius: 8px; background: black; margin-bottom: 16px; color: white; } .contain__thumbnail { height: 130px; min-width: 130px; background: red; border-radius: 4px; } .contain__title { margin-top: 4px; margin-bottom: 8px; } .contain__description { margin: 0; }
Результат приведенного выше кода будет выглядеть так:
Обе карты во многом одинаковы, за исключением того, что одна имеет ширину 300 пикселей, а другая — 600 пикселей. С контейнерными запросами мы можем заставить карту правильно выглядеть и вести себя по-другому с помощью следующего кода.
@container (min-width: 400px) { .contain { background-color: white; color: black; display: flex; gap: 16px; } }
Этот код указывает любому контейнеру шириной более 400 пикселей иметь белый цвет фона, использовать display: flex и черный цвет текста. Результат будет выглядеть так:
Изменения в карточке справа применяются только в том случае, если карточка будет занимать пространство шириной ≥ 400 пикселей, поэтому, если для ее отображения недостаточно места или если она просматривается мобильным устройством, карточки вернутся. к этому.
Контейнерные запросы с CSS-in-JS
Я знаю, что JSS, или CSS-in-JS, сейчас является довольно спорной темой. Некоторые люди, например этот парень, ненавидят JSS и не хотят, чтобы вы были рядом с ним. Но другим, например этому парню, это очень нравится, и они хотят, чтобы вы использовали его.
Нравится вам JSS или нет, вы должны признать, что это очень удобно. Как и в обычном CSS, в JSS можно использовать контейнерные запросы. Вот очень простой пример того, как это работает.
Во-первых, давайте создадим четыре простых контейнера.
<div class=cquery> <h1>To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? </h1> </div> <div class=cquery style=width:80%> <h1>To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it?</h1> </div> <div class=cquery style=width:60%> <h1>To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it?</h1> </div> <div class=cquery style=width:40%> <h1>To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it?</h1> </div>
Далее добавим JSS. Я добавил несколько комментариев, чтобы было понятно.
function JSinCSS() { //target an html element with id ='JSinCSS' and declare it tag let tag = document.querySelector("#JSinCSS"); //if there is no html element with id ='#JSinCSS' if (!tag) { //create a style tag like this //<style></style> tag = document.createElement("style"); //set id of style tag to be 'JSinCSS' //<style id='JSinCSS'></style> tag.id = "JSinCSS"; //we call document.head.appendChild to append the style element to the head tag as a child. document.head.appendChild(tag); } //inside the style tag add innerHTML to it tag.innerHTML = ` body:before { content: '${innerWidth} x ${innerHeight}'; } .cquery { border: 4px solid red; background-color: green; } ${containerQuery('.cquery', 'this.offsetWidth > 500', ` $this { background: blue; } $this h1 { font-size: 30pt; } `)} ${containerQuery('.cquery', 'this.offsetWidth > 800', ` $this { background: purple; } $this h1 { font-size: 30pt; } `)} ${containerQuery('.cquery', 'this.offsetWidth > 1000', ` $this { background: gold; } $this h1 { font-size: 30pt; } `)} ` } function containerQuery(selector, test, stylesheet) { //target the container element and declare it tag var tag = document.querySelectorAll(selector); var style = ""; var count = 1; for (var i = 0; i < tag.length; i++) { //tag.length return the number of nodes in tag // run a forLoop so when i == tag.length //declare a function that returns test var func = new Function(`return ${test}`); var attr = (selector + test).replace(/[= "'><+\.]/g, ""); if (func.call(tag[i])) { tag[i].setAttribute(`data-${attr}`, count); var css = stylesheet.replace(/\$this/g, `[data-${attr}="${count}"]`); style += css; count++; } else { tag[i].setAttribute(`data-${attr}`, ""); } } return style; } //call the function in to listen to different events and call the function JSinCSS window.addEventListener("load", JSinCSS); window.addEventListener("resize", JSinCSS); window.addEventListener("input", JSinCSS); window.addEventListener("click", JSinCSS);
Приведенный выше код создает четыре разных контейнера, а затем задает контейнерный запрос с тегом containerQuery, чтобы цвета контейнеров менялись в зависимости от размера. Результат выглядит следующим образом.
Из HTML видно, что это тот же контейнер. Но при ширине ≥1000 пикселей цвет контейнера становится золотым. При ширине 800 пикселей и 500 пикселей контейнер становится фиолетовым и синим соответственно. Ниже этого он остается зеленого цвета по умолчанию. Таким образом, если эти же контейнеры должны занимать пространство ≤1000 пикселей, вы получите следующее:
Вот ссылка на CodePen, если вы хотите немного поиграть с кодом.
Заключение
Весь смысл адаптивного дизайна заключается в достижении универсальности и эффективности, а с введением контейнерных запросов мы стали на один шаг ближе к совершенству адаптивного дизайна. Он устраняет многие ограничения медиа-запросов, но не заменяет их полностью.
Лично я считаю, что медиа-запросы и контейнерные запросы подобны куриным наггетсам и острому соусу: у них обоих есть свое применение по отдельности, но вместе они потрясут ваш мир. Я надеюсь, что вы получите удовольствие от их использования.