디자이너의 스킬업을 위한 lottie.js 완벽 이해하기 강의를 기반으로 작성한 포스팅입니다.
Lottie.js란 무엇인가?
“Lottie는 JSON 기반의 애니메이션 파일이에요. 디자이너는 Lottie를 통해 애니메이션을 이미지만큼 쉽게 옮길 수 있습니다. 용량이 작지만 어떤 기기에서나 작동하고, 크기를 자유롭게 조정해도 해상도가 낮아지지 않아요.”
Lottie는 Airbnb에서 만든 애니메이션 라이브러리로, 움직이는 이미지를 GIF나 비디오가 아닌 스크립트로 구현할 수 있다. 벡터 기반의 애니메이션을 JSON 파일로 변환해주기 때문에 GIF 특유의 버벅거림 없이 부드러운 애니메이션을 구현할 수 있다.
Lottie.js 환경설정
1) Bodymovin 설치
Lottie를 사용하기 위해서는 After Effects에 Bodymovin이라는 플러그인을 설치해야 한다.
(https://airbnb.io/lottie/#/after-effects 👈 공식문서에 설치과정이 친절하게 설명이 되어있다.)
Bodymovin 설치를 완료했다면, After Effects를 실행하고 상단 메뉴 [window → extensions] 에서 Bodymovin을 확인할 수 있다. (아래 화면과 같이 1→2→3→4 순서로 렌더링 준비를 하면 된다.)
Bodymovin 최신버전 오류
현재 공식 문서 내에 안내되어있는 Bodymovin의 버전은 5.12.2이다. 해당 버전을 설치했을 때, 컴포지션이 Bodymovin의 렌더링 대기열에 등록되지 않는 오류를 발견했고, 이전 버전 중 하나인 5.9.0 버전 설치를 통해 해결했다는 글을 발견했다. 덕분에 잘 사용하고 있다.
2) JSON 파일 적용
폴더구조 예시
📁 project folder
|
|- 📄 index.html
|- 📄 style.css
|- 📄 animation.js
|- 📜 leaf-data.json
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Lottie Animation</title>
</head>
<body>
<div id="lottie"></div>
<script src="<https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js>"></script>
<script src="animation.js"></script>
</body>
</html>
JavaScript
const params = {
container: document.getElementById("lottie"),
renderer: "canvas", // canvas, svg, html 3종류 지원, 주로 svg와 canvas를 사용한다고 함
loop: true, // false일 경우 한 번만 재생
autoplay: true, // false일 경우 특정 이벤트를 통한 재생 유도 필수
path: "leaf-data.json", // Bodymovin을 통해 변환한 JSON 파일 적용
};
const anim = lottie.loadAnimation(params);
Lottie 예제
Lottie.js 사용예제
공식문서의 usage 부분을 참고하면 특정 이벤트에 따라 의도한 대로 애니메이션을 작동할 수 있다. 아래에는 사용한 이벤트와 메소드 몇 가지를 소개해보겠다.
1) 마우스 이벤트 컨트롤
동일한 메서드라도 어떤 이벤트 아래에 위치하고 어떤 순서로 호출되는지에 따라 다양한 애니메이션 스타일을 정의할 수 있다.
anim.play()
: 애니메이션 재생anim.stop()
: 애니메이션 정지anim.pause()
: 애니메이션 일시정지anim.setDirection(direction)
: 애니메이션 방향 (1은 정방향, -1은 역방향)anim.setSpeed(speed)
: 애니메이션 속도 (1은 정상속도)
코드
const loopAni = document.querySelector(".ani-loop");
const hoverAni = document.querySelector(".ani-hover");
const reverseAni = document.querySelector(".ani-reverse");
const clickAni = document.querySelector(".ani-click");
const slowAni = document.querySelector(".ani-slow");
// 기본 loop 애니메이션 재생
const loopAnim = bodymovin.loadAnimation({
container: loopAni,
path: `json/${loopAni.dataset.file}.json`,
renderer: "svg",
loop: true,
autoplay: true,
});
// 마우스 오버시 애니메이션 재생
const hoverAnim = bodymovin.loadAnimation({
container: hoverAni,
path: `json/${hoverAni.dataset.file}.json`,
renderer: "svg",
loop: false,
autoplay: false,
});
hoverAni.addEventListener("mouseenter", () => {
hoverAnim.setDirection(1);
hoverAnim.play();
});
hoverAni.addEventListener("mouseleave", () => {
hoverAnim.setDirection(-1);
hoverAnim.play();
});
// 마우스 오버시 애니메이션 반대로 재생
const reverseAnim = bodymovin.loadAnimation({
container: reverseAni,
path: `json/${reverseAni.dataset.file}.json`,
renderer: "svg",
loop: false,
autoplay: true,
});
reverseAni.addEventListener("mouseenter", () => {
reverseAnim.setDirection(-1);
reverseAnim.play();
});
reverseAni.addEventListener("mouseleave", () => {
reverseAnim.setDirection(1);
reverseAnim.play();
});
// 클릭시 애니메이션 재생
const clickAnim = bodymovin.loadAnimation({
container: clickAni,
path: `json/${clickAni.dataset.file}.json`,
renderer: "svg",
loop: false,
autoplay: false,
});
clickAni.addEventListener("click", () => {
clickAnim.play();
});
// 마우스 오버시 애니메이션 느리게 재생
const slowAnim = bodymovin.loadAnimation({
container: slowAni,
path: `json/${slowAni.dataset.file}.json`,
renderer: "svg",
loop: true,
autoplay: true,
});
slowAni.addEventListener("mouseenter", () => {
slowAnim.setSpeed(0.2);
slowAnim.play();
});
slowAni.addEventListener("mouseleave", () => {
slowAnim.setSpeed(1);
});
2) 스크롤 애니메이션
스크롤 애니메이션을 구현할 때, 애니메이션 파일의 프레임 수와 스크롤 백분율을 일치시키지 않으면 부자연스럽게 애니메이션이 끊길 수 있으므로, 스크롤 백분율을 적절히 나누고 곱하여 조절해야 한다.
progressiveLoad
: JSON 애니메이션 파일이 로드될 때 애니메이션 데이터가 점진적으로 로드되는지 여부를 제어하는 옵션true
- 애니메이션 데이터가 점진적으로 로드- 애니메이션 파일이 크고 로딩 시간이 길어질 수 있는 경우 유용
false
- 애니메이션 데이터 한 번에 로드- 애니메이션 파일이 상대적으로 작고 로딩 시간이 짧은 경우 사용
anim.currentRawFrame
: 애니메이션의 현재 프레임anim.totalFrames
: 애니메이션의 전체 프레임 수anim.goToAndStop(value, isFrame)
: 애니메이션을 지정된 프레임으로 이동하고 해당 프레임에서 정지
코드
const elem = document.getElementById("bodymovin");
const animData = {
container: elem,
renderer: "svg",
loop: false,
autoplay: false,
rendererSettings: {
progressiveLoad: false,
},
path: "data/illust-about.json",
};
const anim = bodymovin.loadAnimation(animData);
function lottieScroll() {
let scrollPercent = Math.round(
(document.documentElement.scrollTop /
(document.documentElement.scrollHeight - window.innerHeight)) *
100
);
console.log(`스크롤 : ${scrollPercent}%`);
console.log(`현재 프레임 : ${anim.currentRawFrame}`);
console.log(`토탈 프레임 : ${anim.totalFrames}`);
anim.goToAndStop((scrollPercent / 100) * anim.totalFrames, true);
}
window.addEventListener("scroll", lottieScroll);
마무리
문서 내에 gif, video 등의 요소들을 추가할 때 마다 웹사이트가 무거워 지는 것 때문에 고민이 많았는데, Lottie가 해당 문제들을 깔끔하게 해결해 줄 수 있을 것 같아서 앞으로의 작업이 더욱 기대가 된다. Lottie를 자유자재로 활용하기 위해서는 다양한 툴들을 한 번에 다룰 수 있어야 하지만 그만큼 강력한 시너지를 보여주는 것 같다.
참고자료
https://lottiefiles.com/kr/what-is-lottie