이 글은 누구를 위한 것인가
- 모바일에서는 크롭된 이미지, 데스크탑에서는 원본 이미지를 제공하려는 팀
- WebP/AVIF를 지원 브라우저에만 제공하고 싶은 개발자
- LCP 점수 개선을 위해 이미지를 최적화하려는 팀
들어가며
<img src="hero.jpg">만으로는 4K 이미지를 모바일에서도 다운로드한다. srcset으로 디바이스 픽셀 밀도와 뷰포트 크기에 맞는 이미지를 제공하고, picture로 모바일에서는 세로 구도, 데스크탑에서는 가로 구도를 아트 디렉션한다.
이 글은 bluefoxdev.kr의 반응형 이미지 아트 디렉션 가이드 를 참고하여 작성했습니다.
1. 반응형 이미지 전략
[srcset vs picture]
srcset + sizes: 같은 이미지, 다른 크기
→ 브라우저가 최적 크기 자동 선택
picture: 다른 이미지 (아트 디렉션)
→ 모바일: 얼굴 클로즈업 / 데스크탑: 전체 구도
→ WebP 지원: WebP / 미지원: JPEG
[sizes 속성]
sizes="(max-width: 640px) 100vw,
(max-width: 1024px) 50vw,
33vw"
브라우저는 sizes로 표시 크기를 알고
srcset에서 가장 적합한 이미지 선택
[레이아웃 시프트 방지]
width + height 속성 필수
또는 aspect-ratio CSS
→ 이미지 로드 전 공간 예약
[LCP 최적화]
히어로 이미지: fetchpriority="high"
Above-the-fold: loading="eager"
Below-the-fold: loading="lazy"
preload link: <link rel="preload" as="image">
2. 반응형 이미지 구현
<!-- 기본 srcset (해상도 디스크립터) -->
<img
src="hero-800.jpg"
srcset="hero-400.jpg 400w,
hero-800.jpg 800w,
hero-1200.jpg 1200w,
hero-2400.jpg 2400w"
sizes="(max-width: 640px) 100vw,
(max-width: 1024px) 80vw,
1200px"
alt="서비스 히어로 이미지"
width="1200"
height="600"
fetchpriority="high"
/>
<!-- picture: 아트 디렉션 + 포맷 분기 -->
<picture>
<!-- 모바일: 세로 구도, AVIF -->
<source
media="(max-width: 640px)"
type="image/avif"
srcset="hero-mobile.avif"
/>
<!-- 모바일: 세로 구도, WebP 폴백 -->
<source
media="(max-width: 640px)"
type="image/webp"
srcset="hero-mobile.webp"
/>
<!-- 데스크탑: 가로 구도, AVIF -->
<source
media="(min-width: 641px)"
type="image/avif"
srcset="hero-desktop-800.avif 800w, hero-desktop-1600.avif 1600w"
sizes="(max-width: 1024px) 80vw, 1200px"
/>
<!-- 데스크탑: 가로 구도, WebP 폴백 -->
<source
media="(min-width: 641px)"
type="image/webp"
srcset="hero-desktop-800.webp 800w, hero-desktop-1600.webp 1600w"
sizes="(max-width: 1024px) 80vw, 1200px"
/>
<!-- 최종 폴백 -->
<img
src="hero-desktop.jpg"
alt="서비스 히어로"
width="1600"
height="800"
fetchpriority="high"
/>
</picture>
/* 레이아웃 시프트 방지 */
.hero-image {
aspect-ratio: 16 / 9;
width: 100%;
object-fit: cover;
object-position: center;
}
/* 모바일 아트 디렉션 */
@media (max-width: 640px) {
.hero-image {
aspect-ratio: 4 / 5; /* 세로 구도 */
object-position: top center; /* 얼굴 중심 */
}
}
/* 이미지 갤러리 그리드 */
.image-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 16px;
}
.image-grid img {
aspect-ratio: 4 / 3;
width: 100%;
object-fit: cover;
border-radius: 8px;
}
// Next.js Image 컴포넌트 (자동 최적화)
import Image from 'next/image';
function HeroSection() {
return (
<div style={{ position: 'relative', width: '100%', aspectRatio: '16/9' }}>
<Image
src="/images/hero.jpg"
alt="서비스 소개"
fill
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 80vw, 1200px"
priority // LCP 이미지: 지연 로딩 비활성화
style={{ objectFit: 'cover' }}
/>
</div>
);
}
마무리
반응형 이미지의 핵심은 srcset + sizes로 브라우저가 최적 이미지를 선택하게 하고, picture로 아트 디렉션과 포맷 분기를 처리하는 것이다. LCP 이미지에는 fetchpriority="high"와 <link rel="preload">를 적용하고, width + height 또는 aspect-ratio로 레이아웃 시프트(CLS)를 방지한다.