Files
2nd/10_Wiki/Topics/Frontend/마이크로 인터랙션(Micro-interactions).md
T
2026-05-10 22:08:15 +09:00

7.1 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-마이크로-인터랙션-micro-interactions 마이크로 인터랙션(Micro-interactions) 10_Wiki/Topics verified self
Micro-interactions
마이크로 인터랙션
UI 마이크로 애니메이션
none A 0.9 applied
frontend
ux
animation
interaction-design
2026-05-10 pending
language framework
typescript react

마이크로 인터랙션(Micro-interactions)

매 한 줄

"매 작은 반응이 매 신뢰를 만든다". 매 single-purpose UI feedback (clicked button squish, toggle slide, validation tick) 의 사용자 의도 confirm + 시스템 상태 communicate. Dan Saffer (2013)이 명명, 매 modern design system (Material 3, Apple HIG 2026)의 backbone.

매 핵심

매 4단계 구조 (Saffer)

  • Trigger: user action (click, hover, scroll) or system event.
  • Rules: what happens (state machine).
  • Feedback: visual/audio/haptic response.
  • Loops & Modes: long-term behavior (meta-rules).

매 4가지 기능

  • Status communication — loading spinner, progress bar.
  • Feedback — button press depression, form 검증 shake.
  • Demonstrate result — like 의 heart fill animation.
  • Visualize state changes — toggle on/off, theme switch.

매 응용

  1. Form validation — inline feedback (real-time check).
  2. Loading states — skeleton, spinner, progress.
  3. Notifications — toast slide-in/out.
  4. Gestures — swipe to delete (iOS Mail).
  5. Empty states — illustration + CTA.

💻 패턴

1. Button press feedback (Framer Motion)

import { motion } from 'framer-motion';

export function PressableButton({ children, onClick }: { children: React.ReactNode; onClick: () => void }) {
  return (
    <motion.button
      whileTap={{ scale: 0.95 }}
      whileHover={{ scale: 1.02 }}
      transition={{ type: 'spring', stiffness: 400, damping: 17 }}
      onClick={onClick}
      className="px-4 py-2 bg-blue-600 text-white rounded-lg"
    >
      {children}
    </motion.button>
  );
}

2. Toggle switch (state visualization)

import { motion } from 'framer-motion';
import { useState } from 'react';

export function Toggle() {
  const [on, setOn] = useState(false);
  return (
    <button
      onClick={() => setOn(!on)}
      className={`w-14 h-8 rounded-full p-1 ${on ? 'bg-green-500' : 'bg-gray-300'}`}
      aria-pressed={on}
    >
      <motion.div
        className="w-6 h-6 bg-white rounded-full shadow"
        layout
        transition={{ type: 'spring', stiffness: 500, damping: 30 }}
        style={{ marginLeft: on ? 'auto' : 0 }}
      />
    </button>
  );
}

3. Like heart burst (demonstrate result)

import { motion, AnimatePresence } from 'framer-motion';

export function LikeButton({ liked, onToggle }: { liked: boolean; onToggle: () => void }) {
  return (
    <button onClick={onToggle} aria-label={liked ? 'Unlike' : 'Like'}>
      <AnimatePresence mode="wait">
        <motion.svg
          key={String(liked)}
          initial={{ scale: 0.5, opacity: 0 }}
          animate={{ scale: liked ? [1, 1.4, 1] : 1, opacity: 1 }}
          transition={{ duration: 0.3 }}
          fill={liked ? '#ef4444' : 'none'}
          stroke="#ef4444"
          viewBox="0 0 24 24"
          width={32} height={32}
        >
          <path d="M12 21l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.18L12 21z" strokeWidth="2"/>
        </motion.svg>
      </AnimatePresence>
    </button>
  );
}

4. Toast notification (status)

import { motion, AnimatePresence } from 'framer-motion';

export function Toast({ message, show }: { message: string; show: boolean }) {
  return (
    <AnimatePresence>
      {show && (
        <motion.div
          initial={{ y: 100, opacity: 0 }}
          animate={{ y: 0, opacity: 1 }}
          exit={{ y: 100, opacity: 0 }}
          transition={{ type: 'spring', stiffness: 300, damping: 30 }}
          className="fixed bottom-4 right-4 bg-gray-900 text-white px-4 py-2 rounded shadow-lg"
          role="status"
        >
          {message}
        </motion.div>
      )}
    </AnimatePresence>
  );
}

5. Form validation inline shake

import { motion } from 'framer-motion';

export function ShakeInput({ error, ...props }: { error: boolean } & React.InputHTMLAttributes<HTMLInputElement>) {
  return (
    <motion.input
      animate={error ? { x: [0, -8, 8, -8, 8, 0] } : { x: 0 }}
      transition={{ duration: 0.4 }}
      className={`border rounded px-3 py-2 ${error ? 'border-red-500' : 'border-gray-300'}`}
      aria-invalid={error}
      {...props}
    />
  );
}

6. Loading skeleton (status)

export function Skeleton({ className }: { className?: string }) {
  return (
    <div
      className={`animate-pulse bg-gray-200 rounded ${className}`}
      aria-busy="true"
      aria-live="polite"
    />
  );
}
// usage: <Skeleton className="h-4 w-32" />

7. Reduced-motion respect

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

매 결정 기준

상황 Approach
단순 hover/press CSS transition 충분.
State change (toggle, modal) Framer Motion layout + spring.
Complex sequence (onboarding) Lottie (After Effects export) 또는 Rive.
Performance-critical (60fps mobile) Web Animations API + GPU-only props (transform, opacity).
Accessibility prefers-reduced-motion 매 항상 respect.

기본값: Framer Motion + spring 매 React 매 default. Tailwind animate utilities 매 simple cases.

🔗 Graph

🤖 LLM 활용

언제: state change confirmation, status communication, delight moments, error recovery. 언제 X: 매 사용자 critical path 막는 long animation, accessibility 무시 의 flashy effects, 매 30fps 떨어지는 micro interaction.

안티패턴

  • Animation overload: 매 page 의 every element 의 animate — visual noise.
  • Slow durations: >400ms 의 micro interaction — feels sluggish (sweet spot 100-300ms).
  • Ignoring reduced-motion: 매 vestibular disorder 사용자 unusable.
  • Layout-triggering animation: width/height animate — paint thrash. Use transform: scale.
  • Decorative-only: feedback 없이 매 just for show — 매 noise.

🧪 검증 / 중복

  • Verified (Saffer "Microinteractions" 2013, Material 3 motion guidelines, Apple HIG 2026).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — full content with 4-stage structure + 7 Framer Motion patterns