※ 본 포스팅은 개인 기록용으로 반응형 웹에서 이미지나 요소의 비율을 유지하는 방법에 대해 고민하다가 알게된 내용을 정리한 것입니다. 혹시나 저와 비슷한 고민을 하시는 분이 계실까봐 기록으로 남깁니다.

 aspect-ratio로 반응형 웹에서 요소의 비율 유지하기

 

 들어가며

최근 캐러셀(슬라이더) 컴포넌트를 만들면서 이미지의 비율을 어떻게 유지할지 고민이 많았습니다. 처음에는 단순히 width와 height를 픽셀로 고정하거나 퍼센트(%)로 지정했는데, 이게 생각보다 쉽지 않더라구요. 고정 픽셀을 사용하면 모바일에서 깨지고, 퍼센트만 사용하면 부모 요소의 크기에 따라 이미지가 찌그러지는 문제가 있었습니다. div를 여러 개 중첩해서 해결할 수도 있겠지만, 성능 이슈가 걱정되었죠. 그러다 발견한 게 바로 `aspect-ratio` CSS 속성입니다. 

 

 aspect-ratio란?

`aspect-ratio`는 요소의 가로세로 비율을 설정하는 CSS 속성입니다. 예를 들어 16:9 비율을 유지하고 싶다면 다음과 같이 작성할 수 있습니다: 

element { aspect-ratio: 16/9; }

 

실제 사용 예시 - 기존 제가 했던 캐러셀 구현 방식의 문제점

처음에는 이런 식으로 구현했습니다

.carousel-wrapper {
  width: 100%;
  position: relative;
}

.carousel-container {
  width: 100%;
  height: 0;
  padding-bottom: 56.25%; /* 16:9 비율을 위한 padding hack */
  position: relative;
}

.carousel-item {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.carousel-image-wrapper {
  width: 100%;
  height: 100%;
  position: relative;
}

.carousel-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
...

<div class="carousel-wrapper">
  <div class="carousel-container">
    <div class="carousel-item">
      <div class="carousel-image-wrapper">
        <img src="image1.jpg" class="carousel-image" alt="" />
      </div>
    </div>
    <!-- 추가 슬라이드 아이템들... -->
  </div>
</div>

...

여기에서 저는 처음에는 구현이 일단 됐기 때문에 다른 작업을 하다가

실제로 api 연결을 하고 사진이 많아졌을 때 컴포넌트가 버벅거리는 경험을 하게 되었습니다.

그래서 코드를 점검해보고 고민해보는 시간을 갖게 되었고 제가 내렸던 이 방식의 문제점은

  1. div가 너무 많이 중첩됩니다 (wrapper -> container -> item -> image-wrapper -> image)
  2. position: absolute를 사용해야 하는 등 복잡한 position 설정이 필요합니다
  3. padding hack(padding-bottom: 56.25%)을 사용해야 해서 코드가 직관적이지 않습니다
  4. DOM 요소가 많아져서 성능에 영향을 줄 수 있습니다

였고 어떤 식으로 최적화 및 html 요소를 줄일 수 있을지 찾아보았습니다.

 

 aspect-ratio를 활용한 개선된 구현

이걸 aspect-ratio를 사용하면 훨씬 단순화할 수 있었습니다:

.carousel {
  width: 100%;
  overflow: hidden;
}

.carousel-item {
  width: 100%;
  aspect-ratio: 16/9;
}

.carousel-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
<div class="carousel">
  <div class="carousel-item">
    <img src="image1.jpg" class="carousel-image" alt="" />
  </div>
  <!-- 추가 슬라이드 아이템들... -->
</div>

 

단순히 계산해도 원래는
캐러셀 랩퍼 > 컨테이너 > 아이템 > 아이템 랩퍼 순으로 4뎁스나 필요했었는데

개선된 코드에서는 랩퍼 없이 캐러셀, 캐러셀 아이템 만으로 엄청 간소화되었습니다.

더 좋은 방법이 있지 않을까 고민하지 않고 아는 지식만으로 구현하려 했었기 때문에

무지에서 발생한 성능저하였고, 지금 구현은 된다고 하더라도 내가 하는게 최선인지 의심해보던 초심을 몇개월동안 잃어버렸던 것 같은데 포스팅할 좋은 경험이 되었습니다.

+ Recent posts