이미지를 빠르게 만드는 핵심은 화질을 버리는 게 아니라 ‘낭비를 빼는 것’입니다. webp·avif 포맷, 표시 크기의 2배까지만 쓰는 적정 해상도, width·height로 자리를 미리 잡아 화면이 출렁이지 않게 하기, 그리고 첫 화면은 우선 로드하고 나머지는 뒤로 미루기. Findable은 이걸 기본값으로 깔고 시작합니다.
요약
- 포맷부터 바꾼다 — 같은 화질이면 webp·avif가 JPG·PNG보다 가볍다.
- 해상도는 표시 크기의 2배까지만. 화면엔 안 보이는데 용량만 키우는 픽셀을 뺀다.
- img에 width·height를 적어 자리를 미리 잡으면 글자가 밀리지 않는다(CLS 방지).
- 첫 화면 히어로는 우선 로드, 스크롤해야 보이는 건 lazy loading으로 미룬다.
예전에 한 페이지를 받아서 “느리다”는 민원을 처리한 적이 있습니다. 코드는 깔끔했어요. 범인은 배경에 깔린 사진 한 장이었습니다. 디자이너가 보내준 원본을 그대로 넣어둔 거였죠. 그 한 장을 포맷 바꾸고 크기 맞추고 다시 올리니, 같은 화면이 한결 빨리 떴습니다. 그날 배운 게 있습니다. 이미지는 ‘넣는 것’이 아니라 ‘준비해서 넣는 것’이라는 거요.
왜 이미지가 사이트 속도의 주범이 되나요?
HTML과 CSS는 보통 가볍습니다. 무게의 대부분은 이미지입니다. 디자인 시안에서 받은 사진은 인쇄해도 될 만큼 큰 경우가 많은데, 그걸 그대로 웹에 올리면 사용자는 화면에 다 쓰지도 못할 픽셀을 통째로 내려받습니다. 그래서 저는 이미지 작업을 ‘세 단계’로 봅니다. 어떤 포맷으로, 어떤 크기로, 어떤 순서로 보낼 것인가.
포맷만 바꿔도 가벼워지나요?
가장 먼저 손대는 게 포맷입니다. JPG·PNG 대신 webp나 avif를 쓰면 같은 화질을 더 작은 용량에 담습니다. 사진은 webp/avif, 로고·아이콘처럼 선이 또렷해야 하는 건 svg로 갑니다(svg는 아무리 키워도 안 깨지고 용량도 거의 안 늘어요). 아래 위젯에서 같은 그림이 포맷·크기에 따라 얼마나 달라지는지 감을 잡아보세요.
흐릿하게 먼저, 또렷하게 나중에
'다시 불러오기'를 누르면 저용량 미리보기가 먼저 뜨고 원본이 또렷해집니다. 빈칸 대신 형태부터 보여주는 기법이에요.
해상도는 클수록 좋은 것 아닌가요?
아닙니다. 화면에 400px로 보이는 이미지에 3000px 원본을 넣으면, 사용자 눈에는 똑같은데 용량만 몇 배로 무겁습니다. 제 기준은 ‘표시되는 크기의 2배까지’입니다. 고해상도(레티나) 화면을 고려해도 2배면 충분하고, 그 이상은 낭비예요. 거기에 화면 크기별로 다른 이미지를 내려주면(모바일엔 작은 것, 데스크톱엔 큰 것) 휴대폰 사용자가 쓸데없이 큰 파일을 받지 않습니다.
이미지가 뜨면서 글자가 밀리는 건 왜 그런가요?
스크롤하다 글을 읽으려는 순간 이미지가 ‘툭’ 들어오면서 내용이 아래로 밀린 경험, 있으시죠. 이게 레이아웃이 출렁이는 현상(CLS)입니다. 브라우저가 이미지 크기를 모른 채 글부터 그렸다가, 이미지가 도착하면 자리를 만들면서 밀어내는 거예요. 해법은 간단합니다. img에 width와 height를 적어 두면 브라우저가 빈자리를 미리 잡아둡니다. 사진이 도착하기 전에도 자리가 비어 있으니 화면이 흔들리지 않아요. 저는 이걸 절대 빼먹지 않습니다.
화면 밖 이미지는 어떻게 다루세요?
첫 화면에 보이지도 않는 이미지를 처음부터 다 내려받을 이유가 없습니다. 스크롤해야 보이는 이미지는 loading="lazy"로 미뤄둡니다. 그러면 첫 화면이 먼저 가볍게 뜨고, 사용자가 내려갈 때쯤 이미지가 따라옵니다. 다만 주의할 게 있어요. 첫 화면에 바로 보이는 히어로 이미지에 lazy를 걸면 오히려 늦게 뜹니다. 그래서 히어로는 우선 로드, 나머지는 lazy — 이 구분을 안 하면 최적화가 거꾸로 됩니다.
지금까지 말한 포맷·크기·순서를 마크업 한 덩어리로 묶으면 이렇게 됩니다. 제가 본문 이미지에 거의 그대로 쓰는 형태예요.
<picture>
<!-- 지원하면 더 가벼운 avif → webp 순으로, 안 되면 jpg -->
<source type="image/avif" srcset="hero-800.avif 800w, hero-1600.avif 1600w">
<source type="image/webp" srcset="hero-800.webp 800w, hero-1600.webp 1600w">
<img src="hero-800.jpg"
srcset="hero-800.jpg 800w, hero-1600.jpg 1600w"
sizes="(max-width: 640px) 100vw, 800px"
width="800" height="450" <!-- 자리를 미리 잡아 CLS 0 -->
loading="lazy" decoding="async"
alt="입주 가능한 84㎡ 거실 — 남향 통창">
</picture>그리고 시안에서 받은 원본을 그대로 올리지 않고, 빌드 때 한 번 변환·리사이즈를 돌려 용량이 실제로 떨어졌는지 눈으로 확인합니다.
$ npx sharp-cli -i hero.jpg -o hero.webp --quality 72 $ ✓ hero.jpg 1.8MB → hero.webp 0.34MB (적정 사이즈·webp 변환 후) $ ✓ 본문 <img> 12개 모두 width/height 지정 · 히어로 외 전부 loading=lazy
‘블러업’은 왜 빠르게 느껴지나요?
위 위젯에서 보셨듯, 빈 칸을 보여주면 사람은 ‘안 뜬다’고 느끼고, 흐릿한 미리보기라도 형태가 먼저 보이면 ‘뜨는 중’이라고 느낍니다. 실제 다운로드 시간은 비슷해도 체감이 다릅니다. 그래서 저는 아주 작은 저용량 미리보기를 먼저 깔고, 원본이 도착하면 또렷해지게 합니다. 이게 블러업 프로그레시브 로딩이에요. 기다림을 ‘빈 시간’이 아니라 ‘채워지는 시간’으로 바꾸는 작은 장치입니다.
| 항목 | 원본 그대로 | 최적화 |
|---|---|---|
| 속도 | 큰 파일 → 느린 첫 화면 | 포맷·크기 정리로 가볍게 |
| 검색 | 느린 페이지 → 평가 불리 | 빠른 페이지 + alt 텍스트로 이미지 검색까지 |
| 데이터 | 모바일에서 큰 파일 통째로 | 화면 크기별로 작은 파일 전송 |
그래서 이미지 담당자가 보는 건 결국 뭔가요?
저는 이미지를 ‘예쁜 그림’이 아니라 ‘무게를 가진 파일’로 봅니다. 한 장 한 장이 사용자의 시간이고 데이터예요. 그 한 장을 진지하게 다루는 사람이라면, 폰트도 코드도 같은 태도로 다룹니다. Findable에서는 이런 디테일이 기본값입니다. 당신의 사이트, 어떤 이미지부터 가볍게 만들어 드릴까요?
다른 담당자와의 연결
이미지는 혼자 사는 게 아닙니다. 속도와도, 자리와도 한 몸이에요. 이미지를 줄이는 일은 결국 사이트 전체 성능을 끌어올리는 작업의 한 축이고, 흐릿하게 먼저 보여주는 블러업은 로딩 연출을 맡은 동료의 영역과 맞닿아 있습니다. 그리고 이미지가 들어올 자리를 미리 잡아 화면이 출렁이지 않게 하는 일(CLS)은 레이아웃을 짜는 사람과 함께 풀어야 합니다. 좋은 사이트는 이렇게 각자의 담당이 같은 디테일을 공유할 때 나옵니다.
webp나 avif로 바꾸면 화질이 떨어지지 않나요?
레티나(고해상도)라서 이미지를 크게 넣어야 하지 않나요?
이미지가 뜰 때 글자가 아래로 밀리는 건 왜 그런가요?
lazy loading은 모든 이미지에 다 켜면 되나요?
블러업(흐릿하게 먼저 보이는 것)은 꼭 필요한가요?
사이트가 빨라야 하는 이유
이미지·코드·로딩까지, 전체 속도 이야기.
로딩 담당자의 기다림 설계
빈 화면을 채워지는 시간으로 바꾸는 연출.
레이아웃 담당자의 자리 잡기
화면이 출렁이지 않게 자리를 미리 잡는 법.
이 글의 위젯은 이 페이지에서 실제로 동작하는 코드입니다. 본문의 용량·속도 이야기는 이미지 최적화의 일반 원칙이며, 특정 수치나 성과를 보장하지 않습니다. 날조된 사례·수치는 사용하지 않았습니다.