Что если использовать контейнерные единицы измерения для... всего?

alexei14/03/2025 - 09:00
Что если использовать контейнерные единицы измерения для... всего?

Как-то подумалось, а что, если использовать контейнерные единицы измерения для каждого элемента в дизайне? Наверное, тогда, всё будет хорошо масштабироваться. Контейнерные единицы измерения, если вы о них не слышали, это такие же единицы измерения (вроде, px или rem, но более тесно связанные с единицами измерения области просмотра, например, vw или vi), размер которых зависит от контейнера, в котором они находятся.

Оказалось, сюрприз-сюрприз, все не так просто. Есть множество вещей, с которыми контейнерные запросы работают плохо, или для которых они просто не подходят.

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

Потенциальная проблема: Нельзя задать стили для элемента запроса

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


.card-wrap {
  container: cardWrap / inline-size;

  padding: 2cqi;
  border-radius: 4cqi;

  .card {
    border-radius: 4cqi;
  }
}

При использовании приведенного выше кода border-radius будет отличаться, несмотря на то, что выглядит так же, потому что контейнер, к которому относятся единицы измерения, отличается.

Внутренний радиус у большой карточке выглядит по другому
Обратите внимание, что внешний радиус совпадает, но внутренняя часть карточки отличается и выглядит иначе

Потенциальное решение: Не задавать стили в контейнере

Будьте внимательны! Если вы будете последовательны, когда при определении свойства container вы не будете использовать другие стили, основанные на размере, то это избавит вас от лишней головной боли. Если это означает добавление дополнительного оберточного элемента <div>, который в противном случае не нужен, что ж, это не супер идеальный вариант, так как вес DOM все же имеет значение, но, вероятно, это будет вполне нормально.

Потенциальная проблема: Слишком большой и слишком маленький

Если контейнерные единицы измерения используются только для чего-то вроде управления размером шрифта (например, font-size), то довольно легко попасть в ситуацию, когда текст и текстовые элементы в конечном итоге получаются либо слишком большими, либо слишком маленькими.

Слишком большой и слишком маленький текст
Текст на большой карточке кажется слишком большим, но теги нормальные. Текст на маленькой карточке нормальный, но теги слишком маленькие

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

Использование только контейнерных единиц измерения (или единиц измерения области просмотра) для определения размера текста - плохая практика. Однако это можно исправить.

Потенциальное решение: Функция clamp()

Чтобы текст не был слишком маленьким или слишком большим, достаточно использовать CSS функцию clamp(). При этом, мы можем добавить относительные единицы измерения, чтобы учесть предпочтения пользователей в отношении размера шрифта.

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


.tag {
  /* Плохо */
  font-size: 4cqi;

  /* Хорошо */
  font-size: clamp(16px, 4cqi + 0.5rem, 24px);
}

Потенциальная проблема: Строки vs Столбцов

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

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

Ширина иконок не попадает в ширину колонки

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

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

Сильное изменение размера иконок при изменении ширины макета

Потенциальное решение: Использование других единиц измерения

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

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


.actions {
  container: actions / inline-size;

  svg {
    display: block;
    width: 4cqmax;
    min-width: 24px;
    max-width: 100%;
    aspect-ratio: 1;
  }
}

Но… нет. Это слишком странно. Можно сказать, что здесь лучше использовать относительные единицы измерения, пиксели или что-то в этом роде.

В конце концов, если контейнерные единицы измерения помогут добиться вам нужного эффекта масштабирования в зависимости от размера элемента, используйте их! Поддержка браузерами уже хорошая. Но не переусердствуйте.

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