PD11▸📊 Data Display · 資料展示▸輪播
Apple Carousel
Apple 風格輪播
難度 ★★★★★標籤 apple · snap · 中央放大3 min read
模式簡述
Apple Carousel:中央項目放大、兩側縮小淡出。apple.com 產品頁、App Store 都這麼用。視覺很有 brand 感。
Claude Code Prompt
參考:PD11 apple-carousel 組件:AppleCarousel.tsx Apple Carousel:中央項目放大、兩側縮小淡出。apple.com 產品頁、App Store 都這麼用。視覺很有 brand 感。 限制: - scale 太誇張 - 沒做 snap - 忘了 transition
完整程式碼
"use client";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";
type State = "first" | "middle" | "dragging";
const ITEMS = [
{ title: "iPhone 17 Pro", subtitle: "鈦金屬", color: "from-zinc-700 to-zinc-900" },
{ title: "MacBook Air", subtitle: "M5 晶片", color: "from-slate-300 to-slate-500" },
{ title: "Vision Pro", subtitle: "空間運算", color: "from-purple-700 to-indigo-900" },
{ title: "iPad", subtitle: "Liquid Retina", color: "from-sky-400 to-blue-600" },
{ title: "Apple Watch", subtitle: "Series 12", color: "from-red-500 to-rose-700" },
];
export function AppleCarousel({ state = "first" }: { state?: State }) {
const idx = state === "middle" ? 2 : state === "dragging" ? 1 : 0;
const [active, setActive] = useState(idx);
useEffect(() => setActive(idx), [idx]);
const dragOffset = state === "dragging" ? -40 : 0;
return (
<div className="w-full max-w-2xl">
<div className="relative overflow-hidden rounded-xl">
<div
className="flex items-center gap-4 px-[calc(50%-7rem)] py-6 transition-transform duration-500 ease-out"
style={{ transform: `translateX(calc(-${active * 240}px + ${dragOffset}px))` }}
>
{ITEMS.map((it, i) => {
const d = Math.abs(i - active);
const scale = d === 0 ? 1 : d === 1 ? 0.85 : 0.7;
const opacity = d === 0 ? 1 : d === 1 ? 0.7 : 0.4;
return (
<button
key={i}
onClick={() => setActive(i)}
style={{ transform: `scale(${scale})`, opacity }}
className={cn(
"relative h-56 w-56 shrink-0 overflow-hidden rounded-2xl transition-all duration-500 ease-out",
`bg-gradient-to-br ${it.color}`,
d === 0 && "shadow-2xl",
)}
>
<div className="absolute inset-x-0 bottom-0 p-4 text-left text-white">
<p className="text-[11px] uppercase tracking-wider opacity-70">{it.subtitle}</p>
<p className="mt-0.5 text-base font-medium">{it.title}</p>
</div>
</button>
);
})}
</div>
</div>
<div className="mt-3 flex justify-center gap-1.5">
{ITEMS.map((_, i) => (
<button
key={i}
onClick={() => setActive(i)}
className={cn(
"h-1 rounded-full transition-all",
i === active ? "w-6 bg-lab-accent" : "w-1 bg-muted-foreground/40",
)}
/>
))}
</div>
</div>
);
}何時用
- ✅ 產品展示頁
- ✅ 電商高質感商品輪播
- ✅ 想營造 Apple 風格的 portfolio
何時別用
- ❌ 後台、工具型介面(太炫)
- ❌ 資訊型內容(中央放大但旁邊看不清)
- ❌ 極簡 brand(會破壞調性)
我踩過的坑
-
scale 太誇張:中央 1.5x 兩側 0.7x 太跳。建議 1.0 / 0.85 / 0.7。
-
沒做 snap:手指放開後不對齊任何一項。scroll-snap-type: x mandatory。
-
忘了 transition:scale/opacity 切換要 transition-all 500ms ease-out。
相關模式
- PD09
- PD12