종횡비

Aspect ratio

가로:세로 비율을 고정해서, 폭이 바뀌어도 요소가 항상 같은 비율을 유지하게 하는 속성. `aspect-ratio: 16 / 9` 한 줄이면 됩니다.

다른 이름: aspect-ratio (CSS property)
···
html
<div class="box" id="box"><span id="label">16 / 9</span></div>
css
.box{position:relative;border-radius:12px;display:grid;place-items:center;
  background:linear-gradient(135deg,var(--accent),var(--accent-3));color:#fff;font-weight:700;
  transition:aspect-ratio 1.1s cubic-bezier(.4,0,.2,1),width 1.1s cubic-bezier(.4,0,.2,1),height 1.1s cubic-bezier(.4,0,.2,1);
  aspect-ratio:16/9;box-shadow:0 10px 24px rgba(0,0,0,.15)}
#label{font-size:clamp(11px,2.4vmin,15px);letter-spacing:.03em}
js
const box = document.getElementById('box');
const label = document.getElementById('label');
const steps = [
  { ratio: '16/9', rw: 16, rh: 9 },
  { ratio: '1/1', rw: 1, rh: 1 },
  { ratio: '4/3', rw: 4, rh: 3 },
  { ratio: '9/16', rw: 9, rh: 16 },
];
let i = 0;
function apply() {
  const s = steps[i];
  box.style.aspectRatio = s.ratio;
  // 장변을 뷰포트에서 더 좁은 쪽(폭 또는 높이)의 82% 로 고정해, 세로로 긴 비율도 잘리지 않게 한다
  const unit = Math.min(innerWidth, innerHeight) * 0.82;
  if (s.rw >= s.rh) {
    box.style.width = unit + 'px';
    box.style.height = 'auto';
  } else {
    box.style.height = unit + 'px';
    box.style.width = 'auto';
  }
  label.textContent = s.ratio.replace('/', ' / ');
  i = (i + 1) % steps.length;
}
apply();
setInterval(apply, 1600);

과거에는 이미지 비율을 유지하려고 `padding-top: 56.25%`(16:9의 세로/가로 값) 같은 "패딩 트릭"을 써야 했습니다. 부모에 `position: relative`, 자식 이미지에 `position: absolute; inset: 0`을 걸어야 하는, 본질과 상관없는 코드가 많이 필요했죠.

2021년부터 주요 브라우저에 도입된 `aspect-ratio` 속성은 그 트릭을 대체합니다. `aspect-ratio: 16/9`만 주면 너비가 정해질 때 높이가 자동 계산되고, 반대로 높이가 정해지면 너비가 계산됩니다. 이미지가 로드되기 전에도 미리 공간을 확보해서 레이아웃이 갑자기 밀리는 현상(CLS, Cumulative Layout Shift)도 막아줍니다.

`width`와 `height` 속성이 이미 있는 `<img>` 태그는 브라우저가 자동으로 비율을 계산하므로 CSS로 따로 지정할 필요가 없는 경우도 많습니다. CSS `aspect-ratio`는 주로 배경색만 있는 플레이스홀더, 비디오 래퍼, 커스텀 카드에 씁니다.