좋은 웹 모션은 화려함이 아니라 ‘시선 안내’입니다. transform·opacity만 0.4~0.7초로 짧게, 한 번에 하나씩 움직이고, prefers-reduced-motion을 존중하면 멀미 없이 살아있는 사이트가 됩니다. Findable의 모션은 외부 라이브러리 0으로 가볍게 구현됩니다.
요약
- 모션의 품질은 거리가 아니라 이징 곡선에서 나온다.
- transform·opacity만 움직이면 60fps, layout 속성을 건드리면 끊긴다.
- 한 번에 하나씩 — 다 움직이면 아무것도 강조되지 않는다.
- prefers-reduced-motion을 켠 사용자에겐 애니메이션을 끈다(멀미·접근성).
제가 처음 만든 랜딩은 모든 게 통통 튀었습니다. 뿌듯했죠. 그런데 사용자 테스트에서 한 분이 “예쁜데… 좀 어지러워요”라고 했습니다. 그때 깨달았습니다. 모션은 제 실력을 자랑하는 자리가 아니라, 사용자의 시선을 모시는 일이라는 걸. 지금부터 보여드리는 건 ‘자랑’과 ‘안내’의 경계에서 제가 고른 것들입니다.
모드 1 — 스태거(Stagger): 한 박자씩 들어오기
여러 요소를 동시에 띄우면 묵직하고, 0.07초씩 시차를 두면 ‘리듬’이 생깁니다. 화면에 들어올 때 아래 칩들이 어떻게 들어오는지 보세요.
// 위로 스크롤했다 다시 내려오면 또 재생됩니다.
모드 2 — 텍스트 리빌: 글자가 ‘올라오며’ 등장
헤드라인은 그냥 나타나는 것보다, 마스크 뒤에서 한 단어씩 올라오면 무게가 실립니다. 첫 화면 카피에 자주 씁니다.
당신 브랜드가 AI 답변에 등장합니다
모드 3 — 패럴럭스: 깊이를 만드는 시차
스크롤할 때 레이어마다 다른 속도로 움직이면 평면이 입체가 됩니다. 단, 과하면 멀미의 주범이라 ‘아주 살짝’이 핵심입니다. 천천히 스크롤해 보세요.
// 동그라미와 사각형이 배경판과 다른 속도로 따라옵니다.
모드 4 — 스프링 호버 & 스크롤 스크럽
호버에 ‘스프링(살짝 튕기는)’ 이징을 주면 기계가 아니라 생물처럼 느껴집니다. 그리고 스크롤 진행도에 묶인 바(scrub)는 ‘내가 어디쯤인지’를 알려줍니다.
// 위 바는 이 글을 스크롤하면 길이가 바뀝니다(맨 위 진행바도 같은 원리).
모드 5 — 마퀴 & 카운트업 & SVG 드로우
끊김 없이 흐르는 마퀴, 숫자가 차오르는 카운트업, 선이 그려지는 SVG. 셋 다 ‘시간’을 디자인하는 방법입니다.
// 숫자와 선은 이 블록이 화면에 들어올 때 재생됩니다.
모션에 대해, 나만 아는 실무 이야기
1. 품질은 ‘거리’가 아니라 ‘곡선’에서 나옵니다
똑같이 20px 올려도 linear면 로봇 같고, cubic-bezier로 가속·감속을 주면 살아납니다. 저는 새 효과를 만들 때 모양보다 이징을 먼저 정합니다. 위 스프링 버튼의 ‘튕김’도 이징 한 줄의 차이입니다.
2. 60fps의 규칙: layout을 건드리지 마라
width·height·top·margin을 애니메이션하면 브라우저가 매 프레임 레이아웃을 다시 계산해 끊깁니다. 저는 오직 transform과 opacity만 움직입니다. 그래서 이 페이지는 효과가 이렇게 많은데도 가볍습니다.
위 모드 1(스태거)의 칩들이 ‘올라오며 켜지는’ 등장도 결국 이 keyframe 하나입니다. transform과 opacity만 건드리는 게 핵심이라, 그대로 복사해 어떤 등장 효과에도 쓰실 수 있습니다.
@keyframes rise{
from{ opacity: 0; transform: translateY(16px); } /* layout 속성 X */
to { opacity: 1; transform: translateY(0); }
}
.chip{
animation: rise .55s cubic-bezier(.2,.8,.2,1) both; /* 곡선이 품질을 만든다 */
}
.chip:nth-child(2){ animation-delay: .07s; } /* 스태거 — 한 박자씩 */
.chip:nth-child(3){ animation-delay: .14s; }
@media (prefers-reduced-motion: reduce){
.chip{ animation: none; opacity: 1; transform: none; }
}같은 등장이라도 cubic-bezier 곡선 한 줄과 0.07초씩의 animation-delay가 ‘리듬’을 만듭니다. 거리가 아니라 곡선과 타이밍이 품질을 좌우합니다.
3. 한 화면에 ‘주인공’은 하나
모든 게 움직이면 위계가 사라집니다. 저는 한 섹션에서 가장 중요한 하나에만 모션을 몰아주고 나머지는 절제합니다. 절제가 곧 강조입니다.
4. prefers-reduced-motion은 타협 대상이 아닙니다
전정기관이 예민한 분, 멀미가 있는 분에게 과한 모션은 고통입니다. OS에서 ‘동작 줄이기’를 켠 사용자에겐 저는 애니메이션을 끕니다. 이 페이지도 그 설정을 존중합니다. 멋은 누군가를 배제하면서까지 부릴 게 아닙니다.
| 항목 | 자랑용 모션 | 안내용 모션 |
|---|---|---|
| 목적 | “나 이런 것도 할 줄 알아” | 시선 안내·상태 설명 |
| 속성 | width·top 변경 | transform·opacity (60fps) |
| 양 | 전부 움직임 | 주인공 하나만 |
| 배려 | reduced-motion 무시 | 설정 존중·끔 |
이 감각으로, 당신의 사이트를 움직입니다
모션은 마지막에 ‘뿌리는’ 장식이 아니라 처음부터 설계의 일부입니다. 시선을 어디로 보낼지, 무엇을 강조할지 정한 다음 거기에 딱 맞는 움직임만 남깁니다. 어지럽지 않게, 그러나 분명히 살아있게.
애니메이션이 많으면 사이트가 느려지나요?
스크롤 애니메이션이 멀미를 유발하지 않나요?
좋은 애니메이션과 나쁜 애니메이션의 차이는?
이징(easing)이 그렇게 중요한가요?
라이브러리 없이도 이런 모션이 되나요?
버튼 담당자의 노트
특별한 버튼 8종을 직접 눌러보세요.
사이트 속도 — 코어 웹 바이탈
60fps를 지키는 성능 실무.
역량 — 라이브 데모
인터랙션 8종 모음.
이 글의 모든 모션은 이 페이지에서 실제로 동작하는 코드입니다(CSS + 바닐라 JS, 외부 애니메이션 라이브러리 0, prefers-reduced-motion 대응). 수치(60fps 등)는 transform·opacity 기준의 일반 원칙이며 환경에 따라 다를 수 있습니다. 날조된 사례는 사용하지 않았습니다.