pile·
프론트엔드·크리에이트립크리에이트립·

웹뷰 속 무한 CSS 애니메이션의 숨은 비용

React Native 앱 내 WebView에서 실행되는 무한 CSS 애니메이션이 Chrome에서는 멀쩡하지만 Android WebView에서 CPU 90~102%를 유발하는 문제를 재현·측정·원인 분석한 엔지니어링 사례. will-change와 translateZ(0)는 효과가 없었으며, WebView의 아키텍처적 한계(호스트 앱 View 계층 통합)가 근본 원인임을 규명하고 실효 해법을 제시한다.

핵심 포인트
  • 증상: 오디오 플레이어 화면 표시 시 앱 CPU 96~102% (WebView 샌드박스 21~23%), 오프스크린 시 3~6%로 급감
  • 재현 범위 전수: box-transform(95%), text-transform(96%), opacity-animation(94%), marquee-text(87%) — 모든 무한 CSS 애니메이션 유형 재현
  • 근본 원인: WebView는 독립 컴포지터 패스를 가진 Chrome과 달리, 호스트 Android 앱의 View 렌더링 계층에 컴포지터 프레임을 통합해야 함 → 연속 onDraw 호출 + RenderThread 깨어남
  • 효과 없는 최적화: will-change: transform, translateZ(0) — 메인 스레드 부하는 줄여도 호스트 View 통합 오버헤드 제거 불가
  • 측정 도구: Android top(프로세스 CPU), gfxinfo(6초 측정에서 ~1,367 프레임), 제품 코드에서 격리한 순수 Android WebView 하네스
  • 실효 해법: IntersectionObserver로 오프스크린 시 animation-play-state: paused 적용, React Native Animated API + useNativeDriver: true 위임, WebView 컨텍스트 감지 후 조건부 비활성화
상세 정리
  • Chrome vs WebView 아키텍처 차이: Chrome은 자체 컴포지터 패스로 독립적 프레임 처리 가능, WebView는 "다른 Android 앱 안에 들어가는 View일 뿐" — 레이아웃/페인트 최적화를 해도 컴포지터 통합 비용 잔존
  • gfxinfo 지표: 화면 표시 시 6초 동안 ~1,367 프레임 발생, 오프스크린 시 4초 동안 0 프레임 — 렌더링 자체가 완전히 중단됨
  • 정적 콘텐츠 + 일시정지 애니메이션: CPU 거의 0 — 애니메이션 실행 여부가 핵심 변수
  • 재현 하네스: 제품 코드에서 격리한 순수 Android WebView 환경에서 Chrome과 동일 HTML로 비교 측정
  • WebView 컨텍스트 감지: userAgent 분기로 WebView 환경에서는 애니메이션 클래스를 조건부 비활성화
  • IntersectionObserver 활용: 화면에서 사라지는 순간 paused 적용, 재진입 시 재개 — 가시 구간에만 CPU 소모
  • 마퀴 텍스트 대안: text-overflow: ellipsis + line-clamp 조합으로 무한 스크롤 애니메이션 없이 시각적 목적 달성
  • prefers-reduced-motion: OS 수준 접근성 설정을 CSS 미디어 쿼리로 감지해 모션 비활성화
  • CSS 마이크로 최적화보다 애플리케이션 레벨 해법 우선: React Native native driver는 JS 스레드 우회 → 근본적 CPU 절감
  • 교훈: WebView와 Chrome이 같은 HTML을 다르게 처리하는 지점을 아키텍처 수준에서 파악하지 않으면, 표면적 최적화만 반복하게 됨
왜 읽나React Native + WebView 조합에서 CSS 무한 애니메이션이 CPU를 폭발시키는 이유를 컴포지터 아키텍처 레벨에서 규명하고, 실측 수치와 함께 IntersectionObserver pause 및 native driver 위임 같은 실효 해법을 배울 수 있다.
크리에이트립
크리에이트립 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 프론트엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

    항공 프론트엔드 구축기 (7/10): 창구를 하나만 두었습니다

    여기어때 항공 서비스 프론트엔드가 웹과 앱 웹뷰 두 환경에서 동일한 함수 호출로 동작하는 앱 브릿지 추상화 레이어를 설계한 과정을 다룬다. iOS·안드로이드 규약 차이와 "웹에 존재하지 않는 브릿지를 어떻게 호출하나"라는 문제를 단일 추상화 층으로 해결한 구현 사례다.

    요약 이어보기
    #react#typescript#webview+2