버튼에 손을 올리면 색이 스르르 짙어지고, 스위치를 누르면 손잡이가 미끄러지듯 넘어가는 그 작은 순간이 마이크로인터랙션입니다. 한 번의 조작에 화면이 어떻게 응답하는지, 그 짧은 대화를 CSS로 어떻게 짜는지 코드로 보여드리겠습니다.
75.1 가장 작은 단위: 상태가 바뀌면 반응한다
마이크로인터랙션의 뼈대는 단순합니다. 어떤 사건(트리거)이 생기면 화면이 부드럽게 응답합니다. 좋아요 버튼 하나로 시작해 봅니다.
.like {
color: #6b7280;
transition: color .18s ease, transform .18s ease;
}
.like:hover {
color: #ef4444;
}
.like:active {
transform: scale(1.25);
}
손을 올리면 회색이 빨강으로 번지고, 누르는 순간 살짝 커집니다. 색이 순간이동하지 않고 .18초에 걸쳐 넘어가는 것, 그 짧은 지연이 반응했다는 느낌을 만듭니다.
75.2 트리거, 규칙, 피드백, 반복
마이크로인터랙션은 네 부분으로 쪼갤 수 있습니다. 무엇이 시작시키는가(트리거), 무엇이 일어나는가(규칙), 무엇이 보이는가(피드백), 어떻게 유지되는가(모드)입니다. 토글 스위치로 넷을 한꺼번에 봅니다.
.switch {
width: 44px;
height: 24px;
background: #d1d5db;
border-radius: 999px;
position: relative;
transition: background .2s ease;
}
.switch::after {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background: #fff;
border-radius: 50%;
transition: transform .2s ease;
}
.switch.on {
background: #22c55e;
}
.switch.on::after {
transform: translateX(20px);
}
클릭이 트리거, on 클래스 토글이 규칙, 손잡이가 미끄러지고 배경이 초록으로 바뀌는 게 피드백, 켜진 채 머무는 게 모드입니다. 손잡이가 20px를 미끄러져 가기에 켰다는 사실이 눈에 남습니다.
75.3 피드백이 없으면 대화가 끊긴다
같은 버튼을 반응 없이 두면 어떤 느낌인지 비교해 봅니다. 아래는 아무 상태 전환도 없는 버튼입니다.
.btn {
background: #2563eb;
color: #fff;
padding: 10px 16px;
border-radius: 8px;
}
눌러도 화면은 미동도 없습니다. 사용자는 눌린 건지 확신이 안 서서 한 번 더 누르곤 합니다. 여기에 호버와 눌림 반응을 얹습니다.
.btn {
background: #2563eb;
color: #fff;
padding: 10px 16px;
border-radius: 8px;
cursor: pointer;
transition: background .15s ease, transform .08s ease;
}
.btn:hover {
background: #1d4ed8;
}
.btn:active {
transform: translateY(1px);
}
이제 손을 올리면 짙어지고 누르면 1px 내려앉습니다. 코드 몇 줄 차이지만, 화면이 내 조작에 대답한다는 감각은 완전히 달라집니다.
75.4 자연스러움은 이징에서 나온다
같은 동작이라도 어떤 속도 곡선을 타느냐에 따라 인상이 갈립니다. 처음부터 끝까지 일정 속도(linear)는 기계적이고, 시작과 끝을 눌러 주는 곡선은 자연스럽습니다.
.card {
transition: transform .25s linear;
}
.card-smooth {
transition: transform .25s cubic-bezier(.2, .8, .2, 1);
}
.card:hover,
.card-smooth:hover {
transform: translateY(-6px);
}
위 카드는 딱딱하게 튀어 오르고, 아래 카드는 슬쩍 떠오릅니다. 곡선 하나 바꿨을 뿐인데 손맛이 다릅니다. 이징은 뒤에서 계속 다룰 핵심 재료입니다.
75.5 트리거의 종류: 사람과 시스템
트리거는 사용자가 당기는 것과 시스템이 당기는 것으로 나뉩니다. 앞의 예제들은 hover, active처럼 사람이 당기는 것이었고, 알림 배지처럼 시스템이 스스로 켜는 것도 있습니다. 새 소식이 도착했다고 배지를 톡톡 뛰게 만들어 봅니다.
@keyframes ping {
0% {
transform: scale(1);
opacity: 1;
}
75%, 100% {
transform: scale(2);
opacity: 0;
}
}
.badge {
position: relative;
width: 10px;
height: 10px;
background: #ef4444;
border-radius: 50%;
}
.badge.new::before {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
background: #ef4444;
animation: ping 1.2s ease-out infinite;
}
new 클래스가 붙는 순간(시스템 트리거) 붉은 점 뒤로 물결이 퍼져 나가며 시선을 끕니다. 사용자가 아무 짓도 안 했는데 화면이 먼저 말을 거는 경우입니다.
75.6 상태를 코드로 남기기
피드백은 순간 반짝이고 끝나기도 하지만, 결과가 계속 남아야 할 때도 있습니다. 입력칸이 포커스를 받으면 테두리와 그림자로 지금 여기라고 알려 주는 반응은 머무는 피드백입니다.
.input {
border: 1px solid #d1d5db;
border-radius: 8px;
padding: 10px 12px;
transition: border-color .15s ease, box-shadow .15s ease;
}
.input:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, .2);
}
클릭해 커서를 두면 테두리가 파래지고 은은한 링이 감쌉니다. 손을 떼기 전까지 유지되니, 지금 어느 칸에 글자가 들어가는지 한눈에 잡힙니다.
75.7 움직임을 원하지 않는 사용자 존중하기
어떤 사용자는 화면이 움직이면 어지럼을 느낍니다. 마이크로인터랙션을 넣을 때는 처음부터 이 사람들을 위한 스위치를 함께 답니다.
@media (prefers-reduced-motion: reduce) {
.like,
.switch,
.switch::after,
.card,
.btn,
.input {
transition: none;
}
.badge.new::before {
animation: none;
}
}
운영체제에서 움직임 줄이기를 켠 사람에게는 애니메이션이 즉시 사라지고 상태만 바뀝니다. 반응은 그대로 전하되 움직임만 뺀 것, 이게 마이크로인터랙션을 다루는 기본 예의입니다.
75.8 정리
마이크로인터랙션은 화면과 손 사이의 짧은 대화입니다. 트리거에 규칙으로 답하고, 그 답을 부드러운 피드백으로 보이게 하고, 적절한 이징으로 자연스럽게 만들고, 움직임을 싫어하는 사람까지 챙기는 것. 이 다섯 조각이 전부입니다.