스크롤하지 않아도 보이는 영역에 애니메이션 GIF 세 개가 깔린 마케팅 랜딩 페이지가 있었습니다 — 제품 동작을 보여주는 히어로 루프, 그리고 두 개의 기능 애니메이션. 합계 11MB. Lighthouse는 모바일에서 페이지 점수를 64로 매겼고, LCP는 4.2초, Total Blocking Time은 380ms였습니다. 이 세 GIF를 MP4로 바꿔 — 같은 시각 콘텐츠, 같은 루프 동작 — 같은 오후에 92까지 갔습니다. 이 글은 그 과정을 그대로 풀어놓은 기록입니다.
출발점
페이지는 표준적인 Next.js 마케팅 사이트였습니다. Tailwind, 정적 생성, Vercel 배포. 세 GIF는 After Effects에서 720p, 30fps, 적당한 최적화로 내보낸 것이었습니다. 크기:
- 히어로 애니메이션 (5초, 720p): 5.8 MB
- 기능 1 (3초, 600p): 2.9 MB
- 기능 2 (4초, 600p): 2.4 MB
애니메이션 페이로드 합계: 11.1MB. Slow 4G(Lighthouse 모바일 프로파일)에서 완전 로드까지 약 27초. 페이지 텍스트는 빨리 그려졌지만 히어로는 너무 오래 "로딩 중" 자리표시자로 남아 있었고, 이게 정확히 LCP가 페널티를 주는 지점입니다.
출발 시점의 Lighthouse 보고서
| 지표 | 점수 |
|---|---|
| Performance | 64 |
| Largest Contentful Paint | 4.2초 |
| Total Blocking Time | 380ms |
| Speed Index | 5.8초 |
| Cumulative Layout Shift | 0.04 |
변환
각 GIF를 두 가지 설정으로 ffmpeg에 넣었습니다: 폭넓은 fallback을 위한 H.264 MP4, 그리고 지원하는 브라우저에서 더 작은 페이로드를 주는 VP9 WebM. 명령:
ffmpeg -i hero.gif -movflags faststart -pix_fmt yuv420p -crf 22 -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2:flags=lanczos" -an hero.mp4
ffmpeg -i hero.gif -c:v libvpx-vp9 -crf 30 -b:v 0 -deadline good -cpu-used 2 -row-mt 1 -pix_fmt yuv420p -an hero.webm
변환 후 크기는 인상적이었습니다:
| 자산 | GIF | MP4 (H.264) | WebM (VP9) |
|---|---|---|---|
| 히어로 | 5.8 MB | 320 KB (-94%) | 240 KB (-96%) |
| 기능 1 | 2.9 MB | 180 KB (-94%) | 140 KB (-95%) |
| 기능 2 | 2.4 MB | 150 KB (-94%) | 110 KB (-95%) |
총 페이로드는 H.264로 11.1MB → 650KB, VP9로 490KB까지 떨어졌습니다. 17~22배의 감소입니다.
마크업 변경
원래 마크업은 <img src="hero.gif" alt="...">. 교체본:
<video autoplay loop muted playsinline poster="hero-poster.jpg">
<source src="hero.webm" type="video/webm">
<source src="hero.mp4" type="video/mp4">
</video>
poster는 영상이 디코딩을 시작하기 전에 표시되는 정지 프레임(약 30KB JPEG)입니다. 이게 LCP 잠금 해제 포인트였습니다 — 브라우저가 poster를 contentful paint로 인정하면서 1초 이내에 들어왔습니다.
변환 후 Lighthouse 보고서
| 지표 | 이전 | 이후 |
|---|---|---|
| Performance | 64 | 92 |
| LCP | 4.2초 | 1.4초 |
| TBT | 380ms | 110ms |
| Speed Index | 5.8초 | 1.9초 |
| CLS | 0.04 | 0.02 |
LCP 67%, TBT 71% 감소. TBT가 좋아진 이유는, 소프트웨어 GIF 디코딩이 매 프레임마다 메인 스레드를 블로킹하고 있었기 때문입니다. 하드웨어 MP4 디코딩은 별도 프로세스로 오프로드됩니다.
주의 사항과 함정
- autoplay에는 muted 필수. 2018년 이후 iOS와 대부분 브라우저는 오디오가 있는 비디오의 자동재생을 막습니다. autoplay 루프에는 항상
muted를. - iOS에는 playsinline 필수. 없으면 iOS가 탭 시 풀스크린 플레이어로 엽니다.
- H.264는 짝수 차원. 코덱이 너비/높이 모두 2로 나눠떨어져야 합니다.
scale=trunc(iw/2)*2:trunc(ih/2)*2필터를 쓰세요. - Safari에는 yuv420p 필수. 다른 픽셀 포맷은 Chrome에서는 디코드되지만 Safari 에서는 조용히 실패합니다.
- 정적 장식에는 비디오를 쓰지 마세요. "애니메이션"이 거의 움직이지 않는다면 (느린 줌, 미묘한 팬), 정지 이미지나 CSS 애니메이션이 더 쌉니다.
Lighthouse 너머: 실제 사용자 영향
Lighthouse 점수는 합성 점수입니다. 진짜 봐야 할 지표는 필드 데이터 — 실제 네트워크 위의 실제 방문자입니다. 변경 후 2주 동안 본 것:
- 운영 환경 p75 LCP: 3.8초 → 1.6초 (Chrome User Experience Report)
- 이탈률: 모바일에서 -8% (GA 기준)
- CDN 대역폭 청구: 마케팅 사이트만 -$340/월
대역폭 절감보다, 이전에 팔레트 트릭과 디더링으로 GIF를 더 짜내려고 태운 엔지니어링 시간이 훨씬 컸습니다. 포맷 경계를 넘는 순간 그 모든 게 의미가 없어졌습니다.
당신 사이트에서 똑같이 하는 법
64에서 92로 데려간 다섯 단계:
- DevTools Network 탭에서 페이지의 모든
.gif를 찾으세요. - 각각을 MP4(H.264)와 WebM(VP9)로 변환하세요. 일회성이라면 저희 GIF → MP4 변환 도구가 두 포맷을 모두 처리하고 브라우저에서 실행됩니다. 파이프라인용이라면 위 ffmpeg 명령을 쓰세요.
- 각 비디오에 대한 정지 프레임 JPEG poster를 생성.
ffmpeg -i input.gif -vf "select=eq(n\\,0)" -vframes 1 poster.jpg. - 각
<img>를 위에 보인 대로<video>로 교체. - Lighthouse 재실행. 점수가 뛰었는지, LCP가 떨어졌는지 확인.
총 소요 시간: 우리가 관리하는 사이트 기준 페이지당 약 20분. 수천 명의 사용자가 보는 모든 페이지 뷰에 누적되는 효과 덕에, 올해 한 모든 성능 수정 중 단연 가장 레버리지가 큰 작업이 됐습니다.