웹에 Lottie 넣는 3가지 방법 — lottie-web부터 dotlottie-wc까지
웹에서 Lottie를 재생하는 방법은 크게 세 갈래입니다. 정통 lottie-web, 경량 @lottiefiles/dotlottie-web, 그리고 프레임워크 없이 쓰는 웹 컴포넌트. 프로젝트 성격에 따라 정답이 다릅니다.
방법 1 — lottie-web (정통, 기능 최다)
Airbnb 오리지널 구현체이자 사실상의 레퍼런스입니다. SVG/Canvas 렌더러를 고를 수 있고 API가 가장 풍부합니다.
npm install lottie-web
import lottie from "lottie-web";
const anim = lottie.loadAnimation({
container: document.getElementById("box"),
renderer: "svg", // "canvas"도 가능
loop: true,
autoplay: true,
path: "/assets/loading.json",
});
anim.setSpeed(1.5); // 재생 속도
anim.playSegments([0, 30], true); // 구간 재생
anim.goToAndStop(15, true); // 특정 프레임
장점 — 표현식 등 지원 범위가 가장 넓고, 오래된 파일과의 호환성이 좋습니다. DOM으로 렌더되는 SVG 모드는 CSS로 부분 스타일링도 가능합니다.
단점 — 번들 크기가 큽니다(전체 빌드 약 250KB, light 빌드 약 140KB). 애니메이션 수십 개를 동시에 SVG로 돌리면 DOM 비용이 큽니다.
방법 2 — dotlottie-web (경량, 현대적)
LottieFiles가 만든 차세대 런타임입니다. WASM 렌더러가 캔버스에 그리며, .lottie와 .json을 모두 재생합니다.
npm install @lottiefiles/dotlottie-web
import { DotLottie } from "@lottiefiles/dotlottie-web";
new DotLottie({
canvas: document.querySelector("#canvas"),
src: "/assets/loading.lottie", // .json도 OK
loop: true,
autoplay: true,
});
장점 — JS 번들이 훨씬 작고(WASM 별도 로드), 캔버스 렌더링이라 복잡한 씬에서 DOM 오버헤드가 없습니다. dotLottie의 멀티 애니메이션·테마 기능을 그대로 활용합니다.
단점 — SVG DOM이 아니므로 CSS로 내부 요소를 건드릴 수 없습니다. 구형 파일 일부에서 렌더링 차이가 있을 수 있습니다.
방법 3 — 웹 컴포넌트 (빌드 없이 한 줄)
번들러 없는 정적 페이지나 CMS 환경이라면 웹 컴포넌트가 가장 빠릅니다.
<script type="module"
src="https://unpkg.com/@lottiefiles/dotlottie-wc@latest/dist/dotlottie-wc.js"></script>
<dotlottie-wc src="/assets/hero.lottie" autoplay loop
style="width:320px;height:320px"></dotlottie-wc>
성능 팁 4가지
- 화면 밖에서는 멈추세요 —
IntersectionObserver로 뷰포트를 벗어난 애니메이션을pause()하는 것만으로 CPU 사용량이 크게 떨어집니다. - 동시 재생 수를 제한하세요 — 목록 UI에서 셀마다 Lottie를 돌리면 저사양 기기가 버티지 못합니다. 보이는 것만 재생하세요.
- 렌더러를 상황에 맞게 — 아이콘 몇 개는 SVG, 복잡한 씬 여러 개는 Canvas/WASM이 유리합니다.
- 에셋 자체를 가볍게 — 런타임 튜닝보다 파일 최적화의 효과가 항상 큽니다. 배포 전 Lottie Inspector로 파일 크기·레이어 수를 확인하세요.
matchMedia("(prefers-reduced-motion: reduce)")가 참이면 자동재생을 끄고 정지 프레임을 보여주는 것이 접근성 모범 사례입니다.번들 크기, 실제로 얼마나 차이날까
숫자로만 보던 차이를 직접 확인한 건 이 사이트를 만들면서였습니다. 처음에는 습관적으로 lottie-web 전체 빌드를 넣었는데, 빌드 후 번들 분석 리포트를 열어 보니 사이트 전체 JS 중에서 lottie-web이 가장 큰 덩어리였습니다. 정작 재생하는 건 표현식도 없는 단순한 로딩 아이콘 하나였는데 말입니다.
그래서 light 빌드로 바꿨습니다. import 경로를 lottie-web/build/player/lottie_light로 바꾸기만 하면 되고, 표현식(expression) 지원이 빠지는 대신 용량이 눈에 띄게 줄어듭니다. 다만 표현식이 들어간 파일은 light 빌드에서 일부 동작이 빠진 채 재생되므로, 교체 전에 쓰고 있는 파일들이 표현식을 쓰는지 먼저 확인해야 합니다. 저는 뷰어에 올려 레이어 구성을 훑어본 뒤에 교체했습니다.
dotlottie-web은 조금 다른 눈으로 봐야 합니다. JS 번들 자체는 확실히 작지만, 렌더러가 WASM 파일로 분리되어 첫 재생 시점에 따로 로드됩니다. 번들 분석표에는 이 WASM이 잡히지 않기 때문에 "JS가 작으니 전송량도 작다"라고 읽으면 착시가 생깁니다. 제 프로젝트 기준으로는 초기 화면에 애니메이션이 꼭 필요하지 않았기 때문에, WASM을 나중에 받는 구조가 오히려 유리했습니다.
정리하면 저는 이렇게 고르고 있습니다. 표현식 없는 아이콘 몇 개면 light 빌드, 표현식이 필요한 복잡한 에셋이면 전체 빌드, 애니메이션 수가 많고 CSS로 내부를 건드릴 일이 없으면 dotlottie-web입니다.
SVG 렌더러를 쓰다 겪은 일
SVG 렌더러의 DOM 비용을 체감한 적이 있습니다. 사이드 프로젝트의 목록 화면에서 셀마다 작은 상태 표시용 Lottie를 SVG 렌더러로 재생했는데, 화면에 수십 개가 동시에 올라오자 스크롤이 눈에 띄게 버벅이기 시작했습니다. 애니메이션 하나만 놓고 테스트할 때는 전혀 문제가 없었기 때문에 처음에는 원인을 다른 곳에서 찾았습니다.
개발자 도구의 Elements 패널을 열어 보고서야 이유를 알았습니다. 애니메이션 하나가 수십에서 수백 개의 path, g 노드를 만들고, 매 프레임마다 그 속성이 갱신되고 있었습니다. 이것이 셀 수만큼 곱해지니 스타일 재계산 비용이 스크롤 렌더링과 경쟁하게 된 것입니다.
첫 번째 조치는 위 성능 팁 그대로였습니다. IntersectionObserver로 화면 밖 인스턴스를 pause()했더니 눈에 띄게 나아졌지만, 화면 안에 보이는 개수만으로도 저사양 기기에서는 버거웠습니다. 결국 renderer: "canvas"로 전환했고, 셀마다 수백 개씩 붙던 노드가 캔버스 엘리먼트 하나로 줄면서 문제가 정리됐습니다.
이후로는 기준을 단순하게 잡고 있습니다. CSS로 애니메이션 내부 요소를 건드릴 필요가 있으면 SVG, 재생만 하면 되고 개수가 늘어날 여지가 있으면 처음부터 캔버스입니다. SVG를 유지해야 한다면 rendererSettings의 progressiveLoad 옵션으로 초기 DOM 생성 비용을 프레임에 나눠 싣는 방법도 있습니다.