背景

Store 站点作为门店资源中心,承载着会议记录、营销素材等重要内容。为了提升用户体验,我决定为站点添加动效,让页面更加生动、交互更加自然。

本文记录了 Store 站点动效优化的完整过程,包括动效设计、实施过程、性能优化以及最终的共享组件化。

动效设计

设计原则

在设计动效时,我遵循以下原则:

  1. 零依赖:使用纯 CSS + 原生 JavaScript,不引入额外的动画库
  2. 性能优先:使用 GPU 加速(transform + opacity),避免重排重绘
  3. 移动端友好:支持触摸交互,提供触觉反馈
  4. 可访问性:尊重用户的 prefers-reduced-motion 设置

动效类型

我设计了以下几种动效:

  1. 渐入动画(Fade-in):页面加载时,元素依次渐入
  2. 涟漪效果(Ripple):点击时产生涟漪扩散效果
  3. 触摸反馈(Touch Feedback):移动端点击时轻微缩放

实施过程

阶段一:首页动效实现

首先,我为 Store 首页添加了动效。关键代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/* 渐入动画 */
.fade-in {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}

.fade-in.visible {
opacity: 1;
transform: translateY(0);
}

/* 涟漪效果 */
.ripple {
position: relative;
overflow: hidden;
}

.ripple::after {
content: '';
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: scale(0);
animation: ripple-animation 0.6s ease-out;
}

@keyframes ripple-animation {
to {
transform: scale(4);
opacity: 0;
}
}

阶段二:使用 Intersection Observer 触发动画

为了让渐入动画在元素进入视口时触发,我使用了 Intersection Observer API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Intersection Observer 配置
const observerOptions = {
root: null,
rootMargin: '0px',
threshold: 0.1
};

// 创建 Observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target);
}
});
}, observerOptions);

// 监听所有 .fade-in 元素
document.querySelectorAll('.fade-in').forEach(el => {
observer.observe(el);
});

阶段三:性能优化

为了确保动效的性能,我做了以下优化:

  1. GPU 加速:只使用 transformopacity 属性
  2. will-change:为即将动画的元素添加 will-change 提示
  3. 减少重绘:使用 translateZ(0) 创建合成层
1
2
3
4
.fade-in {
will-change: opacity, transform;
transform: translateZ(0);
}

共享组件化

问题

随着动效的实现,我发现了一个问题:如果后续新增页面,需要手动复制 CSS 和 JavaScript 代码,这会导致:

  • 代码重复
  • 维护困难
  • 更新不一致

解决方案

为了解决这个问题,我将动效代码提取到共享组件中:

  1. CSS 动画样式components/navbar.css
  2. Intersection Observercomponents/navbar.js

这样,所有引入 navbar.cssnavbar.js 的页面都会自动支持动效。

使用方式

新增页面时,只需为元素添加动画类:

1
2
3
<a href="xxx.html" class="module-card fade-in ripple touch-feedback">
<!-- 内容 -->
</a>

动效会自动触发,无需手动添加 JavaScript。

效果展示

渐入效果

页面加载时,badge → 标题 → 描述 → 模块卡片依次渐入,创造出优雅的加载体验。

涟漪效果

点击模块卡片时,产生涟漪扩散效果,提供即时的视觉反馈。

触摸反馈

在移动端,点击时元素会轻微缩放,增强触觉体验。

可访问性

我特别注意了可访问性,尊重用户的 prefers-reduced-motion 设置:

1
2
3
4
5
6
7
8
9
10
11
@media (prefers-reduced-motion: reduce) {
.fade-in {
opacity: 1;
transform: none;
transition: none;
}

.ripple::after {
animation: none;
}
}

这样,对于偏好减少动画的用户,动效会被禁用,确保所有用户都能获得良好的体验。

总结

通过这次动效优化,我学到了以下几点:

  1. 零依赖的动效:纯 CSS + 原生 JavaScript 足以实现优雅的动效
  2. 性能优先:使用 GPU 加速的属性,确保流畅的动画体验
  3. 共享组件化:将通用代码提取到共享组件,提高代码复用性
  4. 可访问性:尊重用户的偏好设置,确保所有用户都能获得良好体验

Store 站点的动效优化已完成,后续新增页面只需添加动画类即可自动应用动效,大大提高了开发效率。


相关文章