Pinterest 过渡
卡片充满屏幕并扩展的沉浸式过渡
Pinterest 过渡
Pinterest 过渡是画廊中的小项目扩展到全屏的扩展过渡(Expansion Transition)。用户选择的内容充满屏幕并放大,提供强大的沉浸感和视觉连续性。
演示
Loading demo...
UX 原则
何时使用?
Pinterest 过渡用于视觉内容的放大浏览。
内容关系适用性
콘텐츠 관계 | 적합성 | 설명 |
---|---|---|
无关内容 | ❌ | 没有扩展连接点时不适用 |
兄弟关系 | ⚠️ | 画廊内项目之间移动时可考虑 |
层级关系 | ✅ | 最适合缩略图→全视图等同一内容的放大视图 |
主要用例
- 图片画廊:从缩略图放大到高分辨率图片
- 产品目录:从产品网格扩展到详细信息
- 媒体浏览:从视频缩略图切换到播放器
- 作品集:从作品列表到全屏演示
为什么这样工作?
- 空间扩展隐喻:通过小窗口进入大世界的感觉
- 自然焦点移动:用户视线自然跟随扩展元素
- 上下文保留:明确来源,保持方向感
- 戏剧效果:扩展动画强调内容的重要性
动效设计
扩展过程:
1. 捕获选定卡片的位置和大小
2. 卡片移动到屏幕中心并放大
3. 同时背景淡化和缩放变化
4. 最终填充整个屏幕
收缩过程:
1. 详情屏幕缩小并返回原位
2. 背景重新出现,画廊恢复
3. 自然的弹簧动画定位
基本用法
1. 过渡设置
import { Ssgoi } from '@ssgoi/react';
import { pinterest } from '@ssgoi/react/view-transitions';
const config = {
transitions: [
{
from: '/gallery',
to: '/gallery/*',
transition: pinterest(),
symmetric: true
}
]
};
export default function App() {
return (
<Ssgoi config={config}>
{/* 应用内容 */}
</Ssgoi>
);
}
2. 元素标记
画廊和详情页面分别使用不同的 data 属性:
// 画廊页面
function Gallery() {
return (
<div className="masonry-grid">
{items.map(item => (
<Link
key={item.id}
to={`/gallery/${item.id}`}
data-pinterest-gallery-key={item.id}
className="gallery-item"
>
<img src={item.image} alt={item.title} />
<h3>{item.title}</h3>
</Link>
))}
</div>
);
}
// 详情页面
function ItemDetail({ item }) {
return (
<div
data-pinterest-detail-key={item.id}
className="detail-container"
>
<button onClick={() => navigate('/gallery')}>
✕ 关闭
</button>
<img src={item.image} alt={item.title} />
<article>
<h1>{item.title}</h1>
<p>{item.description}</p>
</article>
</div>
);
}
实践示例
1. 瀑布流画廊
Pinterest 风格瀑布流布局:
// 瀑布流网格
function MasonryGallery() {
return (
<div className="columns-2 md:columns-3 lg:columns-4 gap-4">
{images.map((img, index) => (
<div
key={img.id}
data-pinterest-gallery-key={img.id}
onClick={() => navigate(`/image/${img.id}`)}
className="break-inside-avoid mb-4 cursor-pointer
hover:scale-105 transition-transform"
>
<img
src={img.url}
alt={img.title}
className="w-full rounded-lg"
/>
<div className="p-2">
<p className="text-sm font-medium">{img.title}</p>
<p className="text-xs text-gray-500">{img.author}</p>
</div>
</div>
))}
</div>
);
}
// 扩展视图
function ImageView({ image }) {
return (
<div
data-pinterest-detail-key={image.id}
className="fixed inset-0 bg-white z-50 overflow-auto"
>
<div className="max-w-4xl mx-auto p-4">
<img
src={image.url}
alt={image.title}
className="w-full rounded-lg shadow-xl"
/>
<div className="mt-4">
<h1 className="text-2xl font-bold">{image.title}</h1>
<p className="text-gray-600 mt-2">{image.description}</p>
</div>
</div>
</div>
);
}
2. 产品目录
产品卡片扩展到详情页面:
// 产品网格
function ProductGrid() {
return (
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
{products.map(product => (
<article
key={product.id}
data-pinterest-gallery-key={product.id}
onClick={() => navigate(`/product/${product.id}`)}
className="bg-white rounded-xl shadow-lg overflow-hidden
cursor-pointer hover:shadow-xl transition-shadow"
>
<img
src={product.image}
alt={product.name}
className="w-full h-48 object-cover"
/>
<div className="p-4">
<h3 className="font-semibold">{product.name}</h3>
<p className="text-lg font-bold mt-2">${product.price}</p>
</div>
</article>
))}
</div>
);
}
// 产品详情
function ProductDetail({ product }) {
return (
<div
data-pinterest-detail-key={product.id}
className="min-h-screen bg-white"
>
<div className="grid md:grid-cols-2 gap-8 p-8">
<img
src={product.image}
alt={product.name}
className="w-full rounded-lg"
/>
<div>
<h1 className="text-3xl font-bold">{product.name}</h1>
<p className="text-2xl font-bold mt-4">${product.price}</p>
<p className="mt-4 text-gray-600">{product.description}</p>
<button className="mt-6 bg-black text-white px-8 py-3 rounded-lg">
加入购物车
</button>
</div>
</div>
</div>
);
}
自定义
弹簧设置
调整动画的弹性和速度:
pinterest({
spring: {
stiffness: 200, // 越低越平滑
damping: 25 // 越高越快稳定
}
})
注意事项
键属性区分
- 画廊:
data-pinterest-gallery-key
- 详情:
data-pinterest-detail-key
- 必须使用不同的属性名(与 Hero 区分)
布局考虑
- 画廊项目必须是 position: static
- 详情页面需要足够的边距
- 与瀑布流布局特别匹配
无障碍性
- 支持 ESC 键关闭详情页面
- 焦点陷阱改善键盘导航
- 减少动画设置时立即过渡
最佳实践
✅ 应该
- 用于以图片为中心的内容
- 应用于画廊或目录形式
- 清晰提供关闭按钮
- 在移动设备上也能良好工作的响应式设计
❌ 不应该
- 不适合以文本为中心的内容
- 避免太多元素同时扩展
- 详情页面加载缓慢时避免使用
- 复杂布局中可能出现意外行为