treeru.com
개발

Tailwind CSS 애니메이션 라이브러리의 함정 — tw-animate-css 15KB 줄이기

2026-01-31
Treeru

Tailwind CSS로 애니메이션을 넣고 싶을 때 가장 먼저 떠오르는 게 tw-animate-css입니다. npm install 한 줄이면 fadeIn, slideUp, bounce 같은 애니메이션을 Tailwind 유틸리티로 쓸 수 있습니다.

문제는 전체 import 하나로 15KB의 CSS가 번들에 추가된다는 점입니다. 실제로 사용하는 유틸리티가 2~3개뿐이어도 전체가 포함됩니다.

~15KB
전체 import
~3KB
필요한 것만
3~5개
사용 유틸리티
80%
절감률

1문제 — 15KB CSS 추가

PageSpeed Insights에서 "렌더링을 차단하는 리소스 제거" 항목을 보면, CSS 번들 크기가 표시됩니다. 빌드된 CSS를 분석해보니 애니메이션 관련 코드가 15KB나 차지하고 있었습니다.

// globals.css — 한 줄이 15KB를 추가한다
@import "tw-animate-css";

// 실제로 프로젝트에서 사용하는 클래스
// animate-fade-in        → 3곳
// animate-slide-in-up    → 2곳
// animate-fade-out       → 1곳
// 나머지 50+ 유틸리티    → 0곳

CSS는 렌더 차단 리소스

JavaScript와 달리 CSS는 기본적으로 렌더 차단입니다. 브라우저는 CSS를 모두 다운로드하고 파싱할 때까지 화면을 그리지 않습니다. 15KB의 미사용 CSS가 추가되면 FCP(First Contentful Paint)가 지연됩니다. Mobile 3G 환경에서 15KB는 약 200~400ms의 추가 지연을 의미합니다.

2tw-animate-css 내부 구조

tw-animate-css는 50개 이상의 애니메이션을 제공합니다. 내부적으로 각 애니메이션마다 @keyframes, @utility, 그리고 CSS 커스텀 프로퍼티를 정의합니다.

/* tw-animate-css 내부 — fadeIn 하나의 정의 */
@keyframes fade-in {
  from {
    opacity: 0;
  }
}

@utility animate-fade-in {
  animation: fade-in var(--tw-animate-duration, 0.3s)
    var(--tw-animate-easing, ease)
    var(--tw-animate-delay, 0)
    var(--tw-animate-iteration, 1)
    var(--tw-animate-fill, both);
}

/* + slideIn, slideOut, bounce, shake, spin,
   wiggle, pulse, ping, zoom... 등 50개 이상 */

Tailwind CSS v4는 사용하지 않는 유틸리티를 제거하지만, @keyframes유틸리티가 아니라 글로벌 정의이므로 tree-shaking 대상이 아닙니다. 사용 여부와 관계없이 모든 @keyframes가 CSS 번들에 포함됩니다.

3실제 사용 클래스 찾기

먼저 프로젝트에서 실제로 사용 중인 애니메이션 클래스를 찾아야 합니다.

# 프로젝트에서 animate- 클래스 사용 현황 검색
grep -r "animate-" --include="*.tsx" --include="*.ts" \
  -oh | sort | uniq -c | sort -rn

# 실행 결과 예시:
#  12 animate-pulse     ← Tailwind 기본 내장
#   6 animate-fade-in   ← tw-animate-css
#   3 animate-slide-in-up
#   1 animate-fade-out
#   ... (나머지는 0회)

주의: animate-pulse는 Tailwind 기본

animate-pulse, animate-spin, animate-bounce, animate-ping은 Tailwind CSS 기본 유틸리티입니다. 이것들은 tw-animate-css 없이도 사용 가능합니다. 검색 결과에서 기본 유틸리티를 제외하면 실제로 tw-animate-css에서 사용하는 것이 더 적을 수 있습니다.

4필요한 것만 추출하기

사용하는 유틸리티가 3개뿐이라면, 라이브러리를 통째로 import할 이유가 없습니다. 해당 부분만 globals.css에 직접 넣으면 됩니다.

/* globals.css — Before */
@import "tw-animate-css";  /* 15KB 전체 */

/* globals.css — After: 필요한 것만 */
/* @import "tw-animate-css";  ← 제거 */

/* fadeIn — 실제 사용 3곳 */
@keyframes fade-in {
  from { opacity: 0; }
}
@utility animate-fade-in {
  animation: fade-in 0.3s ease both;
}

/* slideInUp — 실제 사용 2곳 */
@keyframes slide-in-up {
  from { transform: translateY(20px); opacity: 0; }
}
@utility animate-slide-in-up {
  animation: slide-in-up 0.4s ease both;
}

/* fadeOut — 실제 사용 1곳 */
@keyframes fade-out {
  to { opacity: 0; }
}
@utility animate-fade-out {
  animation: fade-out 0.3s ease both;
}

15KB가 약 500Byte로 줄었습니다. 라이브러리 의존성도 하나 제거할 수 있습니다.

5@keyframes 직접 작성

라이브러리에서 추출하는 대신, 처음부터 직접 작성하는 것도 방법입니다. 실제로 웹에서 자주 쓰는 애니메이션은 몇 가지 안 됩니다.

애니메이션용도코드 양
fade-in요소 등장3줄
slide-in-up아래에서 위로 등장4줄
scale-in크기 커지면서 등장4줄
fade-out요소 퇴장3줄

대부분의 웹 애니메이션은 opacity + transform 조합입니다. 이 두 속성은 GPU 가속이 되기 때문에 성능도 좋습니다. 복잡한 bounce나 shake가 실제로 프로덕션에서 필요한 경우는 드뭅니다.

/* Tailwind v4 — 커스텀 유틸리티 정의 */

/* duration, delay 제어용 커스텀 프로퍼티 */
@property --tw-animate-duration {
  syntax: "<time>";
  inherits: false;
  initial-value: 0.3s;
}

@property --tw-animate-delay {
  syntax: "<time>";
  inherits: false;
  initial-value: 0s;
}

/* 이렇게 쓸 수 있음 */
/* <div className="animate-fade-in [--tw-animate-duration:0.5s]"> */

라이브러리가 적합한 경우도 있다

10개 이상의 다양한 애니메이션을 쓰는 프로젝트라면 tw-animate-css가 편합니다. 3~4개만 쓰는데 15KB를 추가하는 게 문제인 겁니다. 팀 규모와 유지보수 비용도 고려하세요. 직접 작성하면 "이 @keyframes가 뭐지?"라는 질문이 나올 수 있습니다.

6결과

항목BeforeAfter
애니메이션 CSS~15KB~0.5KB
라이브러리 의존성tw-animate-css없음
렌더 차단 시간+200~400ms무시 가능
시각적 차이없음 (동일한 애니메이션)

15KB가 0.5KB로 줄었습니다. 이것만으로 PageSpeed 점수가 극적으로 변하진 않지만, 한국어 웹폰트 최적화(26KB→3KB)와 합치면 렌더 차단 CSS가 약 38KB 줄어듭니다. Mobile 3G 환경에서 이 차이는 FCP에 직접 영향을 줍니다.

CSS 번들 최적화 체크리스트

애니메이션 라이브러리를 전체 import하기 전에, 실제 사용 클래스 수를 확인한다
3~4개만 쓴다면 해당 @keyframes + @utility만 직접 정의한다
Tailwind 기본 유틸리티(pulse, spin, bounce, ping)와 혼동하지 않는다
@keyframes는 tree-shaking 대상이 아님 — 미사용 코드가 번들에 포함된다
렌더 차단 CSS는 FCP에 직접 영향 — KB 단위로 줄이는 게 의미 있다

이 글의 수치는 tw-animate-css v1 기준이며, 라이브러리 버전에 따라 번들 크기가 다를 수 있습니다. Tailwind CSS v4 기준으로 작성되었습니다.

T

Treeru

웹 개발, IT 인프라, AI 솔루션 분야의 실무 인사이트를 공유합니다. 기업의 디지털 전환을 돕는 IT 파트너, Treeru입니다.

공유

댓글

(4개)
4.63/ 5

로그인하면 댓글을 작성할 수 있습니다.

2026-02-10
555.0

렌더 차단 CSS가 줄어들면 PageSpeed에서 '렌더링을 차단하는 리소스 제거' 항목이 개선되나요? 폰트 글에서도 같은 이슈를 봤는데 연결이 되네요.

2026-02-07
454.0

@keyframes 직접 작성하는 게 귀찮을 줄 알았는데, 실제로 해보니 10줄도 안 되네요. 라이브러리 의존성 하나 줄어드는 것도 좋고.

2026-02-05
4.554.5

grep으로 사용 중인 클래스 찾는 방법이 실용적이네요. 이거 한 번 돌려보니 3개만 쓰고 있었습니다.

관련 글

© 2026 TreeRU. All rights reserved.

본 콘텐츠의 저작권은 TreeRU에 있으며, 출처를 밝히지 않은 무단 전재 및 재배포를 금합니다. 인용 시 출처(treeru.com)를 반드시 명시해 주세요.