Claude Code로 안전한 UI 애니메이션을 구현하는 실무 가이드
Claude Code로 가볍고 접근성 좋은 UI 애니메이션을 구현하는 코드, 사례, 함정, 검증 절차.
먼저 목적을 정한다
Claude Code로 UI 애니메이션을 넣을 때 가장 먼저 정할 것은 “어떻게 움직일까”가 아니라 “어떤 불확실성을 줄일까”입니다. 안전한 애니메이션은 장식이 아니라 피드백입니다. 저장이 끝났는지, 오류가 있는지, 다음에 봐야 할 카드가 어디인지, 제품이나 교육 상담 CTA가 주요 경로인지 알려주는 보조 신호여야 합니다.
초보자가 Claude Code에 “페이지를 더 멋지게 움직여줘”라고 요청하면 빠르게 데모는 나옵니다. 하지만 실제 운영 페이지에는 모바일 폭, 키보드 포커스, 긴 제목, 광고 영역, 코드 블록, 빈 데이터, prefers-reduced-motion 같은 조건이 있습니다. 이 글은 CSS와 작은 JavaScript로 스크롤 reveal, 버튼 피드백, 상태 전환을 안전하게 추가하는 방법을 다룹니다.
관련 기초는 Claude Code design system, Claude Code responsive design, Claude Code performance optimization도 함께 보세요. 공식 문서는 Claude Code docs, MDN CSS animation, MDN Intersection Observer API, MDN prefers-reduced-motion, web.dev CSS animations를 기준으로 삼습니다. Intersection Observer는 요소가 화면에 들어왔는지 브라우저가 알려주는 API이고, prefers-reduced-motion은 사용자가 시스템에서 움직임 감소를 선택했을 때 CSS로 대응하는 기능입니다.
Claude Code에 줄 프롬프트
작업 범위를 좁히면 리뷰가 쉬워집니다. 전체 화면을 다시 디자인하게 하지 말고, 검증 가능한 한 영역부터 시작합니다.
이 화면에 가벼운 UI 애니메이션을 추가해 주세요.
대상은 CTA 앞 카드, 로딩 완료 후 나타나는 섹션, 저장 버튼 반응만입니다.
기존 컴포넌트, 라우팅, 문구, 디자인 토큰은 변경하지 마세요.
CSS와 작은 JavaScript를 우선하고, 이유 없이 애니메이션 라이브러리를 추가하지 마세요.
Use case, Pitfall, 접근성, prefers-reduced-motion, 375px 모바일 확인 결과를 함께 보고해 주세요.
이 프롬프트는 대상, 금지 사항, 확인 기준을 같이 전달합니다. Claude Code는 넓은 요청을 받으면 주변 레이아웃까지 수정할 수 있습니다. 게시된 사이트에서는 변경 파일이 적을수록 안전합니다. 특히 제품 카드, 가격표, 상담 폼, 글 하단 CTA는 수익 경로이기 때문에 움직임보다 읽기와 클릭을 우선해야 합니다.
Use case(실무 적용 장면)
| Use case | 목표 | 움직일 위치 | 성공 기준 |
|---|---|---|---|
| 글 하단 전환 | 독자가 다음 자료를 찾게 한다 | 관련 글, 제품 카드, CTA | 코드 복사를 방해하지 않음 |
| SaaS 대시보드 | 저장, 동기화, 오류 상태를 명확히 한다 | 버튼, toast, 빈 상태 | 색만으로 의미를 전달하지 않음 |
| 제품 페이지 | 가격과 혜택을 순서 있게 보여준다 | 비교표, 혜택 카드 | 구매 버튼이 계속 보임 |
| 팀 리뷰 | Claude Code diff를 검토하기 쉽게 한다 | 범위와 체크리스트 | 목적과 위험이 설명됨 |
첫 번째 Use case는 튜토리얼 글입니다. 독자가 코드를 읽은 뒤 ClaudeCodeLab 제품이나 Claude Code 교육 및 상담으로 자연스럽게 이동할 수 있으면 좋습니다. 다만 CTA가 계속 흔들리면 코드 복사와 비교를 방해합니다. 한 번만 조용히 나타나는 정도가 충분합니다.
두 번째 Use case는 관리 화면입니다. 저장 버튼을 누른 뒤 버튼이 짧게 반응하고 문구가 “저장됨”으로 바뀌면 사용자는 클릭이 처리됐다고 느낍니다. 여기서 애니메이션은 유일한 정보가 아니어야 합니다. 텍스트, aria-busy, 포커스 표시, 오류 메시지가 남아 있어야 합니다.
세 번째 Use case는 제품과 가격 페이지입니다. 비교표와 혜택 카드는 정보가 많아 순차 reveal이 시선 이동에 도움이 됩니다. 하지만 각 카드가 너무 늦게 나타나면 구매 판단을 늦춥니다. 장식적 움직임은 보통 200~500ms 안에 끝내고, 사용자의 조작 결과는 즉시 보여줍니다.
네 번째 Use case는 팀 개발입니다. Claude Code에 “어떤 Use case를 위한 애니메이션인지, 어떤 Pitfall을 피했는지”까지 설명하게 하면 디자인 취향 논쟁보다 리뷰 기준이 명확해집니다.
구현 구조
안전한 구현은 HTML, CSS, JS 세 층으로 나누면 이해하기 쉽습니다.
| 층 | 역할 | 확인할 점 |
|---|---|---|
| HTML | 움직일 요소를 표시 | 제목, 본문, CTA 의미가 유지되는가 |
| CSS | 투명도, 이동 거리, 시간, easing 정의 | opacity와 transform 중심인가 |
| JavaScript | 표시 시점과 정리 담당 | reduce motion, 미지원 브라우저, observer 해제 처리 |
이 구조에서는 HTML에 data-reveal과 reveal class만 추가합니다. CSS는 공통 motion 스타일을 관리하고, JS는 is-visible을 붙이는 일만 합니다. 이렇게 하면 Astro, React, Next.js로 옮길 때도 책임 경계가 흐려지지 않습니다.
복사해서 쓰는 HTML
<section class="motion-demo" aria-labelledby="motion-demo-title">
<p class="eyebrow">ClaudeCodeLab workflow</p>
<h2 id="motion-demo-title">안전한 UI 애니메이션 rollout</h2>
<p>
목적, 대상, 검증 방법을 먼저 정한 뒤 Claude Code에 작은 diff를 맡깁니다.
</p>
<div class="motion-grid">
<article class="reveal" data-reveal>
<h3>설계</h3>
<p>Use case와 성공 조건을 하나로 좁힙니다.</p>
</article>
<article class="reveal" data-reveal>
<h3>구현</h3>
<p>CSS 변수와 작은 JS로 기존 UI를 건드리지 않고 추가합니다.</p>
</article>
<article class="reveal" data-reveal>
<h3>검증</h3>
<p>Pitfall, reduce motion, 모바일, 키보드 조작을 확인합니다.</p>
</article>
</div>
<a class="motion-cta reveal" data-reveal href="/ko/training/">
Claude Code 교육 상담하기
</a>
</section>
복사해서 쓰는 CSS
CSS는 opacity와 transform 중심으로 둡니다. width, height, top, left 애니메이션은 레이아웃 계산을 늘릴 수 있습니다. will-change도 필요한 요소에만 제한합니다.
:root {
--motion-duration: 420ms;
--motion-distance: 16px;
--motion-ease: cubic-bezier(0.16, 1, 0.3, 1);
--motion-border: #d8e2ee;
--motion-bg: #ffffff;
--motion-text: #182230;
--motion-accent: #2563eb;
}
.motion-demo {
color: var(--motion-text);
max-width: 920px;
margin: 48px auto;
padding: 24px;
}
.eyebrow {
margin: 0 0 8px;
color: var(--motion-accent);
font-weight: 700;
}
.motion-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
margin: 24px 0;
}
.motion-grid article {
border: 1px solid var(--motion-border);
border-radius: 8px;
background: var(--motion-bg);
padding: 16px;
}
.reveal {
opacity: 0;
transform: translateY(var(--motion-distance));
transition:
opacity var(--motion-duration) var(--motion-ease),
transform var(--motion-duration) var(--motion-ease);
will-change: opacity, transform;
}
.reveal.is-visible {
opacity: 1;
transform: translate3d(0, 0, 0);
}
.motion-cta {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 44px;
padding: 0 18px;
border-radius: 8px;
background: var(--motion-accent);
color: #ffffff;
font-weight: 700;
text-decoration: none;
}
.motion-cta:focus-visible {
outline: 3px solid #f59e0b;
outline-offset: 3px;
}
@media (max-width: 640px) {
.motion-demo {
margin: 32px auto;
padding: 16px;
}
.motion-grid {
grid-template-columns: 1fr;
}
}
@media (prefers-reduced-motion: reduce) {
.reveal {
opacity: 1;
transform: none;
transition: none;
will-change: auto;
}
}
복사해서 쓰는 JavaScript
Intersection Observer로 요소가 화면에 들어올 때 한 번만 표시합니다. reduce motion 사용자나 미지원 브라우저에서는 바로 보이게 합니다.
export function setupScrollReveal(root = document) {
const targets = Array.from(root.querySelectorAll("[data-reveal]"));
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (targets.length === 0) {
return () => {};
}
if (reduceMotion || !("IntersectionObserver" in window)) {
targets.forEach((target) => target.classList.add("is-visible"));
return () => {};
}
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue;
entry.target.classList.add("is-visible");
observer.unobserve(entry.target);
}
},
{
root: null,
rootMargin: "0px 0px -10% 0px",
threshold: 0.1,
},
);
targets.forEach((target) => observer.observe(target));
return () => observer.disconnect();
}
document.addEventListener("DOMContentLoaded", () => {
setupScrollReveal();
});
SPA나 island 컴포넌트처럼 나중에 DOM이 생기면 mount 이후 다시 호출합니다. modal이나 tab 안에서만 새 카드가 생긴다면 해당 container를 root로 넘겨 전체 문서를 다시 훑지 않게 합니다.
버튼 피드백 예시
버튼 반응은 더 짧아야 합니다. 다음 코드는 Web Animations API를 쓰지만, reduce motion이면 움직임 없이 텍스트와 ARIA 상태만 바꿉니다.
const button = document.querySelector("[data-save-button]");
const status = document.querySelector("[data-save-status]");
button?.addEventListener("click", async () => {
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
button.setAttribute("aria-busy", "true");
status.textContent = "저장 중...";
if (!reduceMotion) {
await button.animate(
[
{ transform: "scale(1)" },
{ transform: "scale(0.97)" },
{ transform: "scale(1)" },
],
{ duration: 180, easing: "ease-out" },
).finished;
}
await new Promise((resolve) => window.setTimeout(resolve, 300));
button.setAttribute("aria-busy", "false");
status.textContent = "저장됨";
});
핵심은 움직임이 없어도 의미가 남는 것입니다. 텍스트가 바뀌고, 포커스가 보이고, 보조 기술이 DOM 상태를 읽을 수 있어야 합니다.
Pitfall(구체적인 함정)
첫 번째 Pitfall은 목적이 흐린 애니메이션입니다. “세련되게”는 검증할 수 없지만 “가격 카드가 viewport에 들어올 때 한 번 나타나며 구매 버튼을 가리지 않는다”는 검증할 수 있습니다.
두 번째 Pitfall은 시간이 너무 긴 애니메이션입니다. 글 독자는 코드를 빨리 보고 싶고, 제품 페이지 독자는 가격을 빨리 비교하고 싶습니다. 장식적인 reveal은 짧게 끝내야 합니다.
세 번째 Pitfall은 모바일 가로 overflow입니다. translateX(40px)가 그림자, 표, 코드 블록과 만나면 375px 폭에서 가로 스크롤이 생길 수 있습니다. 가능하면 translateY()를 쓰고 375px, 414px, tablet 폭을 확인합니다.
네 번째 Pitfall은 색과 흔들림만으로 오류를 알리는 것입니다. 오류 문구, aria-describedby, 포커스 이동, 명확한 label을 함께 둡니다.
다섯 번째 Pitfall은 라이브러리를 먼저 추가하는 것입니다. 복잡한 timeline에는 전문 도구가 맞지만, 카드 reveal과 버튼 feedback은 CSS와 작은 JS로 충분한 경우가 많습니다.
여섯 번째 Pitfall은 Claude Code의 결과를 바로 합치는 것입니다. 변경 파일, CSS 변수, 접근성 처리, 수동 확인 항목, 선택하지 않은 대안을 설명하게 한 뒤 리뷰합니다.
리뷰와 검증
구현 후에는 리뷰 전용 프롬프트를 다시 보냅니다.
현재 diff만 리뷰하고 새 기능은 구현하지 마세요.
1. 접근성 위험
2. prefers-reduced-motion 누락
3. 375px 모바일 레이아웃 위험
4. 성능 문제
5. 기존 CSS나 컴포넌트와 충돌
6. 릴리스 전 사람이 직접 확인할 조작
순서로 엄격하게 지적해 주세요.
사람은 일반 모션, reduce motion, 키보드 탐색, 모바일 폭, 느린 네트워크, 빈 데이터를 확인합니다. 브라우저 개발자 도구에서 prefers-reduced-motion을 에뮬레이션하고, 움직임이 없어도 같은 정보가 전달되는지 봅니다. 제품 템플릿과 교육 상담 CTA가 보이고 누르기 쉬운지, 코드 블록이 페이지 전체를 넓히지 않는지도 확인합니다.
전환 경로와 연결하기
UI 애니메이션은 그 자체로 수익을 만들지 않습니다. 독자가 다음 행동으로 안전하게 이동하도록 돕는 장치입니다. 혼자 쓰는 개발자는 ClaudeCodeLab 제품에서 템플릿과 체크리스트를 볼 수 있고, 팀은 권한, CI, 리뷰 정책, CLAUDE.md 정비를 위해 Claude Code 교육 및 상담을 검토할 수 있습니다.
Masa가 글 페이지와 비슷한 레이아웃에서 시험했을 때, 큰 hero 애니메이션보다 글 하단 관련 카드와 CTA를 조용히 드러내는 쪽이 리뷰도 쉽고 독자 흐름도 덜 끊겼습니다. 한 번에 전체를 맡기는 것보다 구현, 리뷰, 수정의 세 단계로 나누는 편이 안정적이었습니다.
실제로 시험한 결과
이 절차는 실제 글 페이지에 가까운 구조에서 확인했습니다. 첫 번째 요청은 data-reveal 카드, reduce motion 처리, 저장 버튼 반응만 포함했습니다. 두 번째 요청은 리뷰 전용으로 375px 폭, 키보드 포커스, 빈 데이터, CTA 가시성을 확인했습니다.
결과적으로 작은 diff가 Pitfall을 더 빨리 드러냈습니다. 움직임을 opacity와 transform: translateY()로 제한하자 모바일 깨짐이 줄었습니다. 애니메이션의 양보다 중요한 것은 각 움직임의 Use case가 분명하고, 텍스트 상태와 접근성 처리가 남아 있으며, 배포 전 확인 목록이 존재하는 것입니다.
무료 PDF: Claude Code 치트시트
이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.
개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.
작성자 소개
Masa
Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.
관련 글
Claude Code 권한 세이프티 래더: 통제력을 잃지 않고 allow 넓히기
read-only에서 제한 편집, 검증 명령, deploy 확인까지 권한을 단계적으로 넓히는 방법.
Claude Code Small PR Proof Pack: 작은 PR을 리뷰 가능한 상태로 만드는 증거 세트
Claude Code의 작은 PR에 diff, 검증, 공개 URL, CTA 경로, rollback을 붙이는 실무 체크리스트.
Claude Code 커밋 전 리뷰 게이트: diff, 테스트, 공개 URL, CTA 확인
Claude Code 작업을 커밋하기 전에 diff 범위, build, 공개 URL, Gumroad 링크, 상담 CTA, 테스트 누락과 무관한 파일을 확인하는 방법입니다.