CSS aspect-ratio로 가로세로 비율 맞추기

CSS aspect-ratio로 가로세로 비율 맞추기

웹 페이지에 이미지나 비디오를 넣을 때 가로세로 비율 때문에 고생해본 적 있으신가요? 너비를 100%로 맞추면 높이가 찌그러지고, 높이를 고정하면 이미지가 잘리고 😅 특히 반응형 웹에서는 화면 크기에 따라 요소의 너비가 계속 바뀌기 때문에 비율을 유지하는 게 쉽지 않습니다.

예전에는 padding-top 트릭 같은 우회 방법을 썼는데요. 이제는 CSS의 aspect-ratio 속성 하나로 깔끔하게 해결할 수 있습니다.

aspect-ratio 속성

aspect-ratio는 요소의 가로세로 비율을 지정하는 CSS 속성입니다.

.box {
  aspect-ratio: 16 / 9;
}

너비 / 높이 형태로 비율을 적어주면 됩니다. 위 코드는 요소를 16:9 비율로 유지하겠다는 뜻이에요. 너비가 바뀌더라도 브라우저가 알아서 높이를 계산해줍니다.

자주 쓰는 비율을 정리하면 이렇습니다.

  • 16 / 9 — 와이드스크린. 유튜브 비디오, 배너 이미지에 많이 씁니다.
  • 4 / 3 — 전통적인 모니터 비율. 썸네일이나 카드에 적합합니다.
  • 1 / 1 — 정사각형. 프로필 이미지, 아이콘에 좋습니다.
  • 21 / 9 — 울트라와이드. 히어로 배너에 쓰기도 합니다.

aspect-ratio가 설정된 요소에 width만 지정하면 높이가 자동으로 결정되고, height만 지정하면 너비가 자동으로 결정됩니다. 둘 다 지정하지 않으면 요소의 기본 너비(보통 부모 너비)를 기준으로 높이가 계산돼요.

이미지에 적용하기

이미지에 aspect-ratio를 적용하면 원본 비율과 다르게 표시할 수 있습니다.

img {
  width: 100%;
  aspect-ratio: 4 / 3;
}

그런데 이렇게만 하면 이미지가 찌그러질 수 있어요. 원본 비율과 지정한 비율이 다르면 이미지가 늘어나거나 줄어들기 때문입니다.

이때 object-fit 속성을 함께 쓰면 비율을 유지하면서 영역에 맞출 수 있습니다.

img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

object-fit: cover는 비율을 유지한 채로 영역을 꽉 채우고 넘치는 부분을 잘라냅니다. 프로필 사진을 정사각형으로 보여주거나, 카드 UI에서 썸네일 크기를 통일할 때 딱이에요.

.profile-image {
  width: 120px;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 50%;
}

object-fit에는 cover 외에도 contain(영역 안에 이미지 전체가 보이도록), fill(영역에 맞춰 늘리기, 기본값), none(원본 크기 유지) 등이 있습니다. 각 값의 차이가 궁금하다면 object-fit 속성으로 이미지를 왜곡 없이 보여주기를 참고하세요.

아래 CodePen에서 직접 비율을 바꿔가며 결과를 확인해보세요.

비디오와 iframe에 적용하기

유튜브 비디오를 임베드할 때도 aspect-ratio가 유용합니다.

iframe {
  width: 100%;
  aspect-ratio: 16 / 9;
}

이렇게 하면 iframe이 부모 너비에 맞춰 늘어나면서 16:9 비율을 유지합니다. 예전에는 이걸 위해 꽤 번거로운 작업이 필요했어요.

padding-top 트릭은 이제 안녕

aspect-ratio가 나오기 전에는 padding-top 트릭을 써야 했습니다. CSS에서 padding을 퍼센트로 지정하면 부모 요소의 너비를 기준으로 계산된다는 점을 이용한 건데요.

/* 예전 방식 */
.video-wrapper {
  position: relative;
  padding-top: 56.25%; /* 9 ÷ 16 = 0.5625 */
  height: 0;
}

.video-wrapper iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

16:9 비율을 만들려면 9 / 16 = 56.25%padding-top에 넣고, 내부 요소를 position: absolute로 배치해야 했습니다. 동작은 하지만 의도가 코드에서 바로 드러나지 않아서 처음 보는 사람은 이해하기 어렵죠.

aspect-ratio를 쓰면 같은 결과를 한 줄로 얻을 수 있습니다.

/* 현대적 방식 */
.video-wrapper {
  aspect-ratio: 16 / 9;
}

.video-wrapper iframe {
  width: 100%;
  height: 100%;
}

래퍼 요소 없이 iframe에 직접 적용하면 더 간단해집니다.

iframe {
  width: 100%;
  aspect-ratio: 16 / 9;
}

레이아웃 시프트 방지

aspect-ratio의 숨은 장점이 하나 더 있는데요. 이미지가 로드되기 전에 브라우저가 차지할 공간을 미리 확보해서 레이아웃 시프트(CLS, Cumulative Layout Shift)를 방지합니다.

레이아웃 시프트란 페이지가 로딩되는 동안 요소의 위치가 갑자기 바뀌는 현상이에요. 이미지의 크기를 모르면 브라우저가 높이를 0으로 잡았다가 이미지가 로드되면서 갑자기 아래 콘텐츠가 밀려나죠.

aspect-ratio를 지정하면 이미지가 로드되기 전에도 올바른 공간이 확보됩니다.

img {
  width: 100%;
  aspect-ratio: 16 / 9;
}

참고로 HTML의 <img> 태그에 widthheight 속성을 명시해도 같은 효과를 얻을 수 있어요. 브라우저가 이 속성값으로 비율을 계산하거든요.

<img src="photo.jpg" width="1600" height="900" alt="사진" />

마치며

aspect-ratio는 한 줄로 요소의 가로세로 비율을 고정하는 CSS 속성입니다. 이미지, 비디오, 카드 UI 등 비율이 중요한 곳이라면 어디서든 쓸 수 있어요.

padding-top 트릭 대비 코드가 직관적이고, object-fit과 조합하면 이미지 크롭까지 간편하게 처리됩니다. 레이아웃 시프트 방지 효과는 덤이고요. 모든 모던 브라우저에서 지원되니 실무에서 바로 써보세요.

더 자세한 내용은 aspect-ratio - MDN Web Docs를 참고하세요.

This work is licensed under CC BY 4.0 CC BY

개발자를 위한 뉴스레터

달레가 정리한 AI 개발 트렌드와 직접 만든 콘텐츠를 전해드립니다.

Discord