Skip to main content

[Day 15] Bicyclopter: 腳踏車還是直升機? 我要腳踏直升機!

事情是發生在Thibe高中的時候,當時放學時間緊迫,我急著回家打LOL,就在我加速騎著Ubike,頭上剛好飛過一台直升機,我心裡想:「要是能搭直升機就好了!」這時候,我腳下突然變成了腳踏直升機,飛也似地我就回到家了,快速地坐到電腦桌前打開電腦, 眼前突然一片光亮,夢醒了。そうか~這就是腳踏直升機的由來。

今天我們來實作Day #14

CodePen: https://codepen.io/stevetanus/pen/OJZjrjx


1. HTML

<div class="frame">
<div class="card">
<div class="flip">
<div class="front">
<img src="https://100dayscss.com/codepen/bycicle.svg">
<div class="street">
.stripe-$*9
</div>
</div>
<div class="back">
<img src="https://100dayscss.com/codepen/helicopter.svg">
<div class="sky">
.cloud-$*9
</div>
</div>
</div>
</div>
</div>

.frame中間有一張卡片.card.flip會加上翻轉的CSS屬性,裡面會有.front.back,前方卡片會顯示腳踏車,.stripe-$*9是九條道路線;後方卡片會顯示直升機,.cloud-$*9是九片雲彩。


2. SCSS(CSS)

.card

.card {
position: absolute;
width: 320px;
height: 180px;
top: 110px;
left: 40px;
perspective: 800px;

&:hover .flip {
transform: rotateX(180deg) translate3d(0, 0, 0);
box-shadow: 8px -10px 15px 0 rgba(0,0,0,.5);
}

.flip {
width: 100%;
height: 100%;
transform-style: preserve-3d;
transition: all 1s ease-in-out;
perspective: 1000px;
box-shadow: 8px 10px 15px 0 rgba(0,0,0,0.5);
}
}

perspective(透視)值代表我們與物體的距離,距離讓我們看到translate3d的效果,在內層要再加入transform-style: preserve-3d讓它以3d顯現,這時候hover.card就會看見中間的卡片隨著X軸旋轉180度來到後方,離開時就會返回前方,box-shadow的y值則是相對的,在旋轉前後都為相同的陰影。而.front.back也要做些處理。

.front, .back

.front, .back {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
...
backface-visibility: hidden;
text-align: center;
}
.back {
transform: rotateX(180deg); }

backface-visibility: hidden在3d旋轉的時候必須考慮進去,讓旋轉後的腳踏車、一開始的直升機背面隱藏起來。(我們要注意如果是在.flip加上背影隱藏就不會有背面的效果了,所以在.flip內要再創.front.back的class)

.street(街道往後的動畫)

.street{
position: absolute;
...
@for $i from 1 through 9 {
.stripe-#{$i} {
position: absolute;
right: -25px;
top: 0;
height: 3px;
width: (2+ $i *2)+px; //每條線的寬度會增加2px
background: #4B4841;
border-radius: 3px;
animation: street (0.8 + random(2) / 10) + s linear (random(10)/10)+ s infinite
// 動畫會在0.8s左右結束,每條線會有0~1s的延遲
}
}
}
// street動畫X軸會往左移-210px,縮小0.8倍
@keyframes street {
0% {
transform: translate3d(0, 0, 0) scaleX(1);
}
100% {
transform: translate3d(-210px,0,0) scaleX(.8);
}
}

.sky(天空雲朵往後動畫)

@for $i from 1 through 9 {
.cloud-#{$i} {
position: absolute;
right: -25px;
// 雲朵每朵會往下14px
top: (20 + $i * 14) + px;
height: 3px;
// 寬度隨機為10~25px
width: (10 + random(150)/ 10)+ px;
background: #4B4841;
border-radius: 3px;
animation: cloud (0.6 + random(2)/ 10) + s linear (random(10)/ 10) + s infinite;
}
}

cloud動畫和street動畫相同,這邊沒有附上,都是往後210px,縮小0.8倍。

bike跳躍動畫

@keyframes bike {
0%, 100% {
transform: scaleY(1);
}
50% {
transform: scaleY(1.05);
}
}

helicopter浮動動畫

@keyframes helicopter {
0%, 100% {
transform: translate3d(0,-5px,0);
}
50% {
transform: translate3d(0,5px,0);
}
}

可以看到腳踏車跟直升機動畫都是在0%、100%時相同位置,而50%時變大或是下降,配合道路和雲朵往後跑的動畫,形成前進的感覺。


打包帶走(take away)

HTML

目標屬性
翻面元素.card外層卡片、.flip內層旋轉元素、front前面、.back後面
CSS
目標屬性
背景顏色黑黃配黑色: background: #4B4841; 黃色: background: #FFCE4E;
翻面效果內外層:perspective,內層transform-style: preserve-3d,X軸翻面rotateX(180deg)
3d元素的背面隱藏backface-visibility: hidden

後記

OK ~ 第15天!挑戰經過一半了,上班忙、回家寫文章真的挺硬的,只是寫文章還可以廢話幾句,還好又要週五了,假日來調整一波XD