Скажите привет контейнерным запросам CSS — Блог о самом интересном.

От автора: сегодня я более взволнован новой функциональностью CSS, чем когда либо за последние шесть лет, которые я провел в качестве фронтенд-разработчика. Прототип контейнерных запросов теперь доступен в Chrome Canary.

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

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

Часто отзывчивый веб-дизайн не зависит от области просмотра или размера экрана. Дело в размере контейнера. Рассмотрим следующий пример:

У нас очень типичный макет. Имеется два варианта компонентов: вложенный и горизонтальный.

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

CSS .c-article { /* The default, stacked version */

}

.c-article > * + * { margin-top: 1rem;

}

/* The horizontal version */ @media (min-width: 46rem) { .c-article—horizontal { display: flex; flex-wrap: wrap;

}

.c-article > * + * { margin-top: 0;

}

.c-article__thumb { margin-right: 1rem; }

}

1234567891011121314151617181920212223 .c-article {  /* The default, stacked version */} .c-article > * + * {  margin-top: 1rem;} /* The horizontal version */@media (min-width: 46rem) {  .c-article—horizontal {    display: flex;    flex-wrap: wrap;  }   .c-article > * + * {    margin-top: 0;  }   .c-article__thumb {    margin-right: 1rem;  }}

Обратите внимание, что мы создали класс .c-article—horizontal для обработки горизонтальной версии компонента. Если ширина области просмотра больше 46 rem, компонент должен переключиться на горизонтальное отображение.

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

Учтите, что мы хотим использовать значение по умолчанию .c-card в основном разделе. Что случится? Что ж, компонент расширится до ширины свого родительского и, следовательно, будет слишком большой. см. следующий рисунок:

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

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

123456789101112                                     

CSS .o-grid__item { contain: layout inline-size;

}

.c-article { /* The default style */

}

@container (min-width: 400px) { .c-article { /* The styles that will make the article horizontal** ** instead of a card style.. */ }

}

1234567891011121314 .o-grid__item {  contain: layout inline-size;} .c-article {  /* The default style */} @container (min-width: 400px) {  .c-article {    /* The styles that will make the article horizontal**        ** instead of a card style.. */  }}

Отечественные сайты чаще всего используют российские доменные зоны

Как нам помогут контейнерные запросы CSS?

Предупреждение: контейнерные запросы CSS пока поддерживаются только в Chrome Canary.

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

Вот как я это себе представляю.

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

Как работают контейнерные запросы

Теперь мы можем поэкспериментировать с контейнерными запросами Chrome Сanary. Чтобы включить возможность контейнерных запросов, введите в адресной строке chrome://flags и выполните поиск по запросу «container queries», а затем включите их.

Первый шаг – добавить свойство contain. Поскольку компонент будет адаптироваться в зависимости от его родительской ширины, нам нужно указать браузеру перерисовывать только затронутую область, а не всю страницу. С помощью свойства contain мы можем сообщить об этом браузеру заранее.

Значение inline-size означает реагирование только на изменение ширины родительского элемента. Я пробовал использовать block-size, но он все еще не работает. Пожалуйста, поправьте меня, если я ошибаюсь.

12345678910111213                                       

CSS .o-grid__item { contain: layout inline-size;

}

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

Это первый шаг. Мы определили элемент .o-grid__item как родительский элемент для .c-article который внутри него. Следующим шагом является добавление стилей, которые мы хотим заставить работать с контейнерными запросами.

CSS .o-grid__item { contain: layout inline-size;

}

@container (min-width: 400px) { .c-article { display: flex; flex-wrap: wrap;

}

/* other CSS.. */
}

123456789101112 .o-grid__item {  contain: layout inline-size;} @container (min-width: 400px) {  .c-article {    display: flex;    flex-wrap: wrap;  }   /* other CSS.. */}

@container является элементом .o-grid__item, а его ширина min-width: 400px. Мы даже можем пойти дальше и добавить больше стилей. У нас есть следующие стили:

По умолчанию.

Горизонтальная карточка с маленькой миниатюрой.

Горизонтальная карточка с большой миниатюрой.

Если родительский объект слишком велик, стиль будет указать нам, что это избранная статья.

Давайте рассмотрим варианты использования контейнерных запросов CSS.

Примеры использования контейнерных запросов CSS

Контейнерные запросы и CSS-сетка auto-fit

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

Обратите внимание, что при использовании auto-fit элементы расширяются, чтобы заполнить доступное пространство. Однако в случае auto-fill, элементы сетки не будут расти, и вместо этого у нас будет свободное место (пунктирный элемент справа).

Теперь вы можете спросить, какое отношение это имеет к контейнерным запросам CSS? Что ж, каждый элемент сетки — это контейнер, и когда он расширяется (мы также используем auto-fit), нам нужно, чтобы компонент изменялся в зависимости от контейнера.

Прикрепленные элементы сетки в CSS

1234567891011121314                                 

CSS .o-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-gap: 1rem;

}

12345 .o-grid {  display: grid;  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));  grid-gap: 1rem;}

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

Ситуация изменится, когда количество статей станет меньше, вот что произойдет. Чем меньше у нас предметов, тем они станут шире. Причина в том, что используется auto-fit. Первый выглядит хорошо, но два последних (по 2 в ряду, по 1 в ряду) выглядят не очень хорошо, так как они слишком широкие.

Что, если каждый компонент статьи изменяется в зависимости от ширины его родительского элемента? Таким образом, мы можем извлечь выгоду от использования auto-fit. Вот что нам нужно сделать.

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

CSS .o-grid__item { contain: layout inline-size;

}

@container (min-width: 400px) { .c-article { display: flex; flex-wrap: wrap; }

}

12345678910 .o-grid__item {  contain: layout inline-size;} @container (min-width: 400px) {  .c-article {    display: flex;    flex-wrap: wrap;  }}

Кроме того, если статья является единственным элементом в сетке:

CSS .o-grid__item { contain: layout inline-size;

}

@container (min-width: 700px) { .c-article { display: flex; justify-content: center; align-items: center; min-height: 350px;

}

.card__thumb { position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover; }

}

123456789101112131415161718192021 .o-grid__item {  contain: layout inline-size;} @container (min-width: 700px) {  .c-article {    display: flex;    justify-content: center;    align-items: center;    min-height: 350px;  }   .card__thumb {    position: absolute;    left: 0;    top: 0;    width: 100%;    height: 100%;    object-fit: cover;  }}

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

Боковая и главная панели

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

Как вы видите на рисунке, у нас есть информационный бюллетень, который существует в двух разных контекстах: боковой раздел и основной раздел.

Без контейнерных запросов это невозможно, пока у нас не будет класса вариаций в CSS, например, .newsletter—stacked или что-то в этом роде.

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

Скрыть определенные элементы.

Сделать кнопку полной ширины.

CSS .newsletter-wrapper { contain: layout inline-size;

}

/* The default, stacked version */ .newsletter { /* CSS styles */

}

.newsletter__title { font-size: 1rem;

}

.newsletter__desc { display: none;

}

/* The horizontal version */ @container (min-width: 600px) { .newsletter { display: flex; justify-content: space-between; align-items: center;

}

.newsletter__title { font-size: 1.5rem;

}

.newsletter__desc { display: block; }

}

123456789101112131415161718192021222324252627282930313233 .newsletter-wrapper {  contain: layout inline-size;} /* The default, stacked version */.newsletter {  /* CSS styles */} .newsletter__title {  font-size: 1rem;} .newsletter__desc {  display: none;} /* The horizontal version */@container (min-width: 600px) {  .newsletter {    display: flex;    justify-content: space-between;    align-items: center;  }   .newsletter__title {    font-size: 1.5rem;  }   .newsletter__desc {    display: block;  }}

Посмотрите демонстрацию на CodePen.

Пагинация

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

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

CSS .wrapper { contain: layout inline-size;

}

@container (min-width: 250px) { .pagination { display: flex; flex-wrap: wrap; gap: 0.5rem;

}

.pagination li:not(:last-child) { margin-bottom: 0; }

}

@container (min-width: 500px) { .pagination { justify-content: center;

}

.pagination__item:not(.btn) { display: block;

}

.pagination__item.btn { display: none; }

}

1234567891011121314151617181920212223242526272829 .wrapper {  contain: layout inline-size;} @container (min-width: 250px) {  .pagination {    display: flex;    flex-wrap: wrap;    gap: 0.5rem;  }   .pagination li:not(:last-child) {    margin-bottom: 0;  }} @container (min-width: 500px) {  .pagination {    justify-content: center;  }   .pagination__item:not(.btn) {    display: block;  }   .pagination__item.btn {    display: none;  }}

Посмотрите демонстрацию на CodePen.

Карточка профиля

Вот еще один вариант, который идеально подходит для использования в нескольких контекстах. Маленькое состояние работает для небольших размеров области просмотра и контекстов, таких как боковая панель. Большое состояние работает в гораздо более широком контексте, например, при размещении ее в сетке с двумя столбцами.

CSS .p-card-wrapper { contain: layout inline-size;

}

.p-card { /* Default styles */

}

@container (min-width: 450px) { .meta { display: flex; justify-content: center; gap: 2rem; border-top: 1px solid #e8e8e8; background-color: #f9f9f9; padding: 1.5rem 1rem; margin: 1rem -1rem -1rem;

}

/* and other styles */
}

123456789101112131415161718192021 .p-card-wrapper {  contain: layout inline-size;} .p-card {  /* Default styles */} @container (min-width: 450px) {  .meta {    display: flex;    justify-content: center;    gap: 2rem;    border-top: 1px solid #e8e8e8;    background-color: #f9f9f9;    padding: 1.5rem 1rem;    margin: 1rem -1rem -1rem;  }   /* and other styles */}

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

Посмотрите демонстрацию на CodePen.

Элементы формы

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

CSS .form-item { contain: layout inline-size;

}

.input-group { @container (min-width: 350px) { display: flex; align-items: center;

gap: 1.5rem;

input { flex: 1; } }

}

123456789101112131415 .form-item {  contain: layout inline-size;} .input-group {  @container (min-width: 350px) {    display: flex;    align-items: center;    gap: 1.5rem;     input {      flex: 1;    }  }}

Попробуйте сами в демонстрации ниже. Посмотрите демонстрацию на CodePen.

Компоненты тестирования

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

CSS .parent { contain: layout inline-size; resize: horizontal; overflow: auto;

}

12345 .parent {  contain: layout inline-size;  resize: horizontal;  overflow: auto;}

Пока что вы не можете увидеть что-то вроде @container (min-width: value). Думаю, это вопрос времени, и это будет реализовано.

Заключение

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

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

Автор: Ahmad Shadeed

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен

Источник

Вам также может понравиться