介绍
在用户体验设计中, microinteractions是帮助用户导航界面的小反馈时刻。
在本教程中,您将构建一个功能性下载按钮与微互动. 要使它工作,我们将使用CSS过渡和动画,以及轻量级动画库 anime.js和 segment.js为SVG path
动画。
在教程结束时,我们会得到这样的下载按钮:
该下载按钮的原始设计属于Pedro Aquino,并可以在 这个Dribbble拍摄找到完整的代码,可以在 这个Github存储,和 这里是演示页面。
第1步:创建HTML结构
让我们来看看我们将使用的HTML代码:
1<!-- Button container -->
2<div class="download-button-container">
3 <!-- The real button -->
4 <button class="download-button">
5 <span class="button-text-real hidden">download</span>
6 <!-- Extra elements to perform the animations -->
7 <span class="button-icon">
8 <span class="button-linear-progress">
9 <span class="button-linear-progress-bar"></span>
10 </span>
11 <svg class="button-icon-svg" viewBox="0 0 60 60">
12 <path class="button-icon-path button-icon-path-square" d="M 20 40 l 0 -20 l 20 0 l 0 20 Z"></path>
13 <path class="button-icon-path button-icon-path-line" d="M 40 20 l -20 20"></path>
14 </svg>
15 </span>
16 </button>
17 <!-- Extra elements to perform the animations -->
18 <svg class="border-svg" width="240px" height="100px" viewBox="0 0 240 100">
19 <path class="border-path hidden" d="M 40 3.5 a 36.5 36.5 0 0 0 -36.5 36.5 a 36.5 36.5 0 0 0 36.5 36.5 C 70 76.5 90 76.5 120 76.5 S 170 76.5 200 76.5 a 36.5 36.5 0 0 0 36.5 -36.5 a 36.5 36.5 0 0 0 -36.5 -36.5 Z"></path>
20 </svg>
21 <span class="button-text button-text-download">download</span>
22 <span class="button-text button-text-done">done!</span>
23 <div class="button-wave"></div>
24 <div class="button-progress-container">
25 <svg class="button-svg">
26 <path class="button-circular-progress" d="M 50 50 m 0 -32.5 a 32.5 32.5 0 0 1 0 65 a 32.5 32.5 0 0 1 0 -65"></path>
27 </svg>
28 <span class="button-ball"></span>
29 </div>
30</div>
例如,在某个时刻,我们希望按钮边缘执行弹性动画,所以我们需要一个 SVG):
第2步:添加风格
请注意,我们在这里不包括整个风格表,而是最重要的部分;您可以在 Github 存储库找到整个代码。
让我们看看我们定义的 SCSS 变量,以及隐藏元素的辅助类:
1// Some variables to use later
2$button-width: 300px;
3$button-height: 70px;
4$button-border: 3px;
5$icon-padding: 5px;
6$icon-width: $button-height - ($icon-padding * 2);
7$ball-width: 18px;
8
9// Helper class to hide elements
10.hidden {
11 visibility: hidden !important;
12 opacity: 0 !important;
13}
实际按钮
元素的风格:
1// Real button styles
2.download-button {
3 position: relative;
4 display: inline-block;
5 width: $button-width;
6 height: $button-height;
7 background-color: #2C2E2F;
8 border: none;
9 box-shadow: 0 0 0 $button-border #02D1FF; // This will be our 'border'
10 border-radius: 100px;
11 cursor: pointer;
12 transition: 1s width, 0.3s box-shadow;
13
14 // Remove the custom behavior in some browsers
15 &, &:focus {
16 padding: 0;
17 outline: none;
18 }
19 &::-moz-focus-inner {
20 border: 0;
21 }
22
23 // Styles for the different states of the button
24 &:hover, &:active, &:focus {
25 box-shadow: 0 0 0 $button-border #02D1FF, 0 0 20px $button-border darken(#02D1FF, 20%);
26 }
27}
我们的按钮可以处于三个不同的状态:下载
,进展
和完成
,因此我们使用以下结构定义了每个状态所需的样式:
1// Button container
2.download-button-container {
3 // ...CODE...
4
5 // Following are the different states for the button: downloading, progressing and completed
6 // We have defined the states in the container to have access to all descendants in CSS
7
8 // Downloading: The download button has been pressed
9 &.downloading {
10 // ...CODE...
11 }
12
13 // Progressing: The progress starts
14 &.progressing {
15 // ...CODE...
16 }
17
18 // Completed: The progress ends
19 &.completed {
20 // ...CODE...
21 }
22}
另一个有趣的代码被用来完成下载后实现球动画:
1.button-ball {
2 left: 50%;
3 transition: none;
4 // CSS animations for the ball. All of them start at the same time, so we need to take care of delays
5 animation:
6 ball-throw-up 0.5s ease-out forwards, // Throw up the ball for 0.5s
7 ball-throw-down 0.5s 0.5s ease-in forwards, // Wait 0.5 seconds (throw up), and throw down the ball for 0.5s
8 ball-rubber 1s forwards; // Move the ball like a rubber deformation during 1s (throw up + throw down)
9}
10
11// Throw up animation
12@keyframes ball-throw-up {
13 from {
14 transform: translate(-50%, 17.5px);
15 }
16 to {
17 transform: translate(-50%, -60px);
18 background-color: #00FF8D;
19 }
20}
21
22// Throw down animation
23@keyframes ball-throw-down {
24 from {
25 transform: translate(-50%, -60px);
26 }
27 to {
28 transform: translate(-50%, 80px);
29 }
30}
31
32// Rubber animation
33@keyframes ball-rubber {
34 from {
35 width: $ball-width;
36 }
37 25% {
38 width: $ball-width * 0.75;
39 }
40 50% {
41 width: $ball-width;
42 }
43 to {
44 width: $ball-width / 2;
45 }
46}
所有其他使用的风格都可以在 Github 存储库找到。
第3步:使用JavaScript动画
我们将使用 anime.js和 segment.js,这两个轻量级的库来帮助动画。
请注意,我们不会在以下代码片段中包含某些变量声明,为了澄清。如果您有任何疑问,请检查 Github 存储库。
以下是我们使用的基本代码来捕捉按钮
上的点击事件,并执行我们想要的行为:
1// Capture click events
2button.addEventListener('click', function () {
3 if (!completed) { // Don't do anything if downloading has been completed
4 if (downloading) { // If it's downloading, stop the download
5 stopDownload();
6 } else { // Start the download
7 startDownload();
8 }
9 }
10});
11
12// Start the download
13function startDownload() {
14 // Update variables and CSS classes
15 downloading = true;
16 buttonContainer.classList.add('downloading');
17 animateIcon();
18 // Update progress after 1s
19 progressTimer = setTimeout(function () {
20 buttonContainer.classList.add('progressing');
21 animateProgress();
22 }, 1000);
23}
24
25// Stop the download
26function stopDownload() {
27 // Update variables and CSS classes
28 downloading = false;
29 clearTimeout(progressTimer);
30 buttonContainer.classList.remove('downloading');
31 buttonContainer.classList.remove('progressing');
32 // Stop progress and draw icons back to initial state
33 stopProgress();
34 iconLine.draw(0, '100%', 1, {easing: anime.easings['easeOutCubic']});
35 iconSquare.draw('30%', '70%', 1, {easing: anime.easings['easeOutQuad']});
36}
动画进度在演示中被伪造了;对于真实的使用案例,它将被真实的进度数据取代。
1// Progress animation
2function animateProgress() {
3 // Fake progress animation from 0 to 100%
4 // This should be replaced with real progress data (real progress percent instead '100%'), and maybe called multiple times
5 circularProgressBar.draw(0, '100%', 2.5, {easing: anime.easings['easeInQuart'], update: updateProgress, callback: completedAnimation});
6}
最后,这里是用来执行动画的代码,当下载完成时,球动画被触发,我们改变了路径
元素。
1// Animation performed when download has been completed
2function completedAnimation() {
3 // Update variables and CSS classes
4 completed = true;
5 buttonContainer.classList.add('completed');
6 // Wait 1s for the ball animation
7 setTimeout(function () {
8 button.classList.add('button-hidden');
9 ball.classList.add('hidden');
10 borderPath.classList.remove('hidden');
11 // Morphing the path to the second shape
12 var morph = anime({
13 targets: borderPath,
14 d: 'M 40 3.5 a 36.5 36.5 0 0 0 -36.5 36.5 a 36.5 36.5 0 0 0 10.5 26.5 C 35 86.5 90 91.5 120 91.5 S 205 86.5 226 66.5 a 36.5 36.5 0 0 0 10.5 -26.5 a 36.5 36.5 0 0 0 -36.5 -36.5 Z',
15 duration: 100,
16 easing: 'linear',
17 complete: function () {
18 // Morphing the path back to the original shape with elasticity
19 morph = anime({
20 targets: borderPath,
21 d: 'M 40 3.5 a 36.5 36.5 0 0 0 -36.5 36.5 a 36.5 36.5 0 0 0 36.5 36.5 C 70 76.5 90 76.5 120 76.5 S 170 76.5 200 76.5 a 36.5 36.5 0 0 0 36.5 -36.5 a 36.5 36.5 0 0 0 -36.5 -36.5 Z',
22 duration: 1000,
23 elasticity: 600,
24 complete: function () {
25 // Update variables and CSS classes, and return the button to the original state
26 completed = false;
27 setTimeout(function () {
28 buttonContainer.classList.remove('completed');
29 button.classList.remove('button-hidden');
30 ball.classList.remove('hidden');
31 borderPath.classList.add('hidden');
32 stopDownload();
33 }, 500);
34 }
35 });
36 }
37 });
38 }, 1000);
39}
结论
本文展示了用于构建此下载按钮的主要代码:
您可以 玩与现场 DEMO,或 得到完整的代码在Github. 请注意,这个组件还没有完全准备好生产,因为它需要真实的进度数据和一些考虑后端将如何影响微互动。