От автора: мне одному кажется, что большую часть времени изучение новых возможностей CSS приводит к изучению не только принципа работы одного конкретного свойства, а набора свойств и того, как они работают вместе? А порой и изучения всей спецификации. Нет, я не жалуюсь: понятное дело, что свойства нужно рассматривать как часть экосистемы. Но признаюсь, я обожаю, когда новое CSS свойство появляется в браузерах, и его изучение не требует много сил, и все просто работает.
Свойство aspect-ratio отвечает всем этим требованиям и решает все глупые костыли (соотношение сторон) одной строкой. Свойство поддерживается уже год, но уверенно его использовать мы смогли только после релиза для Safari в сентябре 2021.
Padding хак, прощай
Раньше для соблюдения элементами соотношения сторон нам нужно было писать довольно страшный CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
.aspect-box { position: relative; } .aspect-box::before { display: block; content: ''; width: 100%; padding-bottom: calc(100% / (var(--aspect-ratio, 3 / 2))); } .aspect-box > :first-child { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } |
Этот способ назывался паддинг хак потому что, ну, он именно это и делает. Кастомное свойство отрезает повторение на случай, если нужно более одного соотношения сторон. Никто в здравом уме не хочет писать так. С помощью Ratio Buddy можно сгенерировать Sass сниппет.
Практическое использование aspect-ratio
Работа с aspect-ratio гораздо проще: указываете ширину и высоту соотношения сторон через слэш или укажите число с плавающей точкой. 2 примера соотношения сторон ниже работают одинаково:
1 2 3 4 5 6 7 |
.aspect-box { aspect-ratio: 3 / 2; } .aspect-box { aspect-ratio: 1.5; } |
Ширину и высоту можно явно указать для элемента, и aspect-ratio будет работать ровно так, как вы ожидаете: если какое-то разрешение не указано, оно автоматически определится по соотношению сторон. Если указать для ширины и высоты не auto, то соотношение сторон больше не применяется. Это не баг. Так и задумано, это удобно.
Увеличение размеров элемента и подстройка под содержимое
aspect-ratio умеет изменять размер относительно дочерних элементов и родительских. Это значит, что он подстраивается как под контент, так и под контекст. Все 3 блока ниже имеют соотношение сторон 2 / 1 и явно заданную ширину. Текст в третьем блоке не помещается, из-за чего блок вертикально расширяется, подстраиваясь под контент.
Если вместо ширины явно указать высоту, то элемент не будет расширяться. Вместо этого текст выйдет за пределы элемента (можно поправить с помощью свойства overflow).
Соотношение сторон изображений и object-fit
Сила aspect-ratio раскрывается при работе изменении размеров изображений в сочетании с object-fit. С помощью object-fit: cover можно создать превью как для галереи изображений:
Или можно использовать object-fit: contain для сетки логотипов.
Нужно добавить, что object-fit обязательно требует явно заданной ширины и высоты элемента, чтобы «подогнать» размеры. Разберем разметку ниже (изображение внутри блока с соотношением сторон):
1 2 3 |
<div class="aspect-box"> <img src="https://images.unsplash.com/photo..." alt="Robin on a log" /> </div> |
Чтобы изображение целиком заполнило родительский блок, необходимо написать следующие стили:
1 2 3 4 5 6 |
img { display: block; width: 100%; height: 100%; object-fit: cover; } |
Довольно часто требуется поместить что-то в блок с соотношением сторон, как выше. Однако блок-обертку можно было опустить и добавить свойство aspect-ratio прямо на изображение вместо height или width:
1 2 3 4 5 6 |
img { display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: cover; } |
Блоки с соотношением сторон в контексте
В демо выше для галереи используется Grid или Flexbox. Все работает, как и ожидается. А что есть у нас сетка, внутри которой блоки с соотношением сторон? А в блоках только текст, или они вообще пустые. Нам стоит обратить внимание на то, что FlexBox и Grid по умолчанию задают align-items: stretch. То есть если у нас в сетки есть одна ячейка с контентом, которые не помещается в соотношение сторон, то другие ячейки начнут увеличивать высоту, равняясь на самый длинный элемент и игнорируя соотношение сторон (предполагается, что для ячеек явно задана ширина, а не высота, так как это более частый сценарий):
Для нашего дизайна поведение ожидаемое и часто подходящее по умолчанию. Но если мы все же хотим соблюдать соотношение сторон ячеек, даже если один элемент в ряду выше остальных, то нам необходимо указать другое значение для align-items, отличное от значения по умолчанию для Grid и Flexbox контейнера:
Минимальное соотношение сторон
Есть место, где стандартное поведение полезно. Когда в нашем UI компоненте есть текст с одной стороны и изображений с другой. Например, CTA элемент (элемент призывающий к действию). Если к изображению добавить соотношение сторон, то колонка с текстом будет такой же высоты, что и высота изображения. А если текст не будет помещаться в свой блок, то уже изображение будет увеличиваться для соблюдения высоты блока с текстом.
В этом примере aspect-ratio ведет себя не как фиксированное значение, а как «минимальное».
Поддержка в браузерах
Сейчас поддержка хорошая. В большинстве случаев не придется городить фолбэки. Пользователи все так же увидят ваш контент. Просто он не будет идеально соблюдать желаемое соотношение сторон. Однако в случае с галереей изображений на object-fit любое большое изображение приведет к тому, что все превьюшки в ряду увеличатся, из-за чего изображения могут неудачно обрезаться.
Проблему можно пофиксить, если на grid контейнер добавить align-items: start.
Если вам нужно предоставить запасной вариант для старых браузеров, то достаточно старого доброго функционального запроса:
1 2 3 4 5 6 7 8 9 |
.aspect-box { /* Styles for browsers that don't support aspect-ratio */ } @supports (aspect-ratio: 1 / 1) { .aspect-box { /* Styles for browsers that support aspect-ratio */ } } |
Заключение
aspect-ratio – яркий пример скромного свойства, которое решает старые проблемы с CSS. Его просто использовать, и оно ведет себя соответственно контента. Никакой лишний CSS не нужен.
Автор: Michelle Barker
Источник: css-irl.info
Редакция: Команда webformyself.
Читайте нас в Telegram, VK, Яндекс.Дзен