弹出提示

短暂停顿后,提示气泡带着一点弹性从图标按钮上方弹出,帮得上忙又不碍事。

  • CSS
  • 按钮
  • 悬停
  • 收录于

AI 提示词

用 CSS 制作弹出式的图标按钮提示。每个按钮设为 position: relative,内含一个 role="tooltip" 的提示元素,并通过按钮上的 aria-describedby 关联;提示位于按钮上方居中,用旋转的伪元素画一个小箭头。静止时提示为 opacity 0、transform: translate(-50%, 4px) scale(0.85),transform-origin 为底部中央,pointer-events none。在 :hover 和 :focus-visible 时,用 220ms、cubic-bezier(0.34, 1.56, 0.64, 1) 过渡到 opacity 1、translate(-50%, 0) scale(1),带一点回弹;并延迟 250ms 出现,避免指针划过工具栏时每个提示都闪一下。消失时不延迟,用 120ms 淡出。在 prefers-reduced-motion 下只淡入淡出,不缩放。提示文字为“加粗”“斜体”“添加链接”。

源代码

Demo.tsx
'use client'

import { useId } from 'react'
import s from './demo.module.css'

const ICONS = {
  bold: <path d="M7 5h6a3.5 3.5 0 0 1 0 7H7zM7 12h7a3.5 3.5 0 0 1 0 7H7z" />,
  italic: <path d="M14 5h-4M14 19h-4M13.5 5l-3 14" />,
  link: <path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1" />,
}

export default function TooltipPop({ labels }: { labels: Record<string, string> }) {
  const id = useId()

  return (
    <div className={s.bar} role="toolbar" aria-label={labels.toolbar}>
      {(Object.keys(ICONS) as (keyof typeof ICONS)[]).map((k) => (
        <button key={k} type="button" className={s.btn} aria-label={labels[k]} aria-describedby={`${id}-${k}`}>
          <svg viewBox="0 0 24 24" aria-hidden="true">
            {ICONS[k]}
          </svg>
          <span id={`${id}-${k}`} role="tooltip" className={s.tip}>
            {labels[k]}
          </span>
        </button>
      ))}
    </div>
  )
}
demo.module.css
.bar {
  display: flex;
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--stage-rule);
  border-radius: 12px;
  background: var(--stage-surface);
}

.btn {
  position: relative;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--stage-ink);
  cursor: pointer;
}

.btn:hover { background: var(--stage-bg); }
.btn:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 1px; }

.btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tip {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 10px);
  padding: 6px 9px;
  border-radius: 6px;
  background: var(--stage-ink);
  color: var(--stage-bg);
  font: 500 var(--text-xs) / 1 var(--font-body);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, 4px) scale(0.85);
  transform-origin: 50% 100%;
  transition: opacity 120ms, transform 120ms;
}

.tip::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 100%;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  background: inherit;
  rotate: 45deg;
}

.btn:hover .tip,
.btn:focus-visible .tip {
  opacity: 1;
  transform: translate(-50%, 0) scale(1);
  transition: opacity 220ms 250ms, transform 220ms cubic-bezier(0.34, 1.56, 0.64, 1) 250ms;
}

@media (prefers-reduced-motion: reduce) {
  .tip, .btn:hover .tip, .btn:focus-visible .tip { transform: translate(-50%, 0); }
}

投稿创意

看到想收录的动效或主题?简单描述一下,会打开一个预先填好的 GitHub Issue,确认后即可提交。

你想投稿的是?

需要 GitHub 账号,投稿内容会公开。