成功对勾

圆环自己画合,对勾随之描出,徽章再轻轻弹一下,告诉你事情办妥了。

  • CSS
  • SVG 与图形
  • 进场
  • 收录于

支付完成

AI 提示词

用 SVG 和 CSS 制作成功徽章动画。在 64px 的 viewBox 中画一个圆(r 26)和一条对勾路径,都只有描边。每条路径的 stroke-dasharray 设为路径长度,stroke-dashoffset 设为同样的值。先用 600ms、cubic-bezier(0.65, 0, 0.35, 1) 把圆的 offset 动到 0,在 550ms 时开始用 300ms 把对勾的 offset 动到 0,在 450ms 时用 260ms 把一个实心圆盘从 scale 0 放大到 1 作为底色,让对勾画在它上面,最后在 850ms 时让整个徽章用 300ms 做 scale 1 → 1.1 → 1 的弹跳。使用 animation-fill-mode both,让它停在完成状态。添加一个“重播”按钮,用新的 key 重新挂载 SVG。在 prefers-reduced-motion 下直接显示完成后的徽章。说明文字为“支付完成”。

源代码

Demo.tsx
'use client'

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

export default function SuccessCheck({ labels }: { labels: Record<string, string> }) {
  const [run, setRun] = useState(0)

  return (
    <div className={s.wrap}>
      <svg key={run} className={s.badge} viewBox="0 0 64 64" aria-hidden="true">
        <circle className={s.disc} cx="32" cy="32" r="26" />
        <circle className={s.ring} cx="32" cy="32" r="26" />
        <path className={s.check} d="M21 33l7.5 7.5L44 25" />
      </svg>
      <p className={s.caption}>{labels.caption}</p>
      <button type="button" className={s.replay} onClick={() => setRun((n) => n + 1)}>
        {labels.replay}
      </button>
    </div>
  )
}
demo.module.css
.wrap {
  display: grid;
  justify-items: center;
  gap: 10px;
}

.badge {
  width: 72px;
  height: 72px;
  animation: pop 300ms var(--ease-out) 850ms both;
}

.ring, .check {
  fill: none;
  stroke: var(--stage-accent);
  stroke-width: 3.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.ring {
  stroke-dasharray: 164;
  stroke-dashoffset: 164;
  transform: rotate(-90deg);
  transform-origin: center;
  animation: draw 600ms var(--ease-in-out) both;
}

.check {
  stroke: var(--stage-accent-ink);
  stroke-dasharray: 36;
  stroke-dashoffset: 36;
  animation: draw 300ms var(--ease-out) 550ms both;
}

.disc {
  fill: var(--stage-accent);
  transform: scale(0);
  transform-origin: center;
  animation: grow 260ms var(--ease-out) 450ms both;
}

@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes grow { to { transform: scale(1); } }
@keyframes pop { 50% { transform: scale(1.1); } }

.caption {
  margin: 0 0 6px;
  font: 600 var(--text-base) / 1.2 var(--font-display);
  color: var(--stage-ink);
}

.replay {
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--stage-rule);
  border-radius: var(--radius-sm);
  background: var(--stage-surface);
  color: var(--stage-ink);
  font: 500 var(--text-sm) / 1 var(--font-body);
  white-space: nowrap;
  cursor: pointer;
}

.replay:hover { border-color: var(--stage-accent); }
.replay:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .badge, .ring, .check, .disc { animation: none; }
  .ring, .check { stroke-dashoffset: 0; }
  .disc { transform: none; }
}

投稿创意

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

你想投稿的是?

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