Skip to main content

CSS співвідношення сторін

aspect-ratio, це CSS властивість, що автоматично обчислює висоту елемента з його ширини (або навпаки) за фіксованим співвідношенням.

Теорія

TL;DR

  • Як рамка для фото, що підлаштовує висоту під будь-яку ширину без спотворень. Ти задаєш пропорцію, браузер рахує.
  • До 2021 року: трюк з padding-bottom: 56.25% на div-обгортці. Тепер одна властивість замінює все це.
  • Задай один розмір (ширину або висоту) плюс aspect-ratio, браузер обчислить інший.
  • Пропускай, якщо обидва розміри вже задані явно.

Швидкий приклад

css
.video { width: 100%; max-width: 800px; aspect-ratio: 16 / 9; background: #000; } /* При ширині 800px висота 450px. При 400px висота 225px. */

Одна властивість. Без JavaScript. Без padding-хаків. Контейнер залишається 16:9 при будь-якому розмірі вікна.

Чому це замінило padding-хак

До Chrome 88 (січень 2021) відсоткова height не мала точки відліку, якщо батьківський елемент не мав явної висоти. Тому розробники застосовували padding-bottom: 56.25% на обгортці, бо відсоткові відступи завжди рахуються від ширини. div з height: 0; padding-bottom: 56.25% давав блок 16:9, а реальний контент розміщувався всередині через position: absolute.

Працювало. Але це був хак. Зайва розмітка, неочевидний CSS, плутанина для всіх, хто читав код пізніше. На практиці я досі зустрічаю цей патерн у проєктах, що стартували до 2021 року, часто просто скопійований без усвідомлення, що існує нативне рішення.

aspect-ratio вирішує це напряму. Браузер рахує висота = ширина * (ratio-height / ratio-width) під час layout-проходу, після того як ширина вже відома. Без обгорток. Без padding-трюків.

Коли використовувати

  • Адаптивні відео-контейнери: width: 100% + aspect-ratio: 16 / 9
  • Мініатюри в галереях, що масштабуються з шириною колонки Grid
  • Картки товарів, де зображення має зберігати форму при зміні розміру
  • Placeholder-блоки до завантаження зображень

Пропускай, якщо width і height задані явно. Тоді властивість ігнорується. Також не потрібна, якщо Flexbox або Grid вже контролює потрібну форму.

Як браузер це обчислює

Браузери (Blink, WebKit, Gecko) обробляють aspect-ratio під час layout-проходу, після визначення ширини. Для блокового елемента з width: 100% ширина відома першою, тому висота обчислюється з пропорції. У вертикальному flex-контейнері з обмеженою висотою логіка зворотна. Якщо задані обидва розміри явно, пропорція ігнорується повністю.

Важливий edge case: min-height і max-height можуть перебити обчислений через ratio розмір. Якщо обчислена висота менша за min-height, браузер бере min-height, і aspect-ratio фактично перестає діяти.

Типові помилки

Задавати height разом з aspect-ratio у Flexbox:

css
/* Неправильно - height перебиває ratio */ .flex-item { flex: 1; aspect-ratio: 16 / 9; height: 100%; } /* Правильно - прибери height, нехай ratio встановить його */ .flex-item { flex: 1; aspect-ratio: 16 / 9; }

Думати, що aspect-ratio: auto зберігає власні пропорції зображення на всіх елементах:

Для replaced elements (img, video) auto дійсно бере власну пропорцію з файлу. Але для звичайних div — це 1:1. Для зображень простіший шлях: width: 100%; height: auto;.

Застосовувати до комірок таблиці:

Table layout ігнорує aspect-ratio. Алгоритм таблиці перебиває його. Обгорни контент комірки у div і застосовуй ratio там.

Батьківський елемент схлопується до нуля у float-контексті:

Якщо батько не має точки відліку для висоти, ratio не може спрацювати. Використовуй Flexbox або Grid як контейнер, або задай батьку явну висоту.

Де зустрічається

  • Tailwind CSS: утиліта aspect-[16/9] з v3+
  • Bootstrap 5.3+: клас .ratio використовує aspect-ratio з @supports fallback для старих браузерів
  • Next.js / Vercel templates: контейнери для відео і hero-зображень
  • Бібліотека react-player: обгортає iframe з aspectRatio в inline-стилях замість старого padding-підходу
  • Legacy-підтримка: @supports not (aspect-ratio: 1) { padding-bottom: 56.25%; } для Safari до версії 15

Питання на співбесіді

Q: Що буде, якщо задати і width, і height разом з aspect-ratio?
A: Пропорція ігнорується. Явні розміри завжди мають пріоритет. aspect-ratio обчислює лише той розмір, якого не вистачає.

Q: Як працює aspect-ratio: auto на зображеннях?
A: Для replaced elements (img, video) auto бере власну пропорцію з файлу. Для звичайних елементів за замовчуванням 1:1. Для зображень зазвичай простіше width: 100%; height: auto;.

Q: Як підтримувати браузери до Chrome 88?
A: Використовуй @supports not (aspect-ratio: 1) і додай padding-bottom як fallback. Окремий поліфіл не потрібен, достатньо прогресивного покращення.

Q: Чому в CSS Grid aspect-ratio іноді ігнорується на елементах сітки?
A: Grid спочатку обчислює розміри треків. Якщо рядок має явну висоту або grid розтягує елементи, ця висота перебиває пропорцію. Рішення: align-items: start на контейнері, або перенеси ratio на внутрішній div всередині елемента сітки.

Q: Чи можна використовувати CSS-змінні з aspect-ratio?
A: Так. aspect-ratio: var(--ratio) працює. Оголоси --ratio: 16 / 9 у :root і використовуй у кількох компонентах.

Приклади

Адаптивне відео

Класичний випадок. iframe залишається 16:9 при будь-якій ширині екрана, без padding-хаку і без JavaScript.

html
<div class="video-wrapper"> <iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" style="width: 100%; height: 100%; border: none;" allowfullscreen> </iframe> </div>
css
.video-wrapper { width: 100%; max-width: 800px; aspect-ratio: 16 / 9; margin: 0 auto; overflow: hidden; /* Без position: absolute. Без padding-bottom. Просто працює. */ }

При ширині 800px висота буде 450px. При 400px висота буде 225px. iframe заповнює обгортку, бо його ширина і висота дорівнюють 100% від батька, а висота батька задається через ratio.

Сітка товарів з однаковими мініатюрами

Інтернет-магазини потребують квадратних мініатюр незалежно від розмірів оригінального зображення. aspect-ratio фіксує форму, object-fit обробляє кадрування.

css
.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; } .product-image { width: 100%; aspect-ratio: 1 / 1; /* завжди квадрат */ overflow: hidden; background: #f5f5f5; border-radius: 4px; } .product-image img { width: 100%; height: 100%; object-fit: cover; /* кадрування, не розтягування */ }

object-fit: cover кадрує зображення в квадрат без спотворення. aspect-ratio: 1 / 1 гарантує, що блок залишається квадратним, скільки б широкою не стала колонка сітки.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?