Pinterest 过渡
Pinterest 风格的从画廊到详情视图的展开效果
Pinterest 过渡
Pinterest 过渡创建了画廊小项目展开到全屏的效果。它将 Pinterest 应用的标志性过渡效果带到了 Web 上,提供视觉上吸引人且直观的用户体验。
核心概念
Pinterest 过渡使用两个 key 属性:
data-pinterest-gallery-key
: 画廊页面的项目data-pinterest-detail-key
: 详情页面的容器
具有相同 key 值的元素会连接并创建展开/收缩动画。
画廊页面 详情页面
┌─────────────────┐ ┌─────────────────┐
│ ┌──┐ ┌──┐ ┌──┐ │ │ │
│ │▣ │ │ │ │ │ │ ═════════> │ ▣ │
│ └──┘ └──┘ └──┘ │ │ │
│ gallery-key="1" │ │ detail-key="1" │
└─────────────────┘ └─────────────────┘
基本用法
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. 画廊页面
export function Gallery() {
return (
<div className="masonry-grid">
{items.map(item => (
<Link
key={item.id}
href={`/gallery/${item.id}`}
data-pinterest-gallery-key={item.id}
className="gallery-item"
>
<img src={item.thumbnail} alt={item.title} />
<h3>{item.title}</h3>
</Link>
))}
</div>
);
}
3. 详情页面
export function GalleryDetail({ item }) {
return (
<div
data-pinterest-detail-key={item.id}
className="detail-container"
>
<img src={item.fullImage} alt={item.title} />
<h1>{item.title}</h1>
<p>{item.description}</p>
</div>
);
}
选项
pinterest({
spring: {
stiffness: 50, // 弹簧刚度(默认:50)
damping: 10 // 阻尼比(默认:10)
},
timeout: 300 // 页面匹配超时(默认:300ms)
})
工作原理
画廊 → 详情(进入模式)
- 计算画廊项目的位置和大小
- 使用 clip-path 从项目区域开始
- 展开到全屏同时进行 clip-path 动画
- 同时应用 scale 和 translate
开始:小卡片 中间:展开中 结束:全屏
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│┌──┐ │ │ ┌────────┐ │ │ │
││▣ │ │ => │ │ ▣ │ │ => │ ▣ │
│└──┘ │ │ └────────┘ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘
详情 → 画廊(退出模式)
- 从详情视图计算画廊项目位置
- 使用 clip-path 收缩到画廊项目大小
- 移动到原始位置同时淡出
高级示例
配合瀑布流布局
// 画廊页面
<div className="masonry-grid">
{items.map((item, index) => (
<div
key={item.id}
data-pinterest-gallery-key={item.id}
className="masonry-item"
style={{
gridRowEnd: `span ${item.height}`,
animationDelay: `${index * 50}ms`
}}
>
<Link href={`/gallery/${item.id}`}>
<img src={item.thumbnail} alt={item.title} />
</Link>
</div>
))}
</div>
图片预加载
// 详情页面 - 为平滑过渡预加载图片
export function GalleryDetail({ item }) {
useEffect(() => {
// 预加载高分辨率图片
const img = new Image();
img.src = item.fullImage;
}, [item.fullImage]);
return (
<div data-pinterest-detail-key={item.id}>
{/* 内容 */}
</div>
);
}
样式考虑
画廊项目
.gallery-item {
/* Pinterest 效果的基础样式 */
overflow: hidden;
border-radius: 8px;
cursor: pointer;
transition: box-shadow 0.2s;
}
.gallery-item:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
详情容器
.detail-container {
/* 全屏利用 */
min-height: 100vh;
width: 100%;
/* 内容对齐 */
display: flex;
flex-direction: column;
align-items: center;
}
重要说明
1. Key 规则
- 每页只使用一个
data-pinterest-detail-key
- 画廊 key 和详情 key 必须完全匹配
- 数字和字符串都可以作为 key
2. 布局要求
- 画廊项目需要明确的边界
- 详情页面使用全屏布局效果最佳
- 需要考虑响应式设计
3. 性能优化
- 将图片优化到适当大小
- 分别使用缩略图和完整图片
- 建议应用懒加载
推荐使用场景
- 📷 图片画廊
- 🛍️ 电商产品列表
- 📌 Pinterest 风格布局
- 🎨 作品集画廊
- 📰 卡片式内容列表
Hero vs Pinterest
| 特性 | Hero 过渡 | Pinterest 过渡 | |------|-----------|----------------| | 用途 | 单个元素移动 | 全屏展开 | | 动画 | 位置和大小变换 | Clip-path 展开 | | 复杂度 | 可多个元素 | 单一容器 | | 效果 | 元素连接性 | 沉浸式展开 |