CSS-свойство aspect-ratio

Соотношение сторон (aspect-ratio) обычно выражается двумя целыми числами с двоеточием: width:height или x:y. Наиболее распространенные соотношения сторон для фотографий — 4:3 и 3:2, а видео, как правило, имеют соотношение сторон 16:9 или 4:3.

aspect-ratio
Два изображения с одинаковым соотношением сторон. У одного размеры 634×951 пикселей, а у другого — 200×300 пикселей. У обоих соотношение сторон 2:3.

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

  • iframe, ширина которого 100% от родительской ширины, а высота должна быть пропорциональна ширине.
  • подготовка контейнеров для изображений, видео и встраиваемых материалов для предотвращения дёргания и перестройки макета, по мере их загрузки
  • единообразное адаптивное пространство для интерактивной визуализации данных (графиков и т.п.) или SVG-анимации
  • единообразное адаптивное пространство для многоэлементных компонентов, например — карточки или календарики с датами.
  • единообразное адаптивное пространство для нескольких изображений разного размера (можно использовать вместе с object-fit)

Встраивание изображений

Определение соотношения сторон помогает устанавливать размеры медиа в адаптивном контексте. Один из инструментов в этом сегменте — css-свойство object-fit, которое позволяет указывать, как объект (например, изображение) внутри блока должен заполнить этот блок:

See this code object-fit on x.xhtml.ru.

Значения initial и fill искажают изображение, чтобы заполнить пространство. Это приводит к тому, что изображение может оказаться становится сжатым и размытым. Не идеально.

object-fit: cover использует размер меньшей из сторон изображения, чтобы заполнить пространство, затем обрезает картинку, чтобы поместить ее в контейнер.

object-fit: contain гарантирует, что всё изображение всегда будет видимым. Это — противоположность cover, для вычисления здесь используется большая из сторон, а размеры изображения изменяются так, чтобы сохранить его внутреннее соотношение сторон и вписать его в отведенное пространство.

В случае object-fit: none изображение обрезается по центру (положение объекта по умолчанию) с естественным размером.

object-fit: cover часто используется для обеспечения хорошего единообразного интерфейса при работе с изображениями разных размеров, однако при этом может теряться часть информации (изображение обрезается по самым длинным краям).

Если какие-то детали на картинке важны (например, при работе с плоской укладкой косметических товаров), обрезка важного контента может оказаться недопустимой. Таким образом, идеальным вариантом были бы адаптивные изображения разных размеров, которые соответствовали бы пространству пользовательского интерфейса без обрезки.

Старый прием: сохранение соотношения сторон с padding-top

padding-top
Использование padding-top для установки соотношения сторон 1:1 для изображений предварительного просмотра публикации в карусели.

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

До настоящего времени широко распространенно кроссбраузерное решение для поддержания соотношения сторон в зависимости от ширины изображения, известное, как «Padding-Top Hack». Для этого решения требуется родительский контейнер и абсолютно спозиционированный дочерний контейнер. Далее требуется рассчитать соотношение сторон в процентах, чтобы установить его как верхнюю часть поля (padding-top). Например:

  • отношение сторон 1:1 = 1 / 1 = 1 = padding-top: 100%
  • отношение сторон 4:3 = 3 / 4 = 0.75 = padding-top: 75%
  • отношение сторон 3:2 = 2 / 3 = 0.66666 = padding-top: 66.67%
  • отношение сторон 16:9 = 9 / 16 = 0.5625 = padding-top: 56.25%

Теперь, когда разобрались со значениями соотношения сторон, их можно применить родительскому контейнеру. Рассмотрим следующий пример:

<div class="container">
  <img class="media" src="..." alt="..." />
</div>

R этому html-коду подойдёт следующий CSS:

.container {
  position: relative;
  width: 100%;
  padding-top: 56.25%; /* отношение 16:9 */
}

.media {
  position: absolute;
  top: 0;
}

Обеспечение соотношения сторон с помощью aspect-ratio

aspect-ratio
Использование aspect-ratio для установки соотношения сторон 1:1 изображениям предварительного просмотра сообщений в карусели.

Вычисление значения padding-top не очень интуитивно понятно и требует применение позиционирования. С помощью нового css-свойства aspect-ratio отношение сторон такая же задача решается иначе.

Для html-разметки из примера выше следует заменить padding-top: 56.25% на aspect-ratio: 16 / 9, т.е. указать реальное отношение width / height.

.container {
  position: relative;
  width: 100%;
  padding-top: 56.25%; /* отношение 16:9 */
  aspect-ratio: 16 / 9; /* отношение 16:9 */
}

.media {
  position: absolute;
  top: 0;
}

Использование aspect-ratio вместо padding-top намного понятнее и оставляет для свойства padding его обычное поведение.

Для свойства aspect-ratio можно установить для соотношения сторон значение auto, где «замененные элементы с внутренним соотношением сторон используют это соотношение сторон; в противном случае блок не имеет предпочтительного соотношения сторон». Если указать одновременно значения auto и <ratio>, то предпочтение будет соотношению сторон, определяемому делением width на height, если только это не замещаемый элемент с внутренним соотношением сторон (в этом случае используется его собственное соотношение сторон).

Пример согласованности в сетке (grid)

Этот пример чётко работает с механизмами компоновки, такими как CSS Grid и Flexbox. Рассмотрим список с дочерними элементами, для которых требуется сохранить соотношение сторон 1:1, например сетку логотипов спонсоров:

<ul class="sponsor-grid">
  <li class="sponsor">
    <img src="..." alt="..." />
  </li>
  <li class="sponsor">
    <img src="..." alt="..." />
  </li>
</ul>
.sponsor-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}

.sponsor img {
  aspect-ratio: 1 / 1;
  width: 100%;
  object-fit: contain;
}
Изображения в сетке внутри родительского элемента с разным соотношением сторон.

See this code Sponsor Logos Aspect Ratio Demo on x.xhtml.ru.

Пример предотвращения сдвига макета

Еще одна замечательная особенность css-свойства aspect-ratio — оно предоставляет возможность реализовать блоки-заглушки (placeholder) для предотвращения сдвига макета (CLS — Cumulative Layout Shift) и предоставления качественных веб-показателей. В первом примере демонстрируется загрузка ресурса из API и получается сдвиг макета, когда загрузка мультимедиа завершится. Проще говоря, текст и блоки страницы скачут и перемещаются, до тех пор, пока все ресурсы загружаются.

Видео о совокупном сдвиге макета, который происходит, когда для контейнера загружаемого ресурса не установлено соотношение сторон. Это видео записано с помощью эмуляции медленного соединения — сети 3G.

Применение css-свойства aspect-ratio устанавливает контейнеру ожидаемое соотношение сторон и предотвращает сдвиг макета после загрузки мультимедиа:

img {
  width: 100%;
  aspect-ratio: 8 / 6;
}
Видео c предустановленным для контейнера загружаемого ресурса aspect-ratio. Это видео записано с помощью эмуляции медленного соединения — сети 3G.

See this code Aspect-Ratio Demo on x.xhtml.ru.

Пример использования атрибутов изображения для указания соотношения сторон

Альтернативный способ установить соотношение сторон изображению — использовать его атрибуты. Если заранее известны размеры изображения, можно установить их, c помощью атрибутов width и height.

Например, если известно, что размеры изображения составляют 800px на 600px, код разметки для него будет выглядеть так: <img src = "image.jpg" alt = "..." width = "800" height = "600">. Тогда, если у отправленного изображения будет такое же соотношение сторон, даже не обязательно с точно такими же значениями в пикселях, можно использовать значения атрибутов изображения для установки соотношения в сочетании с css-свойствами width: 100% и height: auto, чтобы изображение занимало отведенное пространство. Все вместе это будет выглядеть так:


<img src="image.jpg" alt="..." width="8" height="6">
/* CSS */
img {
  width: 100%;
  height: auto;
}

В этом случае, эффект будет таким же, как при установке соотношения сторон изображения с помощью CSS aspect-ratio, и получится избежать кумулятивного сдвига макета.

See this code Image Size Demo on x.xhtml.ru.

Завершение

С новым CSS-свойством aspect-ratio, которое уже работает в нескольких современных браузерах, поддержка правильных соотношений сторон в контейнерах мультимедиа и макета становится проще и понятнее.