Контейнерные запросы (Container Queries)

Тренажер по CSS для пользователей с начальным уровнем подготовки.

Тренажер CSS

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

Список тем

Определение контейнера

Чтобы использовать контейнерные запросы для элемента, сначала нужно указать, что его родитель является контейнером. Задайте для родительского элемента `.card-container` свойство, которое позволит отслеживать его размеры для применения контейнерных запросов.

CSS
.card-container {
  /* input1: inline-size; */
  input1: inline-size;
  border: 2px solid #ccc;
  padding: 10px;
  resize: horizontal; /* Позволяет менять размер вручную для теста */
  overflow: auto; /* Обязательно для resize */
  max-width: 350px; /* Ограничим максимальную ширину */
  min-width: 150px;
}

.card {
  background-color: #f0f0f0;
  padding: 15px;
  border-radius: 5px;
}
HTML
<div class="card-container">
  <div class="card">
    Привет! Я карточка внутри контейнера.
  </div>
</div>
Используйте свойство `container-type`, чтобы объявить элемент контейнером. Значение `inline-size` указывает, что запросы будут основываться на ширине контейнера.
Заполнить ответами все поля
Результат
Сообщения
Выполнить
Отметить решенным
Показать подсказку

Простой контейнерный запрос

Теперь, когда у нас есть контейнер, напишем простой запрос. Измените цвет фона `.card` на `lightblue`, когда ширина родительского `.card-container` превышает 250px. Допишите недостающую часть правила `@container`.

CSS
.card-container {
  container-type: inline-size;
  border: 2px solid #ccc;
  padding: 10px;
  resize: horizontal;
  overflow: auto;
  max-width: 350px;
  min-width: 150px;
}

.card {
  background-color: #f0f0f0;
  padding: 15px;
  border-radius: 5px;
  transition: background-color 0.3s ease;
}

/* input1 (min-width: 250px) { */
input1 (min-width: 250px) {
  .card {
    background-color: lightblue;
  }
}
HTML
<div class="card-container">
  <div class="card">
    Мой фон изменится при ширине контейнера > 250px.
  </div>
</div>
Используйте правило `@container`, чтобы определить контейнерный запрос. Условие пишется в скобках, например `(min-width: 250px)`.
Заполнить ответами все поля
Результат
Сообщения
Выполнить
Отметить решенным
Показать подсказку

Условие в контейнерном запросе

Контейнерные запросы позволяют использовать разные условия. В этом задании измените размер шрифта `.card` на `18px`, когда ширина контейнера `.card-container` *меньше* 200px. Заполните пропуск в условии запроса.

CSS
.card-container {
  container-type: inline-size;
  border: 2px solid #ccc;
  padding: 10px;
  resize: horizontal;
  overflow: auto;
  max-width: 350px;
  min-width: 150px;
}

.card {
  background-color: #f0f0f0;
  padding: 15px;
  border-radius: 5px;
  font-size: 16px;
  transition: font-size 0.3s ease;
}

/* @container (input1: 200px) { */
@container (input1: 200px) {
  .card {
    font-size: 18px; /* Увеличим шрифт в узком контейнере */
  }
}
HTML
<div class="card-container">
  <div class="card">
    Мой шрифт изменится при ширине контейнера < 200px.
  </div>
</div>
Для задания условия "меньше чем" используйте `max-width`. Например, `(max-width: 200px)` сработает, когда ширина контейнера будет 200px или меньше.
Заполнить ответами все поля
Результат
Сообщения
Выполнить
Отметить решенным
Показать подсказку

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

Иногда на странице может быть несколько контейнеров, и нужно применять запросы к конкретному. Задайте имя `my-card-box` для контейнера `.card-container` и используйте это имя в запросе `@container`, чтобы изменить границу `.card` на `2px solid green`, когда ширина *именованного* контейнера превышает 300px.

CSS
.card-container {
  /* container: input1 / inline-size; */
  container-type: inline-size;
  input1: my-card-box;
  border: 2px solid #ccc;
  padding: 10px;
  resize: horizontal;
  overflow: auto;
  max-width: 350px;
  min-width: 150px;
}

.card {
  background-color: #f0f0f0;
  padding: 15px;
  border: 2px solid transparent; /* Изначально прозрачная граница */
  border-radius: 5px;
  transition: border-color 0.3s ease;
}

/* @container input2 (min-width: 300px) { */
@container input2 (min-width: 300px) {
  .card {
    border-color: green;
  }
}
HTML
<div class="card-container">
  <div class="card">
    Моя граница изменится при ширине контейнера 'my-card-box' > 300px.
  </div>
</div>
Используйте свойство `container-name`, чтобы дать имя контейнеру. Затем в запросе `@container` укажите это имя перед условием, например `@container my-name (min-width: ...)`. Также можно использовать сокращенное свойство `container`, объединив тип и имя: `container: my-name / inline-size;`.
Заполнить ответами все поля
Результат
Сообщения
Выполнить
Отметить решенным
Показать подсказку

Сокращенное свойство container

Свойства `container-type` и `container-name` можно объединить в одно сокращенное свойство `container`. Задайте для `.widget-box` одновременно тип `inline-size` и имя `widget` с помощью сокращенного свойства. Затем примените стиль `font-weight: bold;` к `.widget-content`, когда ширина контейнера `widget` будет больше 200px.

CSS
.widget-box {
  /* input1: widget / inline-size; */
  input1: widget / inline-size;
  border: 2px dashed blue;
  padding: 15px;
  resize: horizontal;
  overflow: auto;
  max-width: 350px;
  min-width: 150px;
}

.widget-content {
  background-color: #e0e0ff;
  padding: 10px;
}

/* @container input2 (min-width: 200px) { */
@container input2 (min-width: 200px) {
  .widget-content {
    font-weight: bold;
  }
}
HTML
<div class="widget-box">
  <div class="widget-content">
    Я стану жирным, когда контейнер 'widget' шире 200px.
  </div>
</div>
Используйте свойство `container` со значением в формате `имя / тип` или `тип / имя`. Например: `container: widget / inline-size;`. Затем используйте имя в запросе: `@container widget (...)`.
Заполнить ответами все поля
Результат
Сообщения
Выполнить
Отметить решенным
Показать подсказку

Контейнерные единицы cqw

Контейнерные запросы вводят новые единицы измерения, относительные к размерам контейнера. Единица `cqw` представляет 1% ширины контейнера. Установите размер шрифта для `.resizable-text` равным `5cqw`. Обратите внимание, как размер шрифта будет меняться при изменении ширины контейнера.

CSS
.text-container {
  container-type: inline-size;
  container-name: text-box;
  border: 2px solid green;
  padding: 10px;
  resize: horizontal;
  overflow: auto;
  max-width: 350px;
  min-width: 100px;
}

.resizable-text {
  background-color: #e0ffe0;
  padding: 5px;
  /* font-size: input1; */
  input1: 5cqw;
}
HTML
<div class="text-container">
  <span class="resizable-text">
    Мой размер шрифта зависит от ширины контейнера (5cqw).
  </span>
</div>
Используйте единицу `cqw` для задания значения свойства, зависящего от ширины контейнера. Например: `font-size: 5cqw;`.
Заполнить ответами все поля
Результат
Сообщения
Выполнить
Отметить решенным
Показать подсказку

Комбинирование условий

В контейнерных запросах можно комбинировать несколько условий с помощью логического оператора `and`. Сделайте так, чтобы изображение `.card-img` отображалось (`display: block;`), только когда ширина контейнера `.card-container` находится в диапазоне от 200px до 300px.

CSS
.card-container {
  container: card-area / inline-size;
  border: 2px solid #ccc;
  padding: 10px;
  resize: horizontal;
  overflow: auto;
  max-width: 350px;
  min-width: 150px;
}

.card-content {
  background-color: #f0f0f0;
  padding: 15px;
  border-radius: 5px;
}

.card-img {
  display: none; /* Скрыто по умолчанию */
  width: 100%;
  height: auto;
  margin-top: 10px;
}

/* @container card-area (min-width: 200px) input1 (max-width: 300px) { */
@container card-area (min-width: 200px) input1 (max-width: 300px) {
  .card-img {
    display: block;
  }
}
HTML
<div class="card-container">
  <div class="card-content">
    Картинка появится, когда контейнер будет от 200px до 300px шириной.
    <img src="https://naytikurs.ru/img/7.png" alt="Image" class="card-img">
  </div>
</div>
Используйте оператор `and` для объединения условий `min-width` и `max-width` в одном запросе `@container`. Пример: `@container (min-width: 200px) and (max-width: 300px)`.
Заполнить ответами все поля
Результат
Сообщения
Выполнить
Отметить решенным
Показать подсказку

Адаптивная карточка товара

Создадим адаптивную карточку товара. В узком контейнере (< 280px) изображение и текст должны располагаться друг под другом (flex-direction: column). В более широком контейнере (>= 280px) они должны встать в ряд (flex-direction: row). Заполните пропуски: укажите тип контейнера и условие в запросе `@container`.

CSS
.product-card {
  /* input1: inline-size; */
  input1: inline-size;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
  resize: horizontal;
  padding: 10px;
  max-width: 360px;
  min-width: 150px;
}

.card-body {
  display: flex;
  flex-direction: column; /* По умолчанию - колонка */
  gap: 10px;
}

.card-img {
  width: 80px;
  height: 80px;
  object-fit: cover;
  flex-shrink: 0;
}

.card-text {
  flex-grow: 1;
}

/* @container (input2: 280px) { */
@container (input2: 280px) {
  .card-body {
    /* input3: row; */
    input3: row;
    align-items: center;
  }
}
HTML
<div class="product-card">
  <div class="card-body">
    <img src="https://naytikurs.ru/img/1.png" alt="Product" class="card-img">
    <div class="card-text">
      <h4>Название товара</h4>
      <p>Краткое описание товара здесь.</p>
    </div>
  </div>
</div>
Объявите `.product-card` как контейнер с типом `inline-size`. В запросе `@container` используйте условие `min-width: 280px`, чтобы применить стили для широкого контейнера. Внутри запроса измените `flex-direction` у `.card-body` на `row`.
Заполнить ответами все поля
Результат
Сообщения
Выполнить
Отметить решенным
Показать подсказку
НайтиКурс.Ру