큰 이미지가 느릴 때 렌더링 속도를 높이는 법: 포맷, 크기, 로딩 전략 한 번에 정리
빠른 답
- 원본 이미지를 그대로 내려보내지 말고 실제 표시 크기와 DPR에 맞춘 파일을 서버나 CDN에서 변환해 제공합니다.
- AVIF와 WebP를 우선하되
로 JPEG 또는 PNG fallback을 함께 두어 브라우저 호환성을 확보합니다. - 첫 화면 핵심 이미지는 무조건 lazy 처리하지 말고 fetchpriority="high" 또는 preload를 검토하고, 나머지 이미지만 지연 로딩합니다.
- Network와 Performance 패널에서 전송 크기, 선택된 소스, 디코드 시간, LCP 후보 이미지를 함께 봐야 병목을 정확히 찾을 수 있습니다.
브라우저 렌더링 흐름을 중심으로 초안을 다시 정리하고, 현재 기준의 포맷 지원과 우선순위 관련 공식 문서 포인트를 짧게 확인하겠습니다. 오래된 설명과 지금 설명이 갈리는 부분도 함께 정리해서 발행용 본문으로 맞추겠습니다.# 큰 이미지가 느릴 때 렌더링 속도를 높이는 법: 포맷, 크기, 로딩 전략 한 번에 정리
목차
시간 흐름으로 이해하기
흐름으로 보기
이미지 최적화는 파일 용량만 줄이는 작업에 가깝지 않습니다. 브라우저가 이미지를 언제 발견하고, 어떤 우선순위로 가져오고, 언제 디코드하고, 레이아웃과 페인트에 언제 반영하는지를 함께 봐야 최종 표시 시점을 줄일 수 있습니다.
브라우저 안에서 실제로 무슨 순서로 일어날까
브라우저는 HTML을 파싱해 DOM을 만들고, CSS를 파싱해 CSSOM을 만든 뒤, 두 정보를 바탕으로 렌더 트리를 구성합니다. 그다음 각 요소의 크기와 위치를 계산하는 Layout, 픽셀을 그리는 Paint, 레이어를 합치는 Compositing으로 이어집니다.
큰 이미지가 느리게 느껴지는 이유도 이 흐름 안에서 이해하는 편이 정확합니다. 예를 들어 첫 화면 대표 이미지가 img로 문서 안에 있으면 HTML 파서 단계에서 비교적 빨리 발견됩니다. 반면 background-image로만 들어 있으면 CSS를 내려받고 CSSOM을 만든 뒤에야 요청 후보가 되기 쉬워서, 같은 파일 크기여도 훨씬 늦게 보일 수 있습니다.
이 차이는 LCP와도 바로 연결됩니다. web.dev의 LCP 가이드에 따르면 LCP는 페이지가 로드되기 시작한 시점부터 가장 큰 텍스트 블록이나 이미지가 그려질 때까지를 봅니다. 대표 이미지가 LCP 후보라면, 다운로드 크기만 줄이는 것보다 발견 시점과 우선순위를 먼저 점검하는 편이 도움이 됩니다.
큰 이미지가 느린 이유는 다운로드만이 아니다
이미지가 클수록 느려지는 이유는 보통 네 가지가 겹칩니다.
- 전송 바이트가 많아 네트워크 시간이 길어집니다.
- 해상도가 높을수록 디코드 비용이 커집니다.
- 크기 정보가 늦게 정해지면 레이아웃이 다시 계산될 수 있습니다.
- 그려야 할 픽셀이 많아
Paint와Composite비용이 커집니다.
디코드 비용은 특히 과소평가되기 쉽습니다. 예를 들어 4000x3000 이미지를 RGBA 비트맵으로 펼치면 대략 4000 x 3000 x 4 바이트, 약 45.8MiB 수준의 메모리를 다루게 됩니다. 전송 파일이 500KB였더라도, 브라우저가 최종적으로 처리해야 하는 화면용 데이터는 훨씬 클 수 있다는 뜻입니다.
그래서 “파일 크기는 줄였는데 페이지가 여전히 답답하다”는 상황이 생깁니다. 요청이 늦게 발견되었거나, 필요 이상으로 큰 이미지를 내려보냈거나, width와 height가 없어 레이아웃이 흔들리면 최종 표시 시점은 기대만큼 줄지 않습니다.
현재 기준 포맷 선택과 오래된 설명의 차이
2026년 4월 기준으로 보면, 이미지 최적화에 대한 오래된 설명 중 일부는 그대로 쓰기 어렵습니다.
- 포맷 지원:
WebP는 더 이상 “최신 브라우저에서만 되는 포맷”으로 보기 어렵습니다. MDN 이미지 포맷 가이드는WebP를 주요 브라우저 전반에서 폭넓게 지원하는 포맷으로 설명합니다. AVIF의 위치:AVIF도 현재 주요 브라우저에서 충분히 검토할 수 있는 선택지입니다. MDN은AVIF지원을Chrome 85,Firefox 93,Safari 16.1이상으로 안내합니다. 다만 역사적 지원 폭이WebP보다 얕기 때문에 fallback은 여전히 유용합니다.- 우선순위 API 명칭: 예전 글에서 보이던
Priority Hints라는 이름은 현재 Fetch Priority API와fetchpriority속성으로 정리되어 있습니다. - 지연 로딩 관성: “모든 이미지에
lazy를 붙이면 된다”는 조언은 지금 기준으로는 거칠게 느껴집니다. web.dev LCP 가이드는LCP이미지에loading="lazy"를 두면 불필요한 지연이 생긴다고 경고합니다. - 용어 사용: 예전에는
reflow라는 표현이 자주 쓰였지만, 현재 DevTools에서는Layout,Paint,Composite단위로 보는 편이 병목을 더 직접적으로 설명해 줍니다.
포맷 선택도 파일 성격에 따라 나누어 보는 편이 낫습니다.
- 사진성 이미지:
AVIF또는WebP - 투명 배경이 필요한 일반 이미지:
WebP또는PNG - 텍스트가 많은 스크린샷: 손실 없는
WebP또는PNG - 아이콘, 로고, 도형:
SVG - 범용 fallback:
JPEG또는PNG
한 가지 더 볼 점은 AVIF가 항상 체감 표시 속도까지 가장 빠르다고 단정하기 어렵다는 점입니다. MDN은 AVIF가 JPEG나 PNG보다 더 작은 파일을 만들 수 있다고 설명하면서도, AVIF는 progressive rendering을 지원하지 않는다고 적고 있습니다. 따라서 아주 큰 대표 이미지에서는 전송량 절감 효과와 실제 표시 시점을 둘 다 비교해 보는 편이 좋습니다.
요청 시점과 우선순위 다루기
첫 화면 대표 이미지는 “언제 발견되는가”와 “어느 정도 우선순위로 가져오는가”가 중요합니다. 문서 안의 img로 배치할 수 있다면 그 편이 보통 더 빠릅니다. CSS 배경 이미지를 대표 이미지로 써야 한다면 preload를 함께 두는 쪽이 발견 지연을 줄이는 데 도움이 됩니다.
이미지가 여러 포맷으로 제공될 때는 picture와 srcset을 함께 쓰는 구성이 익숙합니다. 이때 preload는 모든 포맷에 다 거는 방식보다, 다수 사용자에게 실제로 선택될 가능성이 큰 한 포맷에만 적용하는 편이 낫습니다. MDN의 preload 문서는 동일한 리소스의 여러 형식을 한꺼번에 preload하면 실제 사용되지 않을 파일까지 미리 내려받을 수 있다고 설명합니다.
<head>
<link
rel="preload"
as="image"
href="/images/hero-1280.avif"
type="image/avif"
fetchpriority="high">
</head>
<body>
<picture>
<source
type="image/avif"
srcset="/images/hero-640.avif 640w, /images/hero-960.avif 960w, /images/hero-1280.avif 1280w"
sizes="(max-width: 768px) 92vw, 960px">
<source
type="image/webp"
srcset="/images/hero-640.webp 640w, /images/hero-960.webp 960w, /images/hero-1280.webp 1280w"
sizes="(max-width: 768px) 92vw, 960px">
<img
src="/images/hero-960.jpg"
srcset="/images/hero-640.jpg 640w, /images/hero-960.jpg 960w, /images/hero-1280.jpg 1280w"
sizes="(max-width: 768px) 92vw, 960px"
width="960"
height="540"
alt="제품 대표 이미지"
fetchpriority="high"
decoding="async">
</picture>
</body>
이 예시에서 fetchpriority="high"는 우선순위 힌트이고, preload는 빠른 발견을 돕습니다. 둘은 역할이 다릅니다. preload는 “일찍 알리기”, fetchpriority는 “가져올 때 더 중요하게 다뤄 달라고 힌트 주기”에 가깝습니다. decoding="async"도 유용할 수 있지만 디코드 비용 자체를 없애 주는 것은 아니므로, 큰 원본을 그대로 유지한 채 속성이 몇 개 추가된다고 병목이 사라지지는 않습니다.
표시 크기와 레이아웃 안정성 맞추기
브라우저가 srcset 후보를 고를 때 보는 것은 “현재 뷰포트 폭”만이 아닙니다. sizes가 알려주는 슬롯 크기와 기기 DPR을 함께 고려합니다. 그래서 sizes에는 “이미지가 실제로 차지할 자리 크기”를 넣는 편이 맞습니다.
같은 장면을 단지 더 작게 또는 더 크게 내려주고 싶다면 srcset과 sizes가 해상도 전환 문제를 다룹니다. 반대로 모바일에서는 다른 크롭을 쓰고 싶다면 picture가 더 적합합니다. MDN의 responsive images 가이드는 이 둘을 resolution switching과 art direction으로 구분해 설명합니다.
구성은 슬롯 크기 기준으로 잡아두면 관리하기 편합니다.
hero_image:
widths: [640, 960, 1280]
dpr: [1, 2]
formats: [avif, webp, jpg]
quality:
avif: 45
webp: 70
jpg: 78
sizes: "(max-width: 768px) 92vw, 960px"
cache:
max_age: 31536000
immutable: true
이 설정에서 중요한 점은 화면 전체 폭이 아니라 컴포넌트 슬롯 폭을 기준으로 폭 후보를 정했다는 점입니다. 카드가 최대 360px까지만 보이는데 1600px 후보를 계속 만들면, 반응형 이미지를 써도 과한 소스가 선택될 여지가 남습니다.
레이아웃 안정성도 함께 맞춰 두는 편이 좋습니다. width와 height를 마크업에 넣거나, CSS에서 aspect-ratio를 지정하면 브라우저가 자리부터 확보할 수 있습니다.
.hero-media {
width: min(100%, 960px);
aspect-ratio: 16 / 9;
overflow: clip;
}
.hero-media img {
width: 100%;
height: 100%;
object-fit: cover;
}
.promo-banner {
background-image: image-set(
url("/images/promo-960.avif") type("image/avif") 1x,
url("/images/promo-960.jpg") type("image/jpeg") 1x
);
background-size: cover;
background-position: center;
}
배경 이미지는 image-set()으로 해상도나 포맷 분기를 줄 수 있지만, 첫 화면 핵심 배경 이미지라면 여전히 preload를 별도로 검토할 만합니다. CSS 배경은 발견 시점이 늦기 때문입니다.
CDN, 캐시, 변환 파이프라인에서 줄일 수 있는 비용
이미지 최적화가 서버나 CDN 단계에서 끝나면 브라우저가 받아야 하는 후보 자체가 훨씬 정리됩니다. 보통은 원본 한 장을 보관하고, 요청 시점에 폭과 포맷을 변환해 파생본을 만드는 방식을 많이 씁니다.
이 단계에서는 캐시 정책을 함께 보는 편이 좋습니다. URL에 폭과 포맷이 포함되어 버전이 안정적으로 바뀐다면 긴 max-age와 immutable이 잘 맞습니다. 반대로 Accept 헤더를 보고 자동으로 포맷을 바꾸는 구조라면 Vary: Accept가 빠지지 않아야 캐시 오염을 줄일 수 있습니다.
$ curl -I "https://cdn.example.com/images/hero?w=1280&format=avif"
HTTP/2 200
content-type: image/avif
content-length: 151284
cache-control: public, max-age=31536000, immutable
vary: Accept
etag: "hero-1280-avif-v4"
server-timing: cdn-cache; desc=HIT
이런 응답에서는 세 가지를 먼저 확인해 볼 수 있습니다.
content-type이 의도한 포맷과 맞는지cache-control이 재요청을 줄일 수 있게 설정되어 있는지server-timing이나 CDN 전용 헤더가HIT인지MISS인지
첫 화면이 느린데 cdn-cache가 반복해서 MISS로 보인다면, 브라우저 최적화보다 캐시 키 설계나 변환 URL 전략을 먼저 손보는 편이 더 큰 차이를 만들 수 있습니다.
DevTools로 병목 확인하기
이미지 최적화는 적용보다 검증이 더 중요할 때가 많습니다. 2026년 4월 기준 Chrome DevTools에서는 Network와 Performance 패널을 함께 보는 흐름이 가장 설명력이 좋습니다. LCP 목표값은 web.dev에 따르면 75퍼센타일 기준 2.5초 이하입니다.
먼저 브라우저가 실제로 어떤 이미지를 골랐는지 확인해 볼 수 있습니다.
const image = document.querySelector("[data-hero-image]");
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log("[LCP]", {
startTime: entry.startTime.toFixed(1),
url: entry.url || image.currentSrc,
size: entry.size,
});
}
}).observe({ type: "largest-contentful-paint", buffered: true });
console.log("[IMG]", {
currentSrc: image.currentSrc,
complete: image.complete,
naturalSize: `${image.naturalWidth}x${image.naturalHeight}`,
renderedSize: `${image.clientWidth}x${image.clientHeight}`,
fetchPriority: image.fetchPriority,
loading: image.loading,
decoding: image.decoding,
});
출력은 대략 이런 식으로 보입니다.
[IMG] {
currentSrc: "https://cdn.example.com/images/hero?w=1280&format=avif",
complete: true,
naturalSize: "1280x720",
renderedSize: "390x219",
fetchPriority: "high",
loading: "eager",
decoding: "async"
}
[LCP] {
startTime: "1842.3",
url: "https://cdn.example.com/images/hero?w=1280&format=avif",
size: 85320
}
Network:
hero?w=1280&format=avif 200 img High 148 kB transferred 412 kB resource size
Performance:
Image Decode 46 ms
Layout 12 ms
Paint 18 ms
이 출력에서 볼 포인트는 몇 가지로 정리됩니다.
currentSrc가 기대한 후보인지 확인합니다.960w를 기대했는데1920w가 선택됐다면sizes나 후보 폭 구성이 맞지 않을 수 있습니다.Network에서는Priority,Initiator,transferred,resource size를 함께 봅니다. 전송량만 작은지, 실제 선택도 적절한지 구분할 수 있습니다.Performance에서는LCP마커 직전의Image Decode,Layout,Paint시간을 봅니다. 다운로드는 빨랐는데 decode가 길어지는 경우가 여기서 드러납니다.- 캐시를 끈 상태와 켠 상태를 나눠 보아야 초회 방문 병목과 재방문 병목을 구분하기 쉽습니다.
관련 패널 기능은 Chrome DevTools Network reference와 Chrome DevTools Performance reference에서 확인할 수 있습니다.
무엇부터 바꾸면 좋을까
이미지 최적화는 한 번에 모든 속성을 붙이는 것보다, 병목이 생기는 순서대로 보는 편이 읽기 쉽고 유지보수도 수월합니다.
- 요청 발견 시점: 대표 이미지가
img인지, CSS 배경인지, preload가 필요한지 봅니다. - 표시 크기: 슬롯 크기와
DPR기준으로 파생본 폭이 과하지 않은지 봅니다. - 포맷:
AVIF,WebP,JPEG,PNG,SVG를 이미지 성격에 맞춰 나눕니다. - 우선순위:
fetchpriority,lazy,preload가 서로 충돌하지 않는지 봅니다. - 레이아웃 안정성:
width,height,aspect-ratio가 있는지 확인합니다. - 검증: DevTools에서
LCP,Image Decode,Layout,Paint를 다시 확인합니다.
다운로드 바이트만 줄이면 끝나는 문제였다면 이미지 최적화는 훨씬 단순했을 것입니다. 실제로는 DOM과 CSSOM 위에서 어떤 시점에 발견되고, 렌더 트리에 언제 반영되고, 디코드와 페인트가 얼마나 걸리는지까지 보아야 “느리다”는 체감이 줄어듭니다. 그래서 큰 이미지를 다룰 때는 포맷, 크기, 로딩 전략을 따로 보지 않고 브라우저 렌더링 흐름 안에서 함께 보는 편이 더 정확합니다.
공식 문서와 레퍼런스
- MDN: Image file type and format guide
- MDN: Using responsive images in HTML
- MDN: HTML attribute: fetchpriority
- MDN: rel="preload"
- web.dev: Optimize Largest Contentful Paint
- web.dev: Optimize resource loading with the Fetch Priority API
- Chrome DevTools: Network features reference
- Chrome DevTools: Performance features reference
원문 참고
https://www.maeil-mail.kr/question/54
댓글
댓글 쓰기