Tailwind CSS

Tailwind CSS transition, animation, motion-reduce 사용 기준 정리

2026.04.29·수정 2026.05.12·약 17분

이 글에서 정리하는 내용

Tailwind CSS v4 기준으로를 정리합니다. 버튼 hover처럼 상태가 바뀌는 움직임로딩 스피너처럼 시간 흐름을 가진 움직임, 사용자의 모션 감소 설정을 고려해야 하는 움직임을 구분해 봅니다.

움직임 효과를 넣을 때 먼저 나눌 기준

Tailwind CSS에서 transition과 animation을 상태 변화와 시간 흐름 기준으로 구분하는 인포그래픽

Tailwind CSS에서 움직임을 넣을 때 처음 눈에 들어오는 것은 클래스 이름입니다.처럼 바로 붙일 수 있는 유틸리티가 많습니다. 그런데 실제 화면에서는 클래스 이름보다 먼저 봐야 할 것이 있습니다. 이 움직임이 사용자의 행동에 반응하는 변화인지, 화면이 스스로 반복하는 동작인지, 줄여도 되는 장식인지부터 나눠야 합니다.

버튼 hover는 사용자가 마우스를 올렸을 때 색상이 바뀌는 짧은 변화입니다. 카드 hover는 그림자와 위치가 함께 바뀌는 상태 변화입니다. 로딩 스피너는 사용자의 hover와 상관없이 계속 회전해야 하는 시간 기반 동작입니다. 알림 배지의 ping 효과는 사용자의 시선을 끌기 위한 반복 애니메이션입니다. 모두 움직임이지만 처리 기준은 다릅니다.

이 차이를 나누지 않고 모든 요소에 을 붙이면 처음에는 화면이 부드러워 보입니다. 하지만 버튼, 카드, 모달, 드롭다운, 알림까지 늘어나면 페이지 전체가 계속 흔들리는 느낌이 날 수 있습니다. 특히 transform 기반 움직임이 여러 곳에 들어가면 사용자가 내용을 읽기 전에 UI가 먼저 시선을 빼앗습니다.

그래서 Tailwind에서 motion을 다룰 때는 세 가지 질문을 먼저 둡니다. 첫째이 변화는 hover, focus, open 상태처럼 값이 바뀌는 순간인가. 그렇다면 계열이 중심입니다. 둘째이 효과는 로딩이나 알림처럼 시간 흐름 자체가 의미를 가지는가. 그렇다면 계열이 맞습니다. 셋째이 움직임은 사용자의 모션 감소 설정에서 줄여야 하는가. 여기서 와 를 같이 검토합니다.

구분 어울리는 상황 대표 클래스
transition hover, focus, open, disabled처럼 상태가 바뀌는 순간 ,
animation 로딩, 알림, pulse처럼 시간 흐름이 있는 동작 ,
사용자가 모션 감소 설정을 켰을 때 움직임을 줄이는 처리 ,

transition은 상태 변화에 붙이는 기준

은 요소의 값이 바뀔 때 그 변화를 끊어 보이지 않게 이어주는 역할을 합니다. 버튼 배경색이 바뀌거나, 카드 그림자가 강해지거나, 드롭다운이 투명도와 위치를 바꾸며 열리는 상황이 여기에 들어갑니다. 기준은 “움직임을 넣고 싶다”가 아니라 “상태 변화가 갑자기 끊겨 보이는가”입니다.

자주 생기는 문제는 을 기본값처럼 붙이는 습관입니다. 작은 버튼 하나에서는 큰 문제가 없어 보이지만, 컴포넌트가 커지면 의도하지 않은 속성까지 전환 대상이 될 수 있습니다. 색상만 바뀌는 버튼이라면 가 더 분명하고, 카드 위치만 살짝 움직일 계획이라면 이 더 읽기 쉽습니다.

버튼은 색상 변화부터 좁혀 보기

<button class="rounded-lg bg-slate-900 px-4 py-2 text-sm font-medium text-white transition-colors duration-200 hover:bg-slate-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-900 disabled:cursor-not-allowed disabled:opacity-50"> 저장하기
</button>

이 버튼에서 실제로 부드럽게 바뀌어야 하는 값은 배경색입니다. 그래서 전체보다 가 더 맞습니다. 은 사용자가 hover 상태를 바로 인식할 정도로 짧고, 버튼 클릭 흐름을 방해하지 않는 수준입니다. 저장 버튼처럼 반복해서 누르는 UI라면 화려한 움직임보다 반응이 빠르게 느껴지는 쪽이 더 중요합니다.

은 transition보다 우선순위가 높게 봐야 하는 상태입니다. 키보드 사용자가 현재 포커스 위치를 확인해야 하므로 outline을 과하게 흐리거나 늦게 나타나게 만들면 조작 흐름이 나빠집니다. hover는 부드럽게 처리하더라도 focus 표시 자체는 분명해야 합니다.

카드 hover는 transform이 정말 필요한지 먼저 보기

<a href="/products/coffee-mug" class="group block rounded-2xl border border-slate-200 bg-white p-5 shadow-sm transition duration-200 ease-out hover:-translate-y-1 hover:shadow-md focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-slate-900 motion-reduce:hover:translate-y-0"> <span class="block text-sm text-slate-500">Kitchen</span> <strong class="mt-2 block text-lg text-slate-950">Ceramic mug</strong> <span class="mt-3 block text-sm text-slate-600 transition-colors group-hover:text-slate-900">자세히 보기</span>
</a>

카드 hover에서 은 눈에 잘 띕니다. 다만 카드가 많은 그리드에서는 모든 카드가 위아래로 움직일 수 있으므로 화면이 쉽게 산만해집니다. 상품 목록처럼 카드가 반복되는 화면이라면 transform을 약하게 쓰거나, 그림자와 border 변화만으로 hover를 표현하는 방식도 후보가 됩니다.

여기서는 도 함께 넣었습니다. 사용자의 모션 감소 설정을 고려하면 hover 상태에서 카드가 위로 움직이는 효과를 제거할 수 있습니다. 색상이나 그림자 변화까지 모두 없앨 필요는 없지만, 위치 이동처럼 시야 흐름에 영향을 주는 motion은 줄이는 기준을 남겨두는 게 좋습니다.

animation은 시간 흐름이 있는 동작에 쓰는 기준

은 상태가 바뀌는 순간보다 시간 흐름 자체가 의미를 가질 때 사용합니다. 로딩 중인 아이콘이 계속 회전하거나, 알림 배지가 퍼지듯 강조되거나, skeleton UI가 pulse처럼 흐르는 경우입니다. 사용자의 hover가 없어도 움직임이 계속되거나, keyframes 흐름이 필요한 경우라고 보면 됩니다.

Tailwind의 기본 animation 유틸리티는 자주 쓰이는 패턴을 빠르게 적용하기 좋습니다. 은 로딩 아이콘은 알림 강조는 로딩 placeholder는 짧은 주의 환기에 자주 쓰입니다. 다만 기본 제공 클래스가 있다고 해서 모든 상태에 넣을 필요는 없습니다. 반복 애니메이션은 한 화면 안의 개수와 지속 시간을 같이 봐야 합니다.

로딩 스피너는 움직임을 켜는 조건도 같이 보기

<button class="inline-flex items-center gap-2 rounded-lg bg-slate-900 px-4 py-2 text-sm font-medium text-white disabled:cursor-wait disabled:opacity-70" disabled> <svg class="size-4 motion-safe:animate-spin" viewBox="0 0 24 24" aria-hidden="true"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path> </svg> 저장 중
</button>

로딩 스피너는 을 가장 자주 떠올리는 예시입니다. 하지만 여기서는 바로 을 쓰지 않고 을 붙였습니다. 사용자가 모션 감소를 요청하지 않은 환경에서만 회전 애니메이션을 켜겠다는 의미가 더 분명합니다.

로딩 상태를 꼭 회전으로만 표현할 필요는 없습니다. 버튼 텍스트를 “저장 중”으로 바꾸고, disabled 상태를 함께 처리하면 모션이 없어도 사용자는 상태를 이해할 수 있습니다. motion 대응은 애니메이션을 끄는 데서 끝나지 않고, 움직임이 사라져도 상태 정보가 남아 있는지까지 확인해야 합니다.

알림 배지는 강조가 필요한 곳에만 제한하기

<span class="relative inline-flex"> <span class="absolute inline-flex h-full w-full rounded-full bg-rose-400 opacity-75 motion-safe:animate-ping"></span> <span class="relative inline-flex size-3 rounded-full bg-rose-500"></span>
</span>

은 작은 영역에서도 시선을 강하게 끕니다. 그래서 알림 배지, 실시간 상태, 새 메시지처럼 사용자가 놓치면 안 되는 변화에 제한해서 쓰는 편이 낫습니다. 리스트의 모든 항목에 ping 효과를 넣으면 강조가 아니라 소음에 가까워집니다.

반복 애니메이션은 한 화면에서 개수를 세어보는 습관이 필요합니다. 스피너 하나는 괜찮지만, skeleton 카드 10개에 모두 pulse가 들어가고 알림 배지까지 ping이 돌면 페이지가 계속 흔들리는 느낌을 줍니다. 실제 UI에서는 “움직이는 요소가 동시에 몇 개인가”가 체감 품질에 영향을 줍니다.

motion-reduce는 접근성 설정을 반영하는 기준

는 단순히 애니메이션을 싫어하는 사용자를 위한 옵션이 아닙니다. 사용자가 운영체제나 브라우저 환경에서 모션 감소를 설정했다면, 웹 UI도 그 선호를 반영해야 합니다. 강한 이동, 회전, 확대, 시차 효과는 일부 사용자에게 피로감을 줄 수 있습니다.

Tailwind에서는 와 변형을 사용해 reduced motion 환경을 나눌 수 있습니다. 는 모션 감소 요청이 없는 환경에서만 움직임을 적용하고는 모션 감소 환경에서 대체 스타일을 적용할 때 사용합니다.

움직임을 없앨지, 줄일지, 대체할지 나누기

<div class="rounded-2xl border border-slate-200 bg-white p-6 opacity-0 transition duration-300 ease-out data-[open=true]:opacity-100 motion-safe:data-[open=true]:translate-y-0 motion-safe:data-[open=false]:translate-y-2 motion-reduce:transition-opacity" data-open="true"> <h3 class="text-lg font-semibold text-slate-950">필터 설정</h3> <p class="mt-2 text-sm text-slate-600">카테고리와 정렬 기준을 선택합니다.</p>
</div>

모달이나 패널이 열릴 때 아래에서 위로 올라오는 효과는 흔히 쓰입니다. 하지만 reduced motion 환경에서는 위치 이동을 줄이고 opacity 변화만 남기는 방식이 더 안정적입니다. 위 예시에서는 기본 전환은 유지하되, transform 기반 이동은 조건 안에 넣고, reduced motion 환경에서는 로 전환 대상을 좁혔습니다.

모든 움직임을 무조건 으로 끄는 방식만 있는 것은 아닙니다. 로딩 스피너처럼 회전 자체가 부담스러울 수 있는 요소는 애니메이션을 끄고 텍스트 상태를 남길 수 있습니다. 모달처럼 열림 상태를 알려야 하는 요소는 이동을 줄이고 opacity 중심으로 바꿀 수 있습니다. 알림처럼 강조가 필요한 요소는 ping 대신 색상, badge 숫자, 텍스트 라벨로 대체할 수 있습니다.

상황 기본 motion reduced motion 대응
버튼 hover 색상, 그림자 변화 대부분 유지 가능
카드 hover translate, shadow 변화 translate 제거, shadow 또는 border만 유지
로딩 스피너 계속 회전 회전 제거, 텍스트 상태 유지
모달 등장 opacity와 translate 조합 translate 제거, opacity 중심 전환
알림 ping 반복 확산 효과 색상, 숫자, 라벨로 대체

실제 UI에서 다시 확인할 체크포인트

Tailwind CSS motion-reduce와 motion-safe를 사용해 접근성 기준으로 움직임을 줄이는 체크포인트 정리 이미지

Tailwind motion 클래스를 붙이기 전에 먼저 바뀌는 속성을 확인해야 합니다. 색상만 바뀌는지, 투명도도 바뀌는지, transform까지 들어가는지에 따라, 중 선택이 달라집니다. 처음부터 넓은 transition을 붙이면 빠르지만, 나중에 수정할 때 어떤 변화가 의도된 것인지 흐려집니다.

두 번째로 duration을 확인합니다. 버튼이나 링크 hover는 짧아야 합니다. 사용자가 클릭하려는 순간에 전환이 길게 이어지면 반응이 둔하게 느껴집니다. 반대로 모달이나 패널처럼 화면 구조가 바뀌는 요소는 너무 짧으면 갑자기 튀어나오는 느낌이 날 수 있습니다. 그래서, 정도를 UI 성격에 따라 나누어 쓰는 기준을 두면 관리하기 쉽습니다.

세 번째로 easing을 확인합니다. 은 나타나는 움직임에 자주 어울리고은 사라지는 움직임에서 자연스럽게 느껴질 때가 많습니다. 은 들어오고 나가는 양쪽 움직임이 모두 있는 경우에 무난합니다. 다만 모든 버튼에 을 습관처럼 붙이면 코드만 길어지고 기준은 남지 않습니다.

네 번째로 움직이는 요소의 개수를 봅니다. 페이지 안에서 동시에 움직이는 요소가 많을수록 사용자는 어디를 봐야 할지 놓치기 쉽습니다. 관리자 화면의 저장 버튼, 테이블 row hover, toast 알림, skeleton loading이 한 번에 움직이면 각각은 작은 효과라도 전체 화면은 산만해질 수 있습니다.

마지막으로 reduced motion 상태에서 정보가 사라지지 않는지 확인합니다. 애니메이션을 끄면 로딩 중인지 모르게 되는 구조라면 텍스트, aria 속성, disabled 상태, 시각적 라벨을 함께 보강해야 합니다. motion을 줄이는 작업은 장식을 제거하는 일이 아니라, 움직임 없이도 같은 정보를 전달하도록 UI를 다시 정리하는 작업입니다.

정리

Tailwind CSS에서 과 은 같은 움직임처럼 보이지만 적용 기준이 다릅니다. 은 상태가 바뀌는 순간을 부드럽게 연결하는 데 쓰고은 시간 흐름 자체가 필요한 동작에 씁니다. 버튼 hover와 로딩 스피너를 같은 기준으로 보면 코드가 금방 섞입니다.

움직임을 넣을 때는 먼저 바뀌는 속성을 좁혀야 합니다. 색상만 바뀐다면, 투명도만 바뀐다면, 위치 변화가 필요하다면 을 고려합니다. 반복 동작이 필요할 때만같은 animation 유틸리티를 씁니다.

그리고 motion을 넣었다면 줄이는 기준도 같이 남겨야 합니다. 는 움직임을 허용할 수 있는 환경에서만 애니메이션을 켜는 방식이고는 사용자가 모션 감소를 요청했을 때 대체 스타일을 제공하는 방식입니다. 카드가 살짝 올라가는 효과 스피너 회전, 모달 등장 이동처럼 transform과 반복이 들어간 효과는 특히 이 기준을 먼저 확인해야 합니다.

다음에 Tailwind로 움직임을 넣을 때는 클래스 이름보다 질문을 먼저 두는 쪽이 오래 갑니다. 이 변화는 상태 변화인가, 반복 애니메이션인가, 사용자가 모션을 줄였을 때도 필요한 정보가 남는가. 이 세 가지를 통과하면를 훨씬 덜 흔들리게 고를 수 있습니다.

같이 읽으면 좋은 글

이 글이 마음에 드세요?

RSS 피드를 구독하세요!

“Tailwind CSS transition, animation, motion-reduce 사용 기준 정리”에 대한 1개의 생각

댓글 남기기