웹 페이지에서 이미지를 표시할 때 가장 먼저 떠오르는 태그는 img 태그다.
<img src="/product.jpg" alt="상품 이미지" />
이미지를 화면에 보여주는 것만 생각한다면 이것으로 충분해 보인다.
하지만 문득 이런 궁금증이 들었다.
화면에는 200px 크기로 보이는데, 브라우저는 정말 200px 크기의 이미지만 다운로드하고 있을까?
이 질문을 시작으로 img, srcset, picture, lazy loading이 왜 등장하게 되었는지 정리해보았다.
다음과 같은 이미지가 있다고 가정해보자.
그리고 화면에서는 아래처럼 렌더링된다.
<img src="/product.jpg" alt="상품 이미지" />
img {
width: 200px;
height: 200px;
}
사용자 눈에는 200px 크기로 보인다.
하지만 브라우저는 CSS가 적용된 최종 렌더링 크기를 기준으로 이미지를 다운로드하지 않는다.
src에 명시된 원본 이미지를 다운로드한 뒤, 렌더링 과정에서 200px 크기로 축소한다.
즉,
일 수 있다.
이미지 한 장이라면 큰 문제가 아닐 수 있다.
하지만 상품 목록 페이지처럼 이미지가 수십 개 존재한다면 이야기가 달라진다.
500KB × 20장 = 10MB
사용자는 실제로 필요하지 않은 데이터를 다운로드하고 있을 수도 있다.
사실 브라우저 입장에서는 당연한 행동이다.
<img src="/product.jpg" />
이 정보만 보고는
를 정확히 판단할 수 없다.
브라우저는 단순히
"product.jpg를 요청하라고 했으니 product.jpg를 다운로드해야겠다."
라고 생각한다.
그래서 등장한 것이 srcset이다.
srcset은 브라우저에게 여러 크기의 이미지 후보를 제공하는 기능이다.
<img
src="product-400.jpg"
srcset="
product-400.jpg 400w,
product-800.jpg 800w,
product-1200.jpg 1200w
"
alt="상품 이미지"
/>
이제 브라우저는
을 고려하여 적절한 이미지를 선택할 수 있다.
예를 들어
| 환경 | 선택되는 이미지 |
|---|---|
| 모바일 | 400px |
| 태블릿 | 800px |
| 데스크톱 | 1200px |
처럼 동작할 수 있다.
즉, 브라우저가 상황에 맞는 이미지를 스스로 선택할 수 있게 된다.
같은 200px 영역이라도 디바이스마다 필요한 이미지 크기가 다르다.
예를 들어 DPR(Device Pixel Ratio)이 2인 환경에서는
200px 영역
↓
실제로는 400px 이미지 필요
할 수 있다.
그래서 브라우저는 단순히 화면 크기만 보는 것이 아니라 디바이스 해상도까지 고려해서 이미지를 선택한다.
srcset이 없다면
문제가 발생할 수 있다.
srcset은 같은 이미지의 크기만 바꾸는 데 적합하다.
하지만 경우에 따라서는 아예 다른 이미지를 제공해야 할 수도 있다.
예를 들어
를 보여주고 싶을 수 있다.
이때 사용하는 것이 picture 태그다.
<picture>
<source
media="(min-width: 768px)"
srcset="/banner-desktop.jpg"
/>
<source
media="(max-width: 767px)"
srcset="/banner-mobile.jpg"
/>
<img src="/banner.jpg" alt="배너" />
</picture>
브라우저는 조건에 맞는 이미지를 선택하여 렌더링한다.
즉,
srcset은 "어떤 크기의 이미지를 사용할까?"를 해결하고,
picture는 "어떤 이미지를 사용할까?"를 해결한다.
이미지 최적화는 크기만의 문제가 아니다.
포맷 역시 중요하다.
일반적으로 다음과 같은 압축 효율을 가진다.
| 포맷 | 상대 용량 |
|---|---|
| JPG | 100% |
| WebP | 60~80% |
| AVIF | 40~70% |
이를 활용하면 같은 이미지를 더 작은 용량으로 제공할 수 있다.
<picture>
<source
srcset="/product.avif"
type="image/avif"
/>
<source
srcset="/product.webp"
type="image/webp"
/>
<img src="/product.jpg" alt="상품" />
</picture>
브라우저는 지원 가능한 가장 효율적인 포맷을 선택한다.
상품 목록 페이지를 생각해보자.
사용자가 처음 보는 영역은 화면 상단뿐이다.
그런데 아래쪽에 있는 이미지까지 모두 다운로드한다면 어떨까?
초기 로딩 시간이 길어질 수 있다.
이를 해결하기 위해 등장한 것이 Lazy Loading이다.
<img
src={imageUrl}
alt={name}
loading="lazy"
/>
브라우저는 해당 이미지가 화면에 가까워졌을 때 다운로드를 시작한다.
결과적으로
효과를 얻을 수 있다.
특히 무한 스크롤이나 상품 목록 페이지에서 유용하다.
이미지와 관련하여 자주 언급되는 성능 지표 중 하나가 CLS(Cumulative Layout Shift)다.
다음 코드를 보자.
<img src="/product.jpg" alt="상품" />
브라우저는 이미지 크기를 알 수 없기 때문에 처음에는 공간을 확보하지 못한다.
이후 이미지가 로딩되면 갑자기 공간이 생기면서 화면이 밀릴 수 있다.
사용자는
이를 방지하려면 이미지 크기를 미리 알려주는 것이 좋다.
<img
src="/product.jpg"
alt="상품"
width="300"
height="300"
/>
또는 CSS의 aspect-ratio를 활용할 수도 있다.
처음에는 단순히 이미지를 보여주는 태그라고 생각했던 img 태그가 생각보다 많은 고민을 담고 있다는 것을 알게 되었다.
이미지 최적화는 단순히 파일 용량을 줄이는 것이 아니다.
브라우저가
를 효율적으로 결정할 수 있도록 돕는 과정에 가깝다.
정리하면,
srcset : 적절한 크기의 이미지를 선택하기 위해picture : 상황에 따라 다른 이미지를 제공하기 위해loading="lazy" : 필요한 시점에 다운로드하기 위해사용할 수 있다.
실제로 원본 이미지(1200px)와 srcset 적용 후 다운로드 크기를 비교한 실험 결과를 추가해볼 예정