웹 사이트를 만들 때 보통 디자인 도구(Figma 등)에서 만든 이미지들을 그냥 PNG나 JPEG로 뽑아서 아무 생각 없이 프로젝트에 넣곤 했습니다.
그러다 최근 진행했던 웹 서비스에서 큰 문제를 하나 만났습니다. 메인 화면에 들어가는 고화질 배너 이미지 몇 개를 PNG 파일 그대로 넣었더니, 이미지 파일 몇 개 용량만 합쳐도 5MB가 훌쩍 넘어가는 참사가 일어난 것입니다.
모바일로 접속했을 때 이미지가 위에서부터 천천히 스캔되듯이 지저분하게 내려오면서 로딩되는 모습을 보고 "아, 이미지 포맷부터 당장 바꿔야겠다"는 결심을 하게 되었습니다.
오늘은 구시대 포맷인 PNG/JPEG를 버리고 차세대 포맷인 WebP와 AVIF로 전환하면서 겪었던 과정과, 실무에서 브라우저 깨짐 없이 안전하게 적용했던 노하우를 공유해 봅니다.
1. 내가 부딪힌 문제: "화질은 포기하기 싫고, 용량은 너무 크다"
프로젝트 배너에 글씨와 그래픽이 섞여 있다 보니, 화질이 깨지는 JPEG 대신 깨끗하게 나오는 PNG 포맷을 사용했습니다. 하지만 PNG는 무손실 압축 방식이라 파일 용량이 어마무시하게 컸습니다.
- 메인 배너 PNG 파일 1개 용량: 무려 2.4 MB
- 문제점: 접속할 때마다 유저의 데이터와 시간을 엄청나게 갉아먹고 있었고, 네트워크가 조금만 느려도 화면이 텅 비어 보이는 현상 발생.
화질을 떨어뜨리지 않으면서 용량만 획기적으로 줄일 수 있는 방법을 찾다가 구글이 만든 WebP와 차세대 비디오 코덱 기반의 AVIF 포맷을 알게 되었습니다.
2. 해결책 1: HTML <picture> 태그로 구형 브라우저 호환성 지키기
WebP나 AVIF가 아무리 용량이 작고 좋아도, "혹시 최신 포맷을 지원하지 않는 구형 브라우저에서는 이미지가 엑박(X)으로 깨지면 어쩌지?" 하는 걱정이 들었습니다.
이 문제를 구원해 준 것이 바로 HTML5의 <picture> 태그였습니다. 브라우저에게 "네가 AVIF를 지원하면 AVIF를 보여주고, 안 되면 WebP를, 그것도 안 되면 기존 JPEG를 보여줘" 하고 우선순위를 정해주는 방식입니다.
<!-- ⭕ 내 프로젝트에 직접 적용한 크로스 브라우징 picture 태그 -->
<picture>
<!-- 1. 가장 가볍고 최신인 AVIF 포맷을 최우선으로 시도 -->
<source srcset="/images/main-banner.avif" type="image/avif" />
<!-- 2. AVIF 미지원 시 WebP 포맷 사용 -->
<source srcset="/images/main-banner.webp" type="image/webp" />
<!-- 3. 최신 포맷을 둘 다 지원하지 않는 구형 브라우저용 기본 이미지 -->
<img
src="/images/main-banner.jpg"
alt="메인 프로모션 배너"
width="1200"
height="600"
loading="lazy"
/>
</picture>
이렇게 코드를 짜두니 에러 걱정 없이 마음 편하게 최신 이미지 포맷을 도입할 수 있었습니다.

3. 해결책 2: Node.js(Sharp)로 자동 변환 스크립트 만들어 버리기
이미지가 한두 개가 아니다 보니 일일이 변환 사이트에 업로드해서 다운로드하는 작업이 너무 귀찮았습니다. 그래서 Node.js의 이미지 처리 라이브러리인 sharp를 활용해, 명령어 하나만 치면 프로젝트 내 모든 PNG 파일이 WebP와 AVIF로 자동 변환되는 스크립트를 직접 짜서 해결했습니다.
// convert.js (내가 직접 만든 이미지 자동 변환 스크립트)
const sharp = require('sharp');
const path = require('path');
const inputPath = path.join(__dirname, 'public/images/main-banner.png');
// PNG를 WebP로 자동 변환 (품질 80% 설정)
sharp(inputPath)
.webp({ quality: 80 })
.toFile(path.join(__dirname, 'public/images/main-banner.webp'))
.then(() => console.log('✅ WebP 변환 성공!'));
// PNG를 AVIF로 자동 변환 (품질 75% 설정)
sharp(inputPath)
.avif({ quality: 75 })
.toFile(path.join(__dirname, 'public/images/main-banner.avif'))
.then(() => console.log('🚀 AVIF 변환 성공!'));
터미널에서 node convert.js만 실행하면 몇 초 만에 고용량 PNG가 초경량 파일들로 쓱 변환되어 나와서 개발 생산성이 엄청나게 올라갔습니다.
4. 직접 눈으로 확인한 용량 비교: "2.4MB가 210KB가 되는 기적"
변환을 마치고 폴더 안에 있는 동일한 이미지의 포맷별 파일 용량을 직접 확인해 보았습니다.
- 기존 원본 PNG: 2,400 KB (2.4MB)
- WebP 변환 후: 420 KB (약 82% 용량 감소!)
- AVIF 변환 후: 210 KB (약 91% 용량 감소!)
화질은 눈으로 봤을 때 원본 PNG와 차이를 구분할 수 없을 정도로 선명한데, 파일 용량은 무려 10분의 1 수준으로 줄어들었습니다. 그 결과 메인 페이지에 진입할 때 이미지가 버벅거리지 않고 즉시 뜨는 쾌적한 환경을 만들 수 있었습니다.

5. 깨달은 점 및 요약
이전에는 프론트엔드 성능 최적화라고 하면 무조건 복잡한 코드 리팩토링이나 상태 관리 최적화만 생각했었습니다.
하지만 이번 경험을 통해 이미지 포맷을 WebP나 AVIF로 바꾸는 것 같은 단순한 시도가 웹사이트 성능에 얼마나 파격적인 영향을 주는지 깨달았습니다.
혹시 지금 만들고 계신 프로젝트의 로딩 속도가 답답하다면, 소스 코드보다 먼저 '내가 넣은 이미지 파일의 포맷과 용량'부터 점검해 보시면 좋을 것 같습니다!
'개발' 카테고리의 다른 글
| [Next.js] 메인 페이지 로딩 속도가 3초? Next.js Image 컴포넌트로 0.8초까지 줄여본 삽질기 (0) | 2026.07.29 |
|---|---|
| [React] useState와 useEffect 실무 적용 중 겪었던 3가지 초보적 실수와 해결책 (0) | 2026.07.28 |
| [Git] "내 코드가 어디 갔지?" 초보 개발자가 자주 범하는 Git 실수 3가지와 해결법 (0) | 2026.07.28 |
| [CSS] Tailwind CSS 도입 후기: BEM 클래스명 지옥 탈출과 가독성 극복 전략 (0) | 2026.07.28 |
| [Web] 웹 액세서빌러티(A11y): 모두를 위한 접근성 높은 인터페이스 구축 (1) | 2026.05.06 |