03라벨 툴팁
아이콘에 손을 올리면 이름표가 아이콘 아래쪽 변을 경첩 삼아 위로 튀어 오르고, 손이 옆으로 옮기면 이전 이름표는 곧바로 사라집니다.
쓰임아이콘만 쓴 독에서 처음 온 사람에게 각 단추가 뭘 하는지 알려 줘야 할 때
scaleYsteps(1, end)transform-origin

<main class="stage">
<div class="tt is-demo" id="tt">
<nav class="tt__dock" aria-label="주요 메뉴">
<button class="tt__btn" type="button">
<span class="tt__tip" aria-hidden="true">홈</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true"><g fill="currentColor"><path d="M216 120v96h-64v-64h-48v64H40v-96a8 8 0 0 1 2.34-5.66l80-80a8 8 0 0 1 11.32 0l80 80A8 8 0 0 1 216 120" opacity=".2"/><path d="m219.31 108.68l-80-80a16 16 0 0 0-22.62 0l-80 80A15.87 15.87 0 0 0 32 120v96a8 8 0 0 0 8 8h64a8 8 0 0 0 8-8v-56h32v56a8 8 0 0 0 8 8h64a8 8 0 0 0 8-8v-96a15.87 15.87 0 0 0-4.69-11.32M208 208h-48v-56a8 8 0 0 0-8-8h-48a8 8 0 0 0-8 8v56H48v-88l80-80l80 80Z"/></g></svg>
<span class="tt__sr">홈</span>
</button>
<button class="tt__btn" type="button">
<span class="tt__tip" aria-hidden="true">검색</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true"><g fill="currentColor"><path d="M192 112a80 80 0 1 1-80-80a80 80 0 0 1 80 80" opacity=".2"/><path d="m229.66 218.34l-50.06-50.06a88.21 88.21 0 1 0-11.32 11.31l50.06 50.07a8 8 0 0 0 11.32-11.32M40 112a72 72 0 1 1 72 72a72.08 72.08 0 0 1-72-72"/></g></svg>
<span class="tt__sr">검색</span>
</button>
<button class="tt__btn" type="button">
<span class="tt__tip" aria-hidden="true">사진</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true"><g fill="currentColor"><path d="M224 56v122.06l-39.72-39.72a8 8 0 0 0-11.31 0L147.31 164l-49.65-49.66a8 8 0 0 0-11.32 0L32 168.69V56a8 8 0 0 1 8-8h176a8 8 0 0 1 8 8" opacity=".2"/><path d="M216 40H40a16 16 0 0 0-16 16v144a16 16 0 0 0 16 16h176a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16m0 16v102.75l-26.07-26.06a16 16 0 0 0-22.63 0l-20 20l-44-44a16 16 0 0 0-22.62 0L40 149.37V56ZM40 172l52-52l80 80H40Zm176 28h-21.37l-36-36l20-20L216 181.38zm-72-100a12 12 0 1 1 12 12a12 12 0 0 1-12-12"/></g></svg>
<span class="tt__sr">사진</span>
</button>
<button class="tt__btn" type="button">
<span class="tt__tip" aria-hidden="true">즐겨찾기</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true"><g fill="currentColor"><path d="m229.06 108.79l-48.7 42l14.88 62.79a8.4 8.4 0 0 1-12.52 9.17L128 189.09l-54.72 33.65a8.4 8.4 0 0 1-12.52-9.17l14.88-62.79l-48.7-42A8.46 8.46 0 0 1 31.73 94l63.91-5.2l24.62-59.6a8.36 8.36 0 0 1 15.48 0l24.62 59.6l63.91 5.2a8.46 8.46 0 0 1 4.79 14.79" opacity=".2"/><path d="M239.18 97.26A16.38 16.38 0 0 0 224.92 86l-59-4.76l-22.78-55.09a16.36 16.36 0 0 0-30.27 0L90.11 81.23L31.08 86a16.46 16.46 0 0 0-9.37 28.86l45 38.83L53 211.75a16.38 16.38 0 0 0 24.5 17.82l50.5-31.08l50.53 31.08A16.4 16.4 0 0 0 203 211.75l-13.76-58.07l45-38.83a16.43 16.43 0 0 0 4.94-17.59m-15.34 5.47l-48.7 42a8 8 0 0 0-2.56 7.91l14.88 62.8a.37.37 0 0 1-.17.48c-.18.14-.23.11-.38 0l-54.72-33.65a8 8 0 0 0-8.38 0l-54.72 33.67c-.15.09-.19.12-.38 0a.37.37 0 0 1-.17-.48l14.88-62.8a8 8 0 0 0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16a8 8 0 0 0 6.72-4.94l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153 91.86a8 8 0 0 0 6.75 4.92l63.92 5.16c.15 0 .24 0 .33.29s0 .4-.16.5"/></g></svg>
<span class="tt__sr">즐겨찾기</span>
</button>
<button class="tt__btn" type="button">
<span class="tt__tip" aria-hidden="true">설정</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true"><g fill="currentColor"><path d="m207.86 123.18l16.78-21a99 99 0 0 0-10.07-24.29l-26.7-3a81 81 0 0 0-6.81-6.81l-3-26.71a99.4 99.4 0 0 0-24.3-10l-21 16.77a82 82 0 0 0-9.64 0l-21-16.78a99 99 0 0 0-24.21 10.07l-3 26.7a81 81 0 0 0-6.81 6.81l-26.71 3a99.4 99.4 0 0 0-10 24.3l16.77 21a82 82 0 0 0 0 9.64l-16.78 21a99 99 0 0 0 10.07 24.29l26.7 3a81 81 0 0 0 6.81 6.81l3 26.71a99.4 99.4 0 0 0 24.3 10l21-16.77a82 82 0 0 0 9.64 0l21 16.78a99.4 99.4 0 0 0 24.29-10.07l3-26.7a81 81 0 0 0 6.81-6.81l26.71-3a99.4 99.4 0 0 0 10-24.3l-16.77-21a82 82 0 0 0-.08-9.64M128 168a40 40 0 1 1 40-40a40 40 0 0 1-40 40" opacity=".2"/><path d="M128 80a48 48 0 1 0 48 48a48.05 48.05 0 0 0-48-48m0 80a32 32 0 1 1 32-32a32 32 0 0 1-32 32m88-29.84q.06-2.16 0-4.32l14.92-18.64a8 8 0 0 0 1.48-7.06a107.6 107.6 0 0 0-10.88-26.25a8 8 0 0 0-6-3.93l-23.72-2.64q-1.48-1.56-3-3L186 40.54a8 8 0 0 0-3.94-6a107.3 107.3 0 0 0-26.25-10.86a8 8 0 0 0-7.06 1.48L130.16 40h-4.32L107.2 25.11a8 8 0 0 0-7.06-1.48a107.6 107.6 0 0 0-26.25 10.88a8 8 0 0 0-3.93 6l-2.64 23.76q-1.56 1.49-3 3L40.54 70a8 8 0 0 0-6 3.94a107.7 107.7 0 0 0-10.87 26.25a8 8 0 0 0 1.49 7.06L40 125.84v4.32L25.11 148.8a8 8 0 0 0-1.48 7.06a107.6 107.6 0 0 0 10.88 26.25a8 8 0 0 0 6 3.93l23.72 2.64q1.49 1.56 3 3L70 215.46a8 8 0 0 0 3.94 6a107.7 107.7 0 0 0 26.25 10.87a8 8 0 0 0 7.06-1.49L125.84 216q2.16.06 4.32 0l18.64 14.92a8 8 0 0 0 7.06 1.48a107.2 107.2 0 0 0 26.25-10.88a8 8 0 0 0 3.93-6l2.64-23.72q1.56-1.48 3-3l23.78-2.8a8 8 0 0 0 6-3.94a107.7 107.7 0 0 0 10.87-26.25a8 8 0 0 0-1.49-7.06Zm-16.1-6.5a74 74 0 0 1 0 8.68a8 8 0 0 0 1.74 5.48l14.19 17.73a91.6 91.6 0 0 1-6.23 15l-22.6 2.56a8 8 0 0 0-5.1 2.64a74 74 0 0 1-6.14 6.14a8 8 0 0 0-2.64 5.1l-2.51 22.58a91.3 91.3 0 0 1-15 6.23l-17.74-14.19a8 8 0 0 0-5-1.75h-.48a74 74 0 0 1-8.68 0a8.06 8.06 0 0 0-5.48 1.74l-17.78 14.2a91.6 91.6 0 0 1-15-6.23L82.89 187a8 8 0 0 0-2.64-5.1a74 74 0 0 1-6.14-6.14a8 8 0 0 0-5.1-2.64l-22.58-2.52a91.3 91.3 0 0 1-6.23-15l14.19-17.74a8 8 0 0 0 1.74-5.48a74 74 0 0 1 0-8.68a8 8 0 0 0-1.74-5.48L40.2 100.45a91.6 91.6 0 0 1 6.23-15L69 82.89a8 8 0 0 0 5.1-2.64a74 74 0 0 1 6.14-6.14A8 8 0 0 0 82.89 69l2.51-22.57a91.3 91.3 0 0 1 15-6.23l17.74 14.19a8 8 0 0 0 5.48 1.74a74 74 0 0 1 8.68 0a8.06 8.06 0 0 0 5.48-1.74l17.77-14.19a91.6 91.6 0 0 1 15 6.23L173.11 69a8 8 0 0 0 2.64 5.1a74 74 0 0 1 6.14 6.14a8 8 0 0 0 5.1 2.64l22.58 2.51a91.3 91.3 0 0 1 6.23 15l-14.19 17.74a8 8 0 0 0-1.74 5.53Z"/></g></svg>
<span class="tt__sr">설정</span>
</button>
</nav>
<p class="tt__cap">아이콘에 손을 올리면 이름표가 튀어 오릅니다</p>
</div>
</main>@use "../../../../site/static/demo-tokens" as *;
$duration: $dur-quick;
$easing: $ease-pop;
$color: $subject-ink;
@include stage($stage-yellow);
.tt {
display: flex;
flex-direction: column;
align-items: center;
gap: $sp-4;
// 이름표는 절대 배치라 부모 높이에 안 들어간다 — 위쪽 자리를 미리 비워 둔다
padding-top: $sp-10;
}
.tt__dock {
display: flex;
gap: $sp-2;
padding: $sp-2;
border-radius: $r-pill;
background: $subject-ink;
}
.tt__btn {
position: relative;
width: 48px;
height: 48px;
display: grid;
place-items: center;
padding: 0;
border: 0;
border-radius: $r-pill;
background: none;
color: rgba(255, 255, 255, .6);
cursor: pointer;
transition: color $duration $easing, background-color $duration $easing;
}
.tt__btn svg { width: 24px; height: 24px; display: block; }
.tt__btn:hover,
.tt__btn:focus-visible { color: #fff; background: rgba(255, 255, 255, .12); }
.tt__btn:focus-visible { outline: 2px solid $stage-yellow; outline-offset: 2px; }
.tt__sr {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.tt__tip {
position: absolute;
bottom: calc(100% + #{$sp-2});
left: 50%;
padding: $sp-1 $sp-2;
border-radius: $r-xs;
background: $color;
color: $stage-yellow;
font-size: 12px;
font-weight: 600;
line-height: 1.4;
white-space: nowrap;
pointer-events: none;
opacity: 0;
// 경첩은 아이콘 쪽 변 — 아래에서 위로 펴진다
transform-origin: bottom center;
transform: translateX(-50%) scaleY(0);
transition: transform $duration $easing, opacity $dur-instant steps(1, end);
}
.tt__btn:hover .tt__tip,
.tt__btn:focus-visible .tt__tip {
opacity: 1;
transform: translateX(-50%) scaleY(1);
}
.tt__cap {
margin: 0;
font-size: 13px;
line-height: 1.5;
color: rgba(23, 20, 26, .7);
}
/* 자동 재생 — 이름표가 왼쪽부터 차례로 올라온다. 사라짐은 컷(steps) */
.is-demo .tt__tip {
animation-name: tt-pop;
animation-duration: 2s;
animation-timing-function: $ease-pop;
animation-iteration-count: infinite;
}
.is-demo .tt__btn:nth-child(2) .tt__tip { animation-delay: .34s; }
.is-demo .tt__btn:nth-child(3) .tt__tip { animation-delay: .68s; }
.is-demo .tt__btn:nth-child(4) .tt__tip { animation-delay: 1.02s; }
.is-demo .tt__btn:nth-child(5) .tt__tip { animation-delay: 1.36s; }
.is-demo .tt__btn {
animation-name: tt-lit;
animation-duration: 2s;
animation-timing-function: steps(1, end);
animation-iteration-count: infinite;
}
.is-demo .tt__btn:nth-child(2) { animation-delay: .34s; }
.is-demo .tt__btn:nth-child(3) { animation-delay: .68s; }
.is-demo .tt__btn:nth-child(4) { animation-delay: 1.02s; }
.is-demo .tt__btn:nth-child(5) { animation-delay: 1.36s; }
@keyframes tt-pop {
0% { opacity: 0; transform: translateX(-50%) scaleY(0); }
3% { opacity: 1; transform: translateX(-50%) scaleY(0); }
9% { opacity: 1; transform: translateX(-50%) scaleY(1); }
26% { opacity: 1; transform: translateX(-50%) scaleY(1); }
26.01% { opacity: 0; transform: translateX(-50%) scaleY(0); }
100% { opacity: 0; transform: translateX(-50%) scaleY(0); }
}
@keyframes tt-lit {
0% { color: rgba(255, 255, 255, .6); background: none; }
3% { color: #fff; background: rgba(255, 255, 255, .12); }
26% { color: rgba(255, 255, 255, .6); background: none; }
100% { color: rgba(255, 255, 255, .6); background: none; }
}
@media (max-width: 340px) {
.tt__btn { width: 44px; height: 44px; }
.tt { padding-top: $sp-8; }
}
@media (prefers-reduced-motion: reduce) {
.is-demo .tt__tip,
.is-demo .tt__btn { animation-name: none; }
.tt__tip,
.tt__btn { transition: none; }
}@charset "UTF-8";
html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #ffd23f;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.tt {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
padding-top: 40px;
}
.tt__dock {
display: flex;
gap: 8px;
padding: 8px;
border-radius: 999px;
background: #17141a;
}
.tt__btn {
position: relative;
width: 48px;
height: 48px;
display: grid;
place-items: center;
padding: 0;
border: 0;
border-radius: 999px;
background: none;
color: rgba(255, 255, 255, 0.6);
cursor: pointer;
transition: color 220ms cubic-bezier(0.2, 1.4, 0.4, 1), background-color 220ms cubic-bezier(0.2, 1.4, 0.4, 1);
}
.tt__btn svg {
width: 24px;
height: 24px;
display: block;
}
.tt__btn:hover,
.tt__btn:focus-visible {
color: #fff;
background: rgba(255, 255, 255, 0.12);
}
.tt__btn:focus-visible {
outline: 2px solid #ffd23f;
outline-offset: 2px;
}
.tt__sr {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.tt__tip {
position: absolute;
bottom: calc(100% + 8px);
left: 50%;
padding: 4px 8px;
border-radius: 4px;
background: #17141a;
color: #ffd23f;
font-size: 12px;
font-weight: 600;
line-height: 1.4;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transform-origin: bottom center;
transform: translateX(-50%) scaleY(0);
transition: transform 220ms cubic-bezier(0.2, 1.4, 0.4, 1), opacity 140ms steps(1, end);
}
.tt__btn:hover .tt__tip,
.tt__btn:focus-visible .tt__tip {
opacity: 1;
transform: translateX(-50%) scaleY(1);
}
.tt__cap {
margin: 0;
font-size: 13px;
line-height: 1.5;
color: rgba(23, 20, 26, 0.7);
}
/* 자동 재생 — 이름표가 왼쪽부터 차례로 올라온다. 사라짐은 컷(steps) */
.is-demo .tt__tip {
animation-name: tt-pop;
animation-duration: 2s;
animation-timing-function: cubic-bezier(0.2, 1.4, 0.4, 1);
animation-iteration-count: infinite;
}
.is-demo .tt__btn:nth-child(2) .tt__tip {
animation-delay: 0.34s;
}
.is-demo .tt__btn:nth-child(3) .tt__tip {
animation-delay: 0.68s;
}
.is-demo .tt__btn:nth-child(4) .tt__tip {
animation-delay: 1.02s;
}
.is-demo .tt__btn:nth-child(5) .tt__tip {
animation-delay: 1.36s;
}
.is-demo .tt__btn {
animation-name: tt-lit;
animation-duration: 2s;
animation-timing-function: steps(1, end);
animation-iteration-count: infinite;
}
.is-demo .tt__btn:nth-child(2) {
animation-delay: 0.34s;
}
.is-demo .tt__btn:nth-child(3) {
animation-delay: 0.68s;
}
.is-demo .tt__btn:nth-child(4) {
animation-delay: 1.02s;
}
.is-demo .tt__btn:nth-child(5) {
animation-delay: 1.36s;
}
@keyframes tt-pop {
0% {
opacity: 0;
transform: translateX(-50%) scaleY(0);
}
3% {
opacity: 1;
transform: translateX(-50%) scaleY(0);
}
9% {
opacity: 1;
transform: translateX(-50%) scaleY(1);
}
26% {
opacity: 1;
transform: translateX(-50%) scaleY(1);
}
26.01% {
opacity: 0;
transform: translateX(-50%) scaleY(0);
}
100% {
opacity: 0;
transform: translateX(-50%) scaleY(0);
}
}
@keyframes tt-lit {
0% {
color: rgba(255, 255, 255, 0.6);
background: none;
}
3% {
color: #fff;
background: rgba(255, 255, 255, 0.12);
}
26% {
color: rgba(255, 255, 255, 0.6);
background: none;
}
100% {
color: rgba(255, 255, 255, 0.6);
background: none;
}
}
@media (max-width: 340px) {
.tt__btn {
width: 44px;
height: 44px;
}
.tt {
padding-top: 32px;
}
}
@media (prefers-reduced-motion: reduce) {
.is-demo .tt__tip,
.is-demo .tt__btn {
animation-name: none;
}
.tt__tip,
.tt__btn {
transition: none;
}
}// 실제 동작: 사람이 만지면 .is-demo 를 떼고, 그 뒤로는 :hover · :focus-visible 이 이름표를 연다.
var root = document.getElementById('tt');
['pointerenter', 'focusin'].forEach(function (t) {
root.addEventListener(t, function () { root.classList.remove('is-demo'); });
});import type { CSSProperties } from "react";
import styles from "./LabelTooltipDock.module.scss";
export type LabelTooltipDockProps = {
duration?: number;
easing?: string;
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
const ICONS = [
{
label: "Home",
svg: (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true"><g fill="currentColor"><path d="M216 120v96h-64v-64h-48v64H40v-96a8 8 0 0 1 2.34-5.66l80-80a8 8 0 0 1 11.32 0l80 80A8 8 0 0 1 216 120" opacity=".2"/><path d="m219.31 108.68l-80-80a16 16 0 0 0-22.62 0l-80 80A15.87 15.87 0 0 0 32 120v96a8 8 0 0 0 8 8h64a8 8 0 0 0 8-8v-56h32v56a8 8 0 0 0 8 8h64a8 8 0 0 0 8-8v-96a15.87 15.87 0 0 0-4.69-11.32M208 208h-48v-56a8 8 0 0 0-8-8h-48a8 8 0 0 0-8 8v56H48v-88l80-80l80 80Z"/></g></svg>
),
},
{
label: "Search",
svg: (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true"><g fill="currentColor"><path d="M192 112a80 80 0 1 1-80-80a80 80 0 0 1 80 80" opacity=".2"/><path d="m229.66 218.34l-50.06-50.06a88.21 88.21 0 1 0-11.32 11.31l50.06 50.07a8 8 0 0 0 11.32-11.32M40 112a72 72 0 1 1 72 72a72.08 72.08 0 0 1-72-72"/></g></svg>
),
},
{
label: "Photos",
svg: (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true"><g fill="currentColor"><path d="M224 56v122.06l-39.72-39.72a8 8 0 0 0-11.31 0L147.31 164l-49.65-49.66a8 8 0 0 0-11.32 0L32 168.69V56a8 8 0 0 1 8-8h176a8 8 0 0 1 8 8" opacity=".2"/><path d="M216 40H40a16 16 0 0 0-16 16v144a16 16 0 0 0 16 16h176a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16m0 16v102.75l-26.07-26.06a16 16 0 0 0-22.63 0l-20 20l-44-44a16 16 0 0 0-22.62 0L40 149.37V56ZM40 172l52-52l80 80H40Zm176 28h-21.37l-36-36l20-20L216 181.38zm-72-100a12 12 0 1 1 12 12a12 12 0 0 1-12-12"/></g></svg>
),
},
{
label: "Favorites",
svg: (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true"><g fill="currentColor"><path d="m229.06 108.79l-48.7 42l14.88 62.79a8.4 8.4 0 0 1-12.52 9.17L128 189.09l-54.72 33.65a8.4 8.4 0 0 1-12.52-9.17l14.88-62.79l-48.7-42A8.46 8.46 0 0 1 31.73 94l63.91-5.2l24.62-59.6a8.36 8.36 0 0 1 15.48 0l24.62 59.6l63.91 5.2a8.46 8.46 0 0 1 4.79 14.79" opacity=".2"/><path d="M239.18 97.26A16.38 16.38 0 0 0 224.92 86l-59-4.76l-22.78-55.09a16.36 16.36 0 0 0-30.27 0L90.11 81.23L31.08 86a16.46 16.46 0 0 0-9.37 28.86l45 38.83L53 211.75a16.38 16.38 0 0 0 24.5 17.82l50.5-31.08l50.53 31.08A16.4 16.4 0 0 0 203 211.75l-13.76-58.07l45-38.83a16.43 16.43 0 0 0 4.94-17.59m-15.34 5.47l-48.7 42a8 8 0 0 0-2.56 7.91l14.88 62.8a.37.37 0 0 1-.17.48c-.18.14-.23.11-.38 0l-54.72-33.65a8 8 0 0 0-8.38 0l-54.72 33.67c-.15.09-.19.12-.38 0a.37.37 0 0 1-.17-.48l14.88-62.8a8 8 0 0 0-2.56-7.91l-48.7-42c-.12-.1-.23-.19-.13-.5s.18-.27.33-.29l63.92-5.16a8 8 0 0 0 6.72-4.94l24.62-59.61c.08-.17.11-.25.35-.25s.27.08.35.25L153 91.86a8 8 0 0 0 6.75 4.92l63.92 5.16c.15 0 .24 0 .33.29s0 .4-.16.5"/></g></svg>
),
},
{
label: "Settings",
svg: (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" aria-hidden="true"><g fill="currentColor"><path d="m207.86 123.18l16.78-21a99 99 0 0 0-10.07-24.29l-26.7-3a81 81 0 0 0-6.81-6.81l-3-26.71a99.4 99.4 0 0 0-24.3-10l-21 16.77a82 82 0 0 0-9.64 0l-21-16.78a99 99 0 0 0-24.21 10.07l-3 26.7a81 81 0 0 0-6.81 6.81l-26.71 3a99.4 99.4 0 0 0-10 24.3l16.77 21a82 82 0 0 0 0 9.64l-16.78 21a99 99 0 0 0 10.07 24.29l26.7 3a81 81 0 0 0 6.81 6.81l3 26.71a99.4 99.4 0 0 0 24.3 10l21-16.77a82 82 0 0 0 9.64 0l21 16.78a99.4 99.4 0 0 0 24.29-10.07l3-26.7a81 81 0 0 0 6.81-6.81l26.71-3a99.4 99.4 0 0 0 10-24.3l-16.77-21a82 82 0 0 0-.08-9.64M128 168a40 40 0 1 1 40-40a40 40 0 0 1-40 40" opacity=".2"/><path d="M128 80a48 48 0 1 0 48 48a48.05 48.05 0 0 0-48-48m0 80a32 32 0 1 1 32-32a32 32 0 0 1-32 32m88-29.84q.06-2.16 0-4.32l14.92-18.64a8 8 0 0 0 1.48-7.06a107.6 107.6 0 0 0-10.88-26.25a8 8 0 0 0-6-3.93l-23.72-2.64q-1.48-1.56-3-3L186 40.54a8 8 0 0 0-3.94-6a107.3 107.3 0 0 0-26.25-10.86a8 8 0 0 0-7.06 1.48L130.16 40h-4.32L107.2 25.11a8 8 0 0 0-7.06-1.48a107.6 107.6 0 0 0-26.25 10.88a8 8 0 0 0-3.93 6l-2.64 23.76q-1.56 1.49-3 3L40.54 70a8 8 0 0 0-6 3.94a107.7 107.7 0 0 0-10.87 26.25a8 8 0 0 0 1.49 7.06L40 125.84v4.32L25.11 148.8a8 8 0 0 0-1.48 7.06a107.6 107.6 0 0 0 10.88 26.25a8 8 0 0 0 6 3.93l23.72 2.64q1.49 1.56 3 3L70 215.46a8 8 0 0 0 3.94 6a107.7 107.7 0 0 0 26.25 10.87a8 8 0 0 0 7.06-1.49L125.84 216q2.16.06 4.32 0l18.64 14.92a8 8 0 0 0 7.06 1.48a107.2 107.2 0 0 0 26.25-10.88a8 8 0 0 0 3.93-6l2.64-23.72q1.56-1.48 3-3l23.78-2.8a8 8 0 0 0 6-3.94a107.7 107.7 0 0 0 10.87-26.25a8 8 0 0 0-1.49-7.06Zm-16.1-6.5a74 74 0 0 1 0 8.68a8 8 0 0 0 1.74 5.48l14.19 17.73a91.6 91.6 0 0 1-6.23 15l-22.6 2.56a8 8 0 0 0-5.1 2.64a74 74 0 0 1-6.14 6.14a8 8 0 0 0-2.64 5.1l-2.51 22.58a91.3 91.3 0 0 1-15 6.23l-17.74-14.19a8 8 0 0 0-5-1.75h-.48a74 74 0 0 1-8.68 0a8.06 8.06 0 0 0-5.48 1.74l-17.78 14.2a91.6 91.6 0 0 1-15-6.23L82.89 187a8 8 0 0 0-2.64-5.1a74 74 0 0 1-6.14-6.14a8 8 0 0 0-5.1-2.64l-22.58-2.52a91.3 91.3 0 0 1-6.23-15l14.19-17.74a8 8 0 0 0 1.74-5.48a74 74 0 0 1 0-8.68a8 8 0 0 0-1.74-5.48L40.2 100.45a91.6 91.6 0 0 1 6.23-15L69 82.89a8 8 0 0 0 5.1-2.64a74 74 0 0 1 6.14-6.14A8 8 0 0 0 82.89 69l2.51-22.57a91.3 91.3 0 0 1 15-6.23l17.74 14.19a8 8 0 0 0 5.48 1.74a74 74 0 0 1 8.68 0a8.06 8.06 0 0 0 5.48-1.74l17.77-14.19a91.6 91.6 0 0 1 15 6.23L173.11 69a8 8 0 0 0 2.64 5.1a74 74 0 0 1 6.14 6.14a8 8 0 0 0 5.1 2.64l22.58 2.51a91.3 91.3 0 0 1 6.23 15l-14.19 17.74a8 8 0 0 0-1.74 5.53Z"/></g></svg>
),
},
];
export default function LabelTooltipDock({
duration = 220,
easing = "cubic-bezier(.2,1.4,.4,1)",
color = "#17141a",
}: LabelTooltipDockProps) {
// 실제 동작: :hover · :focus-visible 이 이름표를 연다 — 상태 없이 CSS 가 전부 처리한다.
const vars: Vars = {
"--duration": `${duration}ms`,
"--easing": easing,
"--color": color,
};
return (
<div className={styles.tt} style={vars}>
<nav className={styles.dock} aria-label="Main menu">
{ICONS.map((it) => (
<button key={it.label} className={styles.btn} type="button">
<span className={styles.tip} aria-hidden="true">{it.label}</span>
{it.svg}
<span className={styles.sr}>{it.label}</span>
</button>
))}
</nav>
<p className={styles.cap}>Hover an icon and its label pops up</p>
</div>
);
}03 라벨 툴팁 — 측정 누적면적 10.12% · 움직인 프레임 15/23GODRICH 원작 · zip 에 SCSS·React 포함 · 플로팅 내비게이션 독 스타일 9종 — 호버 물결이 따라오는
이 데모가 속한 글
플로팅 내비게이션 독 스타일 9종 — 호버 물결이 따라오는플로팅 내비게이션은 화면 가장자리에 띄워 둔 작은 메뉴 막대이고, 아이콘 단추 몇 개와 지금 어느 칸인지 알려 주는 표시 하나로 이루어집니다. 아홉 개 중 하나는 이웃 아이콘까지 밀어내며 부풉니다. 이 글의 데모 전부 보기


