在製作個人網頁時,通常會有一個contactme(與我聯絡)的表格,這時候,我們就可以想想看怎麼美化我們的送信動畫~
今天我們來實作Day #20
CodePen: https://codepen.io/stevetanus/pen/jOxYaBN
<div class="frame">
<input type="checkbox" id="cb">
<label for="cb" class="button">Send mail</label>
<label for="cb" class="button reset">Reset</label>
<div class="circle"></div>
<div class="circle-outer"></div>
<svg class="icon mail">
<!-- 信封四方形 -->
<polyline points="119,1 119,69 1,69 1,1"></polyline>
<!-- 開關三角形 -->
<polyline points="119,1 60,45 1,1 119,1"></polyline>
</svg>
<svg class="icon plane">
<!-- 飛翼三角形 -->
<polyline points="119,1 1,59 106,80 119,1"></polyline>
<!-- 飛機中間線和基座 -->
<polyline points="119,1 40,67 43,105 69,73"></polyline>
</svg>
</div>
input:checkbox
放在最前面,有兩個label
指向這個checkbox,中間有.circle
圓形背景和.circle-outer
圓形邊框線,兩個svg.mail
跟.plane
,分別為信封和飛機,飛機的SVG較難理解,我下面透過註解與截圖呈現:
飛翼三角形
飛機中間線和基座
#cb {
display: none; //讓checkbox消失,用label去做切換
}
.circle {
position: absolute;
width: 200px;
height: 200px;
top: 65px;
left: 100px;
background: #354A5F;
border-radius: 50%;
}
.circle-outer {
@extend .circle;
box-sizing: border-box;
background: none;
border: 4px solid #354A5F;
}
.circle-outer
為.circle
外圍的框線,兩者在後面的動畫會有差異。
.icon {
position: absolute;
z-index: 2;
top: 130px;
left: 140px;
fill: none; // 去除預設的黑色
stroke-width: 2px;
stroke: #ecf0f1;
stroke-linecap: square; // 方角,且會比butt再延長些路徑的長度。
stroke-dasharray: 325;
&.mail {
width: 120px;
height: 70px;
stroke-dashoffset: 0;
}
&.plane {
width: 120px;
height: 110px;
stroke-dashoffset: 325;
}
}
stroke-dashyarray: 325
使得.mail
充滿實線,而.plane
的stroke-dashoffset: 325
將實線推移了325單元,讓飛機一開始是空白透明的。關於要如何取得SVG線段長度,可以參考這篇文章的末段svg-line-animation-works,使用getTotalLength()
,但其方法對於SVG內有兩個以上重疊線段不管用,這時候可能就要用推估的,從錯中修正。
CSS stroke-linecap: https://css-tricks.com/almanac/properties/s/stroke-linecap/
.button {
...
z-index: 10;
...
border-radius: 20px;
font-weight: 600;
text-transform: uppercase;
font-size: 15px;
cursor: pointer;
&.reset {
opacity: 0;
z-index: 5;
}
&:hover {
background: #1abc9c;
color: #fff;
}
}
.reset
重設按鈕的z-index為5,小於前面的按鈕(10),並設定為透明的。
#cb:checked ~ .button {
animation: button 1.5s ease-in-out 1.7s; // 延遲1.7s出發,飛機駛離動畫為2.4s結束
animation-fill-mode: both;
}
#cb:checked ~ .reset {
animation: reset 1s ease-in-out 3.7s;
animation-fill-mode: both;
}
@keyframes button {
0% {
transform: scale(1);
}
30% {
background: #1abc9c; // 變為深綠色背景
color: transparent; // 文字透明
width: 200px;
left: 100px;
}
50%,60% {
// 縮小成圓球,原本height為40px
width: 40px;
left: 180px;
transform: scale(1);
}
70% {
transform: scale(1.1); // 放大離開
}
100% {
width: 40px;
left: 180px;
background: #1abc9c;
color: transparent;
transform: scale(0);
}
}
@keyframes reset {
// 由暗轉明
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#cb:checked ~ .circle {
animation: circle 1s ease-in-out;
animation-fill-mode: both;
}
#cb:checked ~ .circle-outer {
animation: circle .8s ease-in-out .2s;
animation-fill-mode: both;
}
@keyframes circle {
0% {
transform: scale(1);
}
20% {
transform: scale(1.1);
}
100% {
transform: scale(0);
}
}
.circle-outer
的動畫晚.2s出發,產生較晚但同時收縮完畢的感覺(1s)。
#cb:checked ~ .mail {
stroke-dashoffset: 326; // 所有白線被推移消失
transition: stroke-dashoffset 1s ease-in-out;
}
#cb:checked ~ .plane {
stroke-dashoffset: 0; // 所有白線出現
transition: stroke-dashoffset 1s ease-in-out .6s; // 0.6s動畫開始,剛好是接著信封的動畫,產生連貫的效果。
animation: fly 2.4s ease-in-out;
animation-fill-mode: both;
}
@keyframes fly {
0%, 50% {
scale: 1;
}
60% {
scale: 1.05;
translate: -20px 10px; //向左下稍微移動飛出
}
70% {
opacity: 1;
}
85% {
opacity: 0;
}
100% {
translate: 300px -150px; //往右上飛出消失
scale: 0.4;
opacity: 0;
}
}
HTML
目標 | 屬性 |
---|---|
寄信元素: 信封、紙飛機 | 參考上面程式碼.mail ,.plane |
CSS | |
目標 | 屬性 |
------------- | ------------- |
方角邊框 | stroke-linecap: square ,且會比butt 再延長些路徑的長度。 |
文字透明 | color: transparent |
取得SVG的path長度 | path.getTotalLength() ,但重疊的線段不適用 |
今天早上很早就起床了,所以有先寫一些,還是沒能在早上就發文~儲備文章是真D難...