0100dev

Vol. 02 – Safari Memory Issue

labN
2026. 03. 13.

안녕하세요. 제로백데브 프론트엔더 재균입니다.
제로백데브 Lab 포스팅을 통해 처음으로 인사드리게 되었습니다!

지난 2월은 제로백데브 홈페이지를 새로 리뉴얼하느라 바쁜 일정을 보냈습니다.
이번 프로젝트를 진행하면서 얻은 경험을 여러분께 소개드리면 좋을 것 같아서 준비했습니다!

이번 홈페이지 리뉴얼 프로젝트의 가장 큰 특징은 영상이었습니다. 디자이너분들과 협업하여 모션 영상을 여러 영역에 활용했어요.

섹션마다 루프 영상을 깔고, 모션감 있는 클립들도 곳곳에 배치했는데요. 스크롤 인터랙션이나 재생 타이밍 같은 부분을 스크립트로 직접 제어해야 해서 <video> 태그를 사용해 직접 구현했습니다.

결과물은 꽤 만족스러웠고, 크롬에서도 문제없었고, 제 단말에서도 문제가 없었습니다.




그런데... 검수 중에 이슈가 터졌습니다!

아이폰 단말의 사파리 브라우저에서 열었더니 페이지가 그냥 꺼져버렸어요.
확인할 수 있는 부분은 딱 하나. 사파리에서 뜨는 “문제가 반복적으로 발생했습니다.”

홈페이지에 다양한 효과들이 들어가 있었고 특정 디바이스에서만 발생하는 터라, 처음엔 뭐가 문제인지 특정하기가 어려웠어요. CSS 애니메이션인지, 자바스크립트 스크립트인지, 아니면 영상인지... 범위를 좁혀가면서 여러 테스트를 진행했습니다.

사파리 개발자 도구의 타임라인으로 퍼포먼스를 체크했을 때 드디어 패턴이 보이더라고요. 영상 요소가 로드되는 구간에서 메모리 사용량이 급격히 치솟고 있었고, 어느 시점을 넘어서자 탭이 종료되고 있었어요.


😱😱😱

원인은 "과한 영상"

여기서 잠깐, 비트레이트(bitrate) 라는 개념을 짚고 넘어갈게요.

비트레이트는 영상이 초당 얼마나 많은 데이터를 처리하는지를 나타내는 수치예요. 단위는 Mbps(Megabits per second) 를 쓰는데요. 쉽게 말해서, 이 수치가 높을수록 화질은 좋지만 재생하는 기기가 그만큼 더 많은 메모리와 처리 능력을 요구하게 됩니다.

문제는 브라우저마다 이 메모리를 관리하는 방식이 다르다는 점이에요.

크롬은 메모리 허용 한도가 상대적으로 넉넉한 편이라 고용량 영상 여러 개를 동시에 버퍼링해도 꽤 잘 버텨줘요. 반면 사파리, 특히 iOS 기반 환경의 WebKit은 탭당 메모리 한도가 훨씬 엄격하게 설정되어 있거든요. 한도를 초과하면 경고 한 번 없이 탭을 그냥 종료시켜버립니다.

 

저희 홈페이지에 올라간 영상들은 디자이너분께 받은 원본 그대로였어요. 고화질, 고비트레이트. 웹에서 여러 개를 동시에 로드하기엔 꽤 과한 스펙이었던 거죠.

당시 실제로 사용하던 <video> 태그는 이런 형태였어요.

<!-- 문제가 됐던 코드 — 원본 고용량 영상을 그대로 webm으로 변환해서 사용 -->
<video autoplay loop muted playsinline>
<source src="/videos/hero-section.webm" type="video/webm" />
</video>

페이지 안에 이런 태그가 여러 개 있었고, 모두 페이지 로드와 동시에 버퍼링을 시작하고 있었어요. 뷰포트에 보이지 않는 영상까지도요.

환경에 맞게 재인코딩

기존에는 WebM 포맷만 사용하고 있었어요. WebM은 압축 효율이 좋아서 용량 면에서는 유리하지만, 사파리에서 안정성 문제가 생길 수 있다는 걸 이번에 확인하게 됐거든요.

그래서 WebM은 유지하되, 사파리 안정성을 위해 재인코딩한 MP4를 폴백으로 함께 추가하는 방식으로 수정했어요.

<!-- 기존 코드 — WebM만 사용 -->
<video autoplay loop muted playsinline>
<source src="/videos/hero-section.webm" type="video/webm" />
</video>
<!-- 개선된 코드 — WebM 유지 + 사파리 안정성을 위한 MP4 폴백 추가 -->
<video autoplay loop muted playsinline>
<source src="/videos/hero-section.webm" type="video/webm" />
<source src="/videos/hero-section-optimized.mp4" type="video/mp4" />
</video>


브라우저는 <source> 태그를 위에서부터 순서대로 읽어서 지원 가능한 포맷을 선택해요. WebM을 지원하는 환경에서는 WebM을 재생하고, 그렇지 않은 환경(사파리 일부 버전 등)에서는 자동으로 MP4로 폴백되는 구조입니다.

재인코딩 후 사파리 타임라인을 다시 체크해보니 메모리 사용량이 안정적인 범위 안에서 유지가 되었습니다.


 

잠깐, 그냥 배경 영상이라면요?

저희는 영상을 스크립트로 직접 제어해야 하는 상황이었기 때문에 <video> 태그를 써서 직접 구현했는데요.

만약 단순히 배경 용도로만 영상을 사용하는 경우라면, 굳이 직접 파일을 호스팅하지 않아도 돼요.

Vimeo나 YouTube에 업로드한 뒤 사이트에 임베드하는 방식을 추천드립니다. 외부 플랫폼이 사용자 환경에 맞게 알아서 화질과 용량을 조절해서 스트리밍해주거든요. 브라우저 호환성도, 메모리 관리도 대부분 해결돼요. 직접 파일 관리하는 수고도 없고요.

 

이번 경험에서 얻은 것

이번 이슈를 겪으면서 가장 크게 느낀 건 하나예요.

"내가 아는 환경에서 된다고 다가 아니다."

개발하다 보면 자연스럽게 내 기기, 내가 주로 쓰는 브라우저가 기준이 되어버리는 경우가 많은데요. 실제 사용자는 정말 다양한 기기와 브라우저, 다양한 버전 위에서 사이트를 열어봅니다.

특히 영상처럼 리소스를 많이 쓰는 요소일수록, 처음부터 최대한 다양한 환경을 고려한 설계가 필요하다는 걸 이번 삽질로 제대로 배웠어요.

앞으로도 제로백데브 Lab은 개발하면서 겪은 시행착오들을 솔직하게 풀어볼게요.

다음 실험도 기대해주세요!