[Веб-дизайн, Разработка веб-сайтов, CSS, Google Chrome] Контейнерные запросы в CSS (перевод)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
29-Апр-2021 05:31


Как фронтенд-дизайнер я за последние 6 лет не был так взволнован новой CSS-функцией, как сейчас. Благодаря усилиям Мириам Сюзанны и других умных людей прототип контейнерных запросов можно включить в Chrome CanaryО контейнерных запросах запомнилось много шуток, но они, наконец, здесь. В этой статье я расскажу, зачем нам нужны контейнерные запросы, как они облегчат нашу жизнь, и, самое важное, ваши компоненты и макеты станут мощнее. Если вы взволновались так же, как и я, давайте углубимся в тему. Вы готовы?Проблема с медиазапросамиВеб-страница состоит из разных разделов и компонентов, которые мы делаем отзывчивыми при помощи медиазапросов CSS. В этом нет ничего плохого, но есть ограничения. Например, мы можем написать медиазапрос, чтобы показать минимальную версию компонента на мобильном или настольном компьютере. Часто отзывчивый веб-дизайн не имеет отношения к видовому экрану или к размеру экрана. Он касается размера контейнера. Рассмотрим такой пример:
Вот очень типичный макет с компонентом — карточкой. И два варианта:
  • Стопкой (смотрите aside).
  • Горизонтально (смотрите main).
Реализовать такое на 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;
  }
}
Обратите внимание, что мы описали класс .c-article--horizontal для работы с горизонтальной версией компонента. Если ширина видового экрана больше 46rem, компонент должен переключаться на горизонтальную версию. Это не плохо, но каким-то образом заставляет ощущать себя ограниченным. Хочется, чтобы компонент реагировал на ширину своего родительского компонента, а не на видовой экран браузера или размер экрана.Считайте, что мы хотим использовать стандартную .c-c-card в разделе main. Что произойдёт? Ну, карта расширится до ширины своего родителя и, следовательно, окажется слишком большой. Посмотрите на рисунок:
Это проблема, и мы можем решить её при помощи контейнерных запросов. (Есть! наконец-то!) До погружения в тему давайте взглянем на результат.
Нам нужно сообщить компоненту, что, если непосредственная ширина родительского элемента больше 400 пикселей, ему нужно переключиться на горизонтальный стиль. CSS будет выглядеть так:
<div class="o-grid">
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
</div>
.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 пока поддерживаются только в Chrome Canary с экспериментальным флагом.
При помощи контейнерных запросов CSS  мы можем решить вышеуказанную проблему и создать растягиваемый компонент. Это означает, что мы можем вложить компонент в узкий родительский элемент, и он превратится в версию "стопкой", а в широком родительском компоненте — в горизонтальную версию. Опять же все элементы не зависят от ширины видового экрана.Вот как я представляю себе это:
Фиолетовый контур — это ширина родительского компонента. Обратите внимание, как компонент адаптируется к большему размеру своего родительского компонента. Разве это не потрясающе? Вот мощь контейнерных запросов CSS.Как работают контейнерные запросыС контейнерными запросами теперь можно поэкспериментировать в Chrome Canary. Чтобы включить их, перейдите в chrome://flags, найдите чекбокс "container queries" и отметьте его.Сначала добавим свойство contain. Компонент будет адаптироваться под родительскую ширину, поэтому нужно сказать браузеру, чтобы он перерисовал не всю страницу, а только её изменяемую область. Заранее сообщить об этом браузеру мы можем при помощи свойства contain.Значение inline-size означает, что компонент реагирует только на изменения ширины родительского элемента [прим. перев. — в случае языков с вертикальным направлением, возможно, речь идёт о высоте]. Я попытался задействовать block-size, но это свойство ещё не работает. Пожалуйста, поправьте меня, если я ошибаюсь.
<div class="o-grid">
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
  <!-- other articles.. -->
</div>
.o-grid__item {
  contain: layout inline-size;
}
Это первый шаг. Мы определили элемент .o-grid__item как родительский для .c-article. Следующий шаг — добавить желаемые стили, чтобы контейнерные запросы работали.
.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 — его ширина. Мы даже можем пойти дальше и добавить больше стилей. На видео показано, чего можно добиться от компонентов:Извините, данный ресурс не поддреживается. :( У нас есть следующие стили:
  • По умолчанию (вид карточки).
  • Горизонтальная карточка с маленьким предпросмотром.
  • Горизонтальная карточка с большим предпросмотром.
  • Если родительский компонент слишком большой, стиль будет похож на стиль раздела hero, указывая, что это избранная статья.
Давайте углубимся в примеры применения контейнерных запросов.Случаи применения контейнерных запросов CSSКонтейнерные запросы и CSS-грид с auto-fitВ некоторых случаях применение auto-fit в CSS-гриде приводит к неожиданным результатам. Например, компонент оказывается слишком широким, и его содержимое трудно читается. Дам немного контекста: вот визуальный элемент, показывающий разницу между auto-fit и auto-fill в гриде CSS:
Обратите внимание, что при использовании auto-fit элементы расширяются, чтобы заполнить доступное пространство. Однако в случае автоматического заполнения `` элементы грида не будут разрастаться, вместо этого у нас будет свободное пространство (пунктирный элемент в крайнем правом углу).Возможно, вы сейчас думаете, как этот факт относится к контейнерным запросам. Каждый элемент грида — это контейнер, и, когда он расширяется (то есть когда мы используем auto-fit), нам нужно, чтобы компонент изменился, опираясь на это расширение.
<div class="o-grid">
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
</div>
.o-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: 1rem;
}
Когда элемента четыре, результат должен выглядеть примерно так:
Что произойдёт, когда количество статей уменьшится? Чем меньше у нас будет элементов, тем они будут шире. Так происходит потому, что мы используем auto-fit. Первый выглядит хорошо, но последние два (2 на ряд, 1 на ряд) — не очень: они слишком широкие:
Что делать, если каждый компонент статьи изменяется в зависимости от ширины родительского компонента? Если так, auto-fit будет очень хорошим преимуществом. Вот что нужно сделать: если ширина элемента грида превышает 400 пикселей, статья должна переключиться на горизонтальный стиль, а добиться этого можно так:
.o-grid__item {
  contain: layout inline-size;
}
@container (min-width: 400px) {
  .c-article {
    display: flex;
    flex-wrap: wrap;
  }
}
Кроме того, если статья — единственный элемент в гриде, хочется отобразить её с разделом hero.
.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.aside и mainЧасто нам нужно настроить компонент, чтобы он работал в контейнерах небольшой ширины, таких как <aside>. Идеальный пример — раздел новостей. Когда ширина маленькая, нужно, чтобы её элементы складывались, а когда места достаточно, нужно горизонтальное расположение элементов.
Как видно на рисунке, мы работаем с разделом новостей в двух разных контекстах:
  • Раздел aside.
  • Раздел main.
Такое невозможно без контейнерных запросов, если у нас нет класса вариаций в CSS, например .newsletter--stacked или чего-то в этом роде.Я знаю, что мы можем сказать браузеру, чтобы элементы были обтекающими в случае, когда flexbox не хватает пространства, но этого недостаточно. Мне нужно гораздо больше контроля, чтобы делать кнопку во всю ширину и прятать определённые элементы:
.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.ПагинацияЯ обнаружил, что контейнерные запросы хорошо подходят для пагинации. Сначала у нас могут быть кнопки “Previous” и “Next”; если пространства достаточно, можно скрыть кнопки и показать всю нумерацию страниц. Посмотрим на рисунок ниже:
Чтобы справиться с приведёнными выше состояниями, сначала нужно поработать над стилем по умолчанию (кнопками в виде стопки), а затем — над двумя другими состояниями.
.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.Карточка профиля
Вот ещё один пример применения: контейнерные запросы идеально работают в нескольких контекстах. Состояние малого размера работает при маленьких видовых экранах и в контекстах вроде сайдбара. Состояние большого размера работает при гораздо больших контекстах, таких как размещение в гриде из двух колонок.
.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.Элементы формыЯ ещё не углублялся в случаи применения контейнерных запросов для форм, но в голове держу переключение с горизонтальных меток на метки в стопку.
.form-item {
  contain: layout inline-size;
}
.input-group {
  @container (min-width: 350px) {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    input {
      flex: 1;
    }
  }
}
Посмотрите демо на CodePen.Тестирование компонентовТеперь, когда мы рассмотрели несколько случаев, когда контейнерные запросы могут быть полезны, возникает вопрос: как протестировать компонент? К счастью, мы можем сделать это с помощью свойства родительского компонента resize.
.parent {
  contain: layout inline-size;
  resize: horizontal;
  overflow: auto;
}
Об этом методе я узнал из этой замечательной статьи Брамуса Ван Дамма.Легко ли отлаживать контейнерные запросы в DevTools?Короткий ответ — нет. Вы не увидите чего-то вроде @container (min-width: value). Я думаю, что это дело времени, поддержка такой отладки появится.А запасной вариант для браузеров без контейнерных запросов?Да! Конечно. Определённым образом можно предоставить альтернативу. Вот две замечательные статьи с объяснением, как это сделать: ЗаключениеМне понравилось изучать контейнерные запросы в CSS и играть с ними в браузере. Я знаю, что они ещё официально не поддерживаются, но сейчас для этого самое время. Часть нашей работы как фронтендеров заключается в том, чтобы тестировать функции браузеров и помогать работающим над их реализацией людям. Чем лучше протестирована экспериментальная функциональность, тем меньше проблем мы увидим, когда она станет поддерживаться во всех основных браузерах.Если вы уже имеете некоторые навыки работы с CSS, но всё ещё не можете сказать, что разбираетесь во фронтенде — можете обратить внимание на наш курс-профессию Frontend-разработчик, где вы сможете научиться создавать адаптивные веб-сайты с использованием CSS, Flexbox, разрабатывать интерактивные веб-сайты и приложения на JS и HTML, а также писать сложные компоненты на React и интерфейсы с авторизацией и с подключением к бэкенду.
Ну а если фронтенд для вас давно родная стихия — пора смотреть в сторону Fullstack-разработчика, настоящего универсала веб-разработки, которому будут рады в любом крупном проекте.
Узнайте, как прокачаться и в других специальностях или освоить их с нуля: Другие профессии и курсыПРОФЕССИИ КУРСЫ
===========
Источник:
habr.com
===========

===========
Автор оригинала: Ahmad Shadeed
===========
Похожие новости: Теги для поиска: #_vebdizajn (Веб-дизайн), #_razrabotka_vebsajtov (Разработка веб-сайтов), #_css, #_google_chrome, #_skillfactory, #_css, #_html, #_vebdizajn (веб-дизайн), #_chrome_canary, #_eksperimentalnye_funktsii (экспериментальные функции), #_kontejnernye_zaprosy (контейнерные запросы), #_grid (грид), #_novye_svojstva_css (новые свойства css), #_bez_mediazaprosov (без медиазапросов), #_blog_kompanii_skillfactory (
Блог компании SkillFactory
)
, #_vebdizajn (
Веб-дизайн
)
, #_razrabotka_vebsajtov (
Разработка веб-сайтов
)
, #_css, #_google_chrome
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 19:14
Часовой пояс: UTC + 5