[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -1,115 +1,260 @@
|
||||
---
|
||||
id: wiki-2026-0508-micro-interactions
|
||||
title: Micro interactions
|
||||
title: Micro-interactions
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: []
|
||||
aliases: [Microinteractions, UI Micro-animations, Tiny UX]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.92
|
||||
tags: [auto-consolidated, technical-documentation]
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [ux, ui, animation, design, frontend]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-08
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: typescript
|
||||
framework: react-framer-motion
|
||||
---
|
||||
|
||||
# [[Micro-interactions|Micro-interactions]] (마이크로 인터랙션)
|
||||
# Micro-interactions
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "신은 디테일에 있으며, 유저는 아주 작은 반응에 감동한다." 알람 소리 하나, 버튼의 햅틱 피드백, 전송 중인 프로그레스 바의 애니메이션처럼 단일 작업을 수행하는 아주 작고 정교한 상호작용이다.
|
||||
## 매 한 줄
|
||||
> **"매 작은 순간이 매 product 의 personality 를 결정한다."**. Micro-interaction 은 매 single task 를 중심으로 한 매 작은 UX moment — toggle, like, error feedback, hover state. Dan Saffer 의 매 4-part model (Trigger / Rules / Feedback / Loops & Modes) 이 표준. 매 well-crafted 매 micro-interaction 은 매 product 를 매 functional → 매 delightful 로 매 끌어올림.
|
||||
|
||||
---
|
||||
## 매 핵심
|
||||
|
||||
마이크로 인터랙션은 버튼 클릭, 토글, 스와이프 제스처 등 특정 사용자 동작에 반응하여 트리거되는 작고 섬세한 애니메이션을 의미합니다 [1, 2]. 이는 단일 작업에 초점을 맞춘 제한된 형태의 애니메이션으로, 사용자에게 즉각적인 시각적 피드백을 제공하고 시스템 상태를 명확히 전달합니다 [1, 3]. 단순한 장식적 요소를 넘어 인지적 부하를 줄이고 인터페이스의 반응성과 사용자의 참여도를 높이는 목적 지향적인 역할을 수행합니다 [3-5].
|
||||
### 매 Saffer's 4 parts
|
||||
1. **Trigger**: user 가 시작 (click) 또는 system (notification).
|
||||
2. **Rules**: 매 무엇이 일어나는지 (state transition).
|
||||
3. **Feedback**: 매 user 에게 결과 알림 (visual / sound / haptic).
|
||||
4. **Loops & Modes**: 매 시간에 따른 변화, 매 special state.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **Four Elements of Micro-interactions**:
|
||||
1. **Trigger**: 상호작용을 시작하는 계기 (사용자의 클릭, 시스템 알람).
|
||||
2. **Rules**: 어떤 일이 일어날지 결정하는 논리.
|
||||
3. **Feedback**: 유저에게 일어난 변화를 시각/청각/촉각으로 알림.
|
||||
4. **Loops & Modes**: 상호작용이 얼마나 지속되고 어떤 예외 상황이 있는지 정의.
|
||||
- **Value**:
|
||||
- 시스템의 현재 상태를 즉시 알림 (신뢰성).
|
||||
- 사용자가 작업을 완료했을 때 성취감을 줌 (재미와 보상).
|
||||
- 자칫 딱딱해질 수 있는 디지털 환경에 '생명력'을 부여함.
|
||||
### 매 언제 사용
|
||||
- **Status communication**: loading, saving, online/offline.
|
||||
- **Affordance hint**: hover, focus, disabled.
|
||||
- **Error prevention**: input validation 즉시 feedback.
|
||||
- **Reward**: like animation, achievement unlock.
|
||||
- **Branding**: 매 unique transition 으로 매 personality.
|
||||
|
||||
---
|
||||
### 매 design 원칙
|
||||
- **빠르게**: 매 100-300ms — 매 너무 길면 매 friction.
|
||||
- **Purposeful**: 매 deco 아닌 매 information 전달.
|
||||
- **Consistent**: 매 동일 action → 매 동일 feedback.
|
||||
- **Respectful**: `prefers-reduced-motion` 존중.
|
||||
- **Subtle by default**: 매 hero animation 은 매 rare.
|
||||
|
||||
* **명확한 피드백 및 사용자 신뢰 구축**
|
||||
마이크로 인터랙션은 사용자가 행동을 취했을 때 시스템이 이를 성공적으로 인식했음을 즉각적으로 알려주는 피드백 도구입니다 [2]. 예를 들어, 장바구니에 상품을 추가할 때 카트 아이콘이 짧게 강조되는 애니메이션은 현재의 브라우징 흐름을 방해하지 않으면서도 행동이 완료되었음을 확인시켜 줍니다 [6, 7]. 이를 통해 오류 발생을 줄이고 시스템에 대한 사용자의 신뢰와 확신을 높일 수 있습니다 [2, 8].
|
||||
### 매 performance
|
||||
- 매 transform/opacity 만 사용 (compositor only — GPU).
|
||||
- 매 layout/paint trigger 회피 (width, height, top, left).
|
||||
- 매 will-change 의 sparing 사용.
|
||||
|
||||
* **정서적 교감 및 통제감 제공**
|
||||
정교하게 설계된 미세한 움직임은 정적인 화면에 생동감과 개성을 불어넣어 사용자와 브랜드 간의 정서적 교감을 강화합니다 [9]. '좋아요' 버튼을 탭할 때 맥박이 뛰듯 움직이거나 슬라이더가 부드럽게 미끄러져 제자리를 찾는 등의 효과는 사용자에게 시각적 즐거움(delight)을 주며, 자신이 시스템을 완벽하게 통제하고 있다는 느낌을 부여합니다 [3].
|
||||
## 💻 패턴
|
||||
|
||||
* **2025년 UI/UX 모션 디자인 트렌드**
|
||||
최근의 마이크로 인터랙션은 단순히 인터페이스를 꾸미는 용도가 아니라 '목적성 있는 마이크로 인터랙션([[Purpose|Purpose]]ful Micro-Interactions)'으로 진화하고 있습니다 [4]. 사용자의 행동, 기기 유형, 또는 사용 이력 등의 컨텍스트를 인식하여 지능적으로 반응하도록 설계되며, 모든 사용자 행동이 의미 있게 받아들여지도록 돕습니다 [4]. Slack과 같은 실제 서비스에서도 메시지 전송이나 파일 업로드 시 이러한 미세 애니메이션을 적극 활용하여 앱의 반응성을 극대화하고 있습니다 [10].
|
||||
### CSS toggle (transform only)
|
||||
```css
|
||||
.toggle {
|
||||
width: 44px; height: 24px;
|
||||
background: #ccc;
|
||||
border-radius: 12px;
|
||||
transition: background 200ms ease;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
.toggle::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2px; left: 2px;
|
||||
width: 20px; height: 20px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
.toggle.on { background: #4ade80; }
|
||||
.toggle.on::after { transform: translateX(20px); }
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- 마이크로 인터랙션이 너무 화려하거나 길면 핵심 작업의 속도를 늦추어 오히려 방해 요소가 된다. 공기처럼 자연스럽게 존재해야 하며, 유저가 "와, 화려하다"라고 느끼는 순간 이미 '마이크로'의 범위를 벗어난 것일 수 있다. 최소한의 픽셀 변화로 최대의 인지 효과를 내는 것이 목표다.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- Related: [[Game-Feel-and-Juiciness|Game-Feel-and-Juiciness]] , [[Feedback-Loops-in-Design|Feedback-Loops-in-Design]]
|
||||
- Principle: [[Affordance|Affordance]] (행동 유도성)
|
||||
|
||||
---
|
||||
|
||||
- **Related Topics:** 애니메이션 (transition / keyframes), 반응형 피드백 (Responsive Feedback)
|
||||
- **Projects/Contexts:** UI/UX 모션 디자인 (UI/UX Motion Design)
|
||||
- **Contradictions/Notes:** 소스에 따르면 마이크로 인터랙션과 일반 UI 애니메이션은 구분되어야 합니다. 마이크로 인터랙션은 '피드백 제공'에 목적을 둔 작업 중심의 아주 작은 애니메이션(예: 버튼 펄스 효과)인 반면, UI 애니메이션은 내비게이션 가이드, 화면 전환, 전반적인 시스템 상태 표시 등에 사용되는 더 넓은 범위의 움직임을 의미합니다 [5].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.toggle, .toggle::after { transition: none; }
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Framer Motion (React)
|
||||
```tsx
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
function LikeButton({ liked, onToggle }: { liked: boolean; onToggle: () => void }) {
|
||||
return (
|
||||
<motion.button
|
||||
whileTap={{ scale: 0.9 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
onClick={onToggle}
|
||||
aria-pressed={liked}
|
||||
>
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.span
|
||||
key={liked ? 'on' : 'off'}
|
||||
initial={{ scale: 0.5, opacity: 0 }}
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
exit={{ scale: 0.5, opacity: 0 }}
|
||||
transition={{ duration: 0.15 }}
|
||||
>
|
||||
{liked ? '❤️' : '🤍'}
|
||||
</motion.span>
|
||||
</AnimatePresence>
|
||||
</motion.button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Skeleton loading
|
||||
```tsx
|
||||
const Skeleton = () => (
|
||||
<motion.div
|
||||
className="h-4 bg-gray-200 rounded"
|
||||
animate={{ opacity: [0.5, 1, 0.5] }}
|
||||
transition={{ duration: 1.5, repeat: Infinity, ease: 'easeInOut' }}
|
||||
/>
|
||||
);
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Optimistic UI (form submit)
|
||||
```tsx
|
||||
function CommentForm({ onSubmit }: { onSubmit: (text: string) => Promise<void> }) {
|
||||
const [pending, setPending] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
return (
|
||||
<form onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
const text = (e.target as any).text.value;
|
||||
setPending(true);
|
||||
setError(null);
|
||||
try {
|
||||
await onSubmit(text);
|
||||
} catch (err) {
|
||||
setError('Failed. Try again.');
|
||||
} finally {
|
||||
setPending(false);
|
||||
}
|
||||
}}>
|
||||
<input name="text" disabled={pending} />
|
||||
<motion.button
|
||||
whileTap={{ scale: 0.95 }}
|
||||
animate={pending ? { opacity: 0.6 } : { opacity: 1 }}
|
||||
disabled={pending}
|
||||
>
|
||||
{pending ? 'Posting…' : 'Post'}
|
||||
</motion.button>
|
||||
<AnimatePresence>
|
||||
{error && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -4 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0 }}
|
||||
role="alert"
|
||||
>{error}</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
### Inline validation
|
||||
```tsx
|
||||
function EmailInput() {
|
||||
const [value, setValue] = useState('');
|
||||
const [touched, setTouched] = useState(false);
|
||||
const valid = /\S+@\S+\.\S+/.test(value);
|
||||
const showError = touched && !valid && value.length > 0;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input
|
||||
type="email"
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
onBlur={() => setTouched(true)}
|
||||
aria-invalid={showError}
|
||||
/>
|
||||
<AnimatePresence>
|
||||
{showError && (
|
||||
<motion.span
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: 'auto' }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
className="text-red-600 text-sm"
|
||||
role="alert"
|
||||
>Invalid email</motion.span>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Pull-to-refresh (mobile)
|
||||
```tsx
|
||||
import { motion, useMotionValue, useTransform } from 'framer-motion';
|
||||
|
||||
function PullToRefresh({ onRefresh }: { onRefresh: () => Promise<void> }) {
|
||||
const y = useMotionValue(0);
|
||||
const opacity = useTransform(y, [0, 80], [0, 1]);
|
||||
const rotate = useTransform(y, [0, 80], [0, 360]);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
drag="y"
|
||||
dragConstraints={{ top: 0, bottom: 100 }}
|
||||
dragElastic={0.3}
|
||||
onDragEnd={async (_, info) => {
|
||||
if (info.offset.y > 80) await onRefresh();
|
||||
y.set(0);
|
||||
}}
|
||||
style={{ y }}
|
||||
>
|
||||
<motion.div style={{ opacity, rotate }}>↻</motion.div>
|
||||
{/* content */}
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| Element | Duration | Easing |
|
||||
|---|---|---|
|
||||
| Toggle, hover | 100-200ms | ease-out |
|
||||
| Modal enter | 200-300ms | cubic-bezier(0.4, 0, 0.2, 1) |
|
||||
| Modal exit | 150-200ms | cubic-bezier(0.4, 0, 1, 1) |
|
||||
| Page transition | 300-500ms | ease-in-out |
|
||||
| Loading shimmer | 1500ms loop | ease-in-out |
|
||||
|
||||
**기본값**: 매 200ms + ease-out + transform/opacity. 매 prefers-reduced-motion 매 항상 존중.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[UX Design]] · [[Interaction Design]]
|
||||
- 변형: [[Animation]] · [[Transitions]] · [[Skeleton Loading]]
|
||||
- 응용: [[Form UX]] · [[Optimistic UI]] · [[Loading States]]
|
||||
- Adjacent: [[Framer Motion]] · [[CSS Transitions]] · [[Web Animations API]] · [[Accessibility]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: UI feedback 설계, button/toggle/input 의 polish, error/loading/empty state 의 personality.
|
||||
**언제 X**: 매 dense data table, 매 power-user tool — 매 animation 이 매 friction.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **너무 긴 duration**: 매 500ms+ → 매 sluggish.
|
||||
- **No reduced-motion**: 매 vestibular disorder user 에게 매 hostile.
|
||||
- **Decorative only**: 매 information 없는 매 animation → 매 cognitive load.
|
||||
- **Inconsistent**: 매 같은 action 이 매 다른 feedback.
|
||||
- **Layout-trigger animation**: 매 width/height/top → 매 jank.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Saffer "Microinteractions", Material Design motion guidelines, Apple HIG, Framer Motion docs, web.dev animations).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — Saffer 4-part + Framer Motion / a11y 패턴 |
|
||||
|
||||
Reference in New Issue
Block a user