镭射卡片

一层变幻色彩的镭射光泽跟着指针在卡面上流动,像在灯下转动一张收藏卡。

  • CSS
  • 卡片
  • 跟随指针
  • 收录于
★

限量版

编号 042 / 300

AI 提示词

用 React 和 CSS 制作镭射卡片。pointermove 时把指针位置以 0–1 的比例写入卡片的 CSS 自定义属性 --x 和 --y,并把 --on 设为 1;pointerleave 时把 --on 设回 0。添加一个 ::before 覆盖层,使用 115deg 的柔和彩虹色 repeating-linear-gradient,background-size 200% 200%,background-position 为 calc(var(--x) * 100%) calc(var(--y) * 100%),用 mix-blend-mode: color-dodge 混合,opacity 为 calc(var(--on) * 0.3)。再添加一个 ::after,用中心位于同一位置的白色 radial-gradient 做高光。用 rotateY(calc((var(--x) - 0.5) * 12deg * var(--on))) 及对应的 rotateX 让卡片最多倾斜 6deg,并加 120ms 过渡让它平滑跟随。在 prefers-reduced-motion 下保留光泽,去掉倾斜。卡片文字为“限量版”和“编号 042 / 300”。

源代码

Demo.tsx
'use client'

import s from './demo.module.css'

export default function HolographicCard({ labels }: { labels: Record<string, string> }) {
  const onMove = (e: React.PointerEvent<HTMLDivElement>) => {
    const el = e.currentTarget
    const r = el.getBoundingClientRect()
    el.style.setProperty('--x', String((e.clientX - r.left) / r.width))
    el.style.setProperty('--y', String((e.clientY - r.top) / r.height))
    el.style.setProperty('--on', '1')
  }
  const onLeave = (e: React.PointerEvent<HTMLDivElement>) => e.currentTarget.style.setProperty('--on', '0')

  return (
    <div className={s.card} onPointerMove={onMove} onPointerLeave={onLeave}>
      <span className={s.badge}>★</span>
      <div>
        <p className={s.title}>{labels.title}</p>
        <p className={s.sub}>{labels.sub}</p>
      </div>
    </div>
  )
}
demo.module.css
.card {
  --x: 0.5;
  --y: 0.5;
  --on: 0;
  position: relative;
  display: grid;
  align-content: space-between;
  width: 136px;
  aspect-ratio: 5 / 7;
  padding: 14px;
  overflow: hidden;
  border: 1px solid var(--stage-rule);
  border-radius: 14px;
  background: linear-gradient(160deg, var(--stage-surface), var(--stage-bg));
  transform: perspective(600px) rotateY(calc((var(--x) - 0.5) * 12deg * var(--on)))
    rotateX(calc((0.5 - var(--y)) * 12deg * var(--on)));
  transition: transform 120ms linear;
}

.card::before,
.card::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  transition: opacity var(--dur-long) var(--ease-out);
}

.card::before {
  background: repeating-linear-gradient(
    115deg,
    oklch(80% 0.08 20),
    oklch(85% 0.08 90),
    oklch(82% 0.08 160),
    oklch(78% 0.08 250),
    oklch(80% 0.08 320),
    oklch(80% 0.08 20) 40%
  );
  background-size: 200% 200%;
  background-position: calc(var(--x) * 100%) calc(var(--y) * 100%);
  mix-blend-mode: color-dodge;
  opacity: calc(var(--on) * 0.3);
}

.card::after {
  background: radial-gradient(circle at calc(var(--x) * 100%) calc(var(--y) * 100%), var(--stage-sheen), transparent 45%);
  opacity: var(--on);
}

.badge {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--stage-accent);
  color: var(--stage-accent-ink);
  font-size: var(--text-sm);
}

.title {
  margin: 0;
  font: 600 var(--text-lg) / 1.2 var(--font-display);
  color: var(--stage-ink);
}

.sub {
  margin: 4px 0 0;
  font: 500 var(--text-xs) / 1 var(--font-mono);
  color: var(--stage-muted);
}

@media (prefers-reduced-motion: reduce) {
  .card { transform: none; }
}

投稿创意

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

你想投稿的是?

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