태그 UI 디자인 9종 — 상태·우선순위·인증 배지 코드
태그 UI 디자인은 상태·카테고리·우선순위 같은 정보를 작은 알약이나 칩 모양으로 압축해 보여주는 장식이다. 온라인 점 하나, 우선순위 색 하나만 봐도 상태를 바로 알 수 있고, 움직임을 더하면 그대로 붙여서 훨씬 눈에 띄게 만들 수 있다. 태그 UI 디자인 9가지를 모았다.
자동 재생 · 눌러서 해당 항목으로 · 전부 한 zip
- 01 상태 표시 뱃지 (온라인·자리비움·다른용무·오프라인)
- 02 제거 버튼 달린 태그 칩
- 03 우선순위 라벨 배지 (낮음·보통·높음·긴급)
- 04 접힌 리본 펼침 코너 배지
- 05 알림 점 더블 펄스
- 06 기술 스택 태그 클라우드
- 07 업적 배지 잠금 해제 애니메이션
- 08 프리미엄·인증 배지 뒤집기
- 09 만료 임박 카운트다운 칩
아홉 개는 인기순이 아니라 화면을 쓰는 사람이 실제로 마주치는 순서로 놓았다. 로그인하면 먼저 팀원의 온라인 상태(01)를 보고, 관심사 태그를 직접 고르거나 지우고(02), 할 일에 우선순위(03)를 매긴다. 둘러보다 세일 리본(04)을 만나고 새 알림(05)을 받으며, 프로필에는 기술 스택(06)과 방금 딴 업적 배지(07), 등급을 증명하는 인증 배지(08)가 쌓이고, 마지막엔 곧 끝나는 쿠폰 만료(09)가 남는다.
01상태 표시 배지 (온라인·자리비움·다른 용무·오프라인)
온라인 점 뒤에 숨은 링이 opacity 와 scale 로 한 번씩 퍼져나가고, 나머지 세 상태는 색만 다른 채 멈춰 있어 온라인만 눈에 띈다.
.pill--online .dot::before {
content: "";
position: absolute; inset: -4px;
border-radius: 50%;
border: 2px solid $color;
opacity: 0;
transform: scale(.6);
}
.stage.is-demo .pill--online .dot::before {
animation: ping $duration $easing infinite;
}
@keyframes ping {
0% { opacity: .55; transform: scale(.6); }
70%, 100% { opacity: 0; transform: scale(2.1); }
}
02제거 버튼 달린 태그 칩
칩의 × 버튼을 누르면 scale·opacity 로 줄어들며 실제로 사라지고, 데모에서는 같은 동작을 한 칩이 스스로 반복한다.
.chip--gone {
transition: transform $dur-quick $easing, opacity $dur-quick $easing;
transform: scale(.6);
opacity: 0;
}
.stage.is-demo .chip--demo {
animation: chip-cycle $duration $easing infinite;
}
@keyframes chip-cycle {
0%, 38% { transform: scale(1); opacity: 1; }
55%, 78% { transform: scale(.55); opacity: 0; }
100% { transform: scale(1); opacity: 1; }
}
03우선순위 라벨 배지 (낮음·보통·높음·긴급)
긴급 라벨만 opacity·scale 로 깜빡여, 색만 다른 낮음·보통·높음 사이에서 가장 먼저 눈에 띄게 만든다.
.label--urgent {
background: $error-soft;
color: $color;
}
.stage.is-demo .label--urgent {
animation: urgent-flash $duration $easing infinite;
}
@keyframes urgent-flash {
0%, 40% { opacity: 1; transform: scale(1); }
55% { opacity: .5; transform: scale(1.05); }
70%, 100% { opacity: 1; transform: scale(1); }
}
04접힌 리본 펼침 코너 배지
카드 위쪽에서 접힌 리본이 transform-origin: top 기준 scaleY 로 펼쳐졌다가 다시 말려 올라가며, 다른 편의 빛줄기 리본과는 다른 움직임을 보여준다.
.ribbon {
clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 82%, 0 100%);
transform: scaleY(0) rotate(0deg);
transform-origin: top center;
}
.stage.is-demo .ribbon {
animation: unfurl $duration $easing infinite;
}
@keyframes unfurl {
0%, 8% { transform: scaleY(0) rotate(0deg); }
30% { transform: scaleY(1.06) rotate(-2deg); }
42%, 78% { transform: scaleY(1) rotate(0deg); }
92%, 100% { transform: scaleY(0) rotate(0deg); }
}
05알림 점 더블 펄스
아이콘은 그대로 두고 코너의 점만 scale 로 두 번 빠르게 튀어, 메시지 두 개가 막 도착한 리듬을 만든다.
.dot {
background: $color;
box-shadow: 0 0 0 2px $stage-ink;
}
.stage.is-demo .dot {
animation: double-pulse $duration $easing infinite;
}
.stage.is-demo .dot__ring {
animation: double-ring $duration $easing infinite;
}
@keyframes double-pulse {
0%, 100% { transform: scale(1); }
8%, 24% { transform: scale(1.35); }
16%, 32% { transform: scale(1); }
}
@keyframes double-ring {
0%, 6% { opacity: 0; transform: scale(1); }
20% { opacity: .5; transform: scale(2.4); }
34% { opacity: 0; transform: scale(2.6); }
100% { opacity: 0; transform: scale(1); }
}
06기술 스택 태그 클라우드
여섯 개 스킬 태그가 opacity·translateY 로 순서대로 떠올랐다 사라지길 반복해, 지연값만으로 물결치는 등장을 만든다.
.cloud li {
transform: translateY(10px);
opacity: 0;
}
.stage.is-demo .cloud li {
animation: rise $duration $easing infinite;
animation-delay: calc(var(--i) * 90ms);
}
@keyframes rise {
0% { opacity: 0; transform: translateY(10px); }
22%, 70% { opacity: 1; transform: translateY(0); }
92%, 100% { opacity: 0; transform: translateY(-6px); }
}
07업적 배지 잠금 해제 애니메이션
회색조로 흐려진 트로피가 scale 로 튀어 오르며 색을 되찾는 순간, 대각선 빛줄기가 한 번 스쳐 지나가며 방금 달성했음을 강조한다.
.badge {
filter: grayscale(1) brightness(.85);
transform: scale(.85);
}
.stage.is-demo .badge {
animation: unlock $duration $easing infinite;
}
@keyframes unlock {
0%, 30% { transform: scale(.85); filter: grayscale(1) brightness(.85); }
55% { transform: scale(1.12); filter: grayscale(0) brightness(1); }
70% { transform: scale(.96); }
82%, 100% { transform: scale(1); filter: grayscale(0) brightness(1); }
}
08프리미엄·인증 배지 뒤집기
카드 전체가 rotateY 로 3D 회전해 골드 Premium 면과 파란 Verified 면을 번갈아 보여준다.
.flip__inner {
transform-style: preserve-3d;
}
.flip__face {
backface-visibility: hidden;
}
.flip__face--back {
transform: rotateY(180deg);
}
.stage.is-demo .flip__inner {
animation: flip $duration $easing infinite;
}
@keyframes flip {
0%, 40% { transform: rotateY(0deg); }
55%, 85% { transform: rotateY(180deg); }
100% { transform: rotateY(360deg); }
}
09만료 임박 카운트다운 칩
초 자리 숫자 10개를 세로로 쌓아 translateY 로 한 칸씩 넘기며, 기계식 플립 카운터처럼 숫자가 넘어간다.
.chip__digit {
width: 18px; height: 26px;
overflow: hidden;
}
.chip__digit-track span {
height: 26px; line-height: 26px;
}
.stage.is-demo .chip__digit-track {
animation: tick $duration $easing infinite;
}
@keyframes tick {
0% { transform: translateY(0); }
100% { transform: translateY(-260px); }
}
어디서 깨지는가 — 숫자 칩은 줄 안에 박아 넣으면 깨진다
09번 카운트다운 칩의 초 자리 숫자를 처음엔 본문 글자와 같은 줄 안에 font-size 만 키워서 넣었더니, 숫자가 칩 밖으로 삐져나와 배경 위에 걸쳐 보였다. 원인은 inline-flex 인 칩이 줄 높이를 주변 텍스트 기준으로 계산하는데, 그 안의 큰 글자가 줄 바깥으로 넘치면서 overflow: hidden 이 없는 칩 테두리를 그냥 지나쳐 버린 것이다. 숫자를 가로세로 고정 크기(18×26px)의 독립된 박스로 떼어내고 칩 자체에도 overflow: hidden 을 걸자 숫자가 항상 칩 안에서만 넘어갔다. 압축을 풀 때 묻는 비밀번호는 cwww6ahb 이고, 받은 파일명 그대로 입력하면 아홉 개 폴더가 그대로 열린다. 08번 배지처럼 rotateY 로 회전하는 요소는 backface-visibility: hidden 을 앞뒤 두 면 모두에 넣지 않으면, 회전 중 뒷면 글자가 거울처럼 뒤집힌 채 비쳐 보인다.
접근성
아홉 개 전부 prefers-reduced-motion: reduce 에서 애니메이션이 꺼지고 마지막 상태로 고정된다. 01번 온라인 링은 고리 없이 점만 남고, 07번 업적 배지는 잠금이 풀린 색 그대로 멈추며, 09번 카운트다운 숫자도 더 넘어가지 않고 멈춘다. 링·점·리본 모두 색과 모양만으로 상태를 구분할 수 있게 처음부터 설계했다. 자세한 설정법은 MDN 의 prefers-reduced-motion 문서 에 있다.
FAQ
상태 배지 색은 마음대로 바꿔도 되나요?
네, 대부분 SCSS 맨 위 $color 하나만 바꾸면 된다. 08번 프리미엄·인증 배지처럼 두 면이 각각 다른 색을 쓰는 항목은 두 면의 그라데이션을 각각 고쳐야 한다. 더 많은 배지·태그 아이디어는 뱃지 디자인 UI 9종 에서 볼 수 있다.
자바스크립트 없이 태그 제거 칩을 써도 되나요?
CSS 애니메이션만으로는 실제 제거는 안 된다. 02번 칩은 클릭하면 요소를 지우는 바닐라 JS 10줄이 함께 있어야 진짜로 동작한다. React 버전은 같은 동작을 useState 훅 두 개로 옮겼다.
카운트다운 숫자는 실제 초를 세나요?
이 데모는 움직임을 보여주기 위한 루프라 실제 시계와 연결돼 있지 않다. 진짜 남은 시간을 세려면 setInterval 로 목표 시각과의 차이를 계산해 숫자만 바꿔 끼우면 된다. 만드는 과정은 소개 페이지 에서 더 볼 수 있다.