在每天的實作中,都會遇到不熟、不知道如何使用語法完成的難題,可以點擊CSS 100作者本身的CodePen參考(參考下圖紅色箭頭),像是背景色、動畫效果之類的,然後在自己挑戰時做出自己的變化。
今天我們挑戰Day #2,此Menu Icon 是很常見於網頁的選單,這個漢堡包點擊之後會變成叉叉,再點擊叉叉就會收合回漢堡包,接下來讓我們來一探玄機吧!
CodePen: https://codepen.io/stevetanus/pen/qBYZgxr
<div class="frame">
<div class="center">
<div class="menu-icon">
<div class="line1 no-animation"></div>
<div class="line2 no-animation"></div>
<div class="line3 no-animation"></div>
</div>
</div>
</div>
.menu-icon
包住三條線.line1
, .line2
, .line3
,三條線都有個no-animation的class。
由於我們一開始不知道三條線要怎樣的長度,且之後有可能會再修改來看效果,所以我們先定義變數,方便之後程式進行修改。
$menu-icon-line-height: 12px;
$menu-icon-line-space: 20px;
$menu-icon-line-offsetY: $menu-icon-line-height + $menu-icon-line-space;
$menu-icon-height: (3 * $menu-icon-line-height) + (2 * $menu-icon-line-space);
$cubic-bezier-in: cubic-bezier(0.3, 1, 0.7, 1);
$menu-icon-line-offsetY
是線的高度加上線之間的空白高度,方便我們在animation
語法中進行消除。
關於SASS變數可以參考以下文章 ~
Cubic Bezier 由四個點所組成(P0, P1, P2, P3),P0和P1為一控制點,P2和P3為一控制點,在起始點到終點之間會受到控制點的影響,形成不同的貝茲曲線,呈現出特別的動畫速度效果。cubic-bezier(0.3, 1, 0.7, 1)
為前快後慢的動畫效果。
.menu-icon {
cursor: pointer;
&:hover {
.line1,
.line2,
.line3 {
background: darken(#fff, 10%);
}
cursor: pointer
(cur)讓我們滑鼠經過其元素時變成食指。我們也會發現背景顏色變暗了10%。
&.active {
.line1,
.line2,
.line3 {
background: darken(#fff, 20%);
}
.line1 {
animation: animate-line1 0.7s $cubic-bezier-in forwards;
}
.line2 {
animation: animate-line2 0.7s $cubic-bezier-in forwards;
}
.line3 {
animation: animate-line3 0.7s $cubic-bezier-in forwards;
}
}
後面會使用JavaScript讓.menu-icon增加active屬性,在.active之中,三條線都有自己的animation。
@keyframes animate-line1 {
0% {
transform: translate3d(0, 0, 0) rotate(0deg);
}
50% {
transform: translate3d(0, $menu-icon-line-offsetY, 0) rotate(0deg);
}
100% {
transform: translate3d(0, $menu-icon-line-offsetY, 0) rotate(45deg);
}
}
@keyframes
用來定義動畫的規則,在animate-line1
中,動畫進行0%(初始狀態)與原本相同,50%時y軸往下移動了整條線加上線間空白的高度,100%時高度與之前(50%)相同,但正向旋轉45度。animation
則是動畫屬性的縮寫,animation: animate-line1 0.7s $cubic-bezier-in forwards;
是指在.active的line1會啟動animate-line1
的動畫,在0.7秒內以變數$cubic-bezier-in的速度執行,最後停在元素停在動畫結束的位置。
@keyframes animate-line2 {
0% {
transform: scale(1);
opacity: 1;
}
100% {
transform: scale(0);
opacity: 0;
}
}
@keyframes animate-line3 {
0% {
transform: translate3d(0, 0, 0) rotate(0deg);
}
50% {
transform: translate3d(0, -$menu-icon-line-offsetY, 0) rotate(0deg);
}
90% {
transform: translate3d(0, -$menu-icon-line-offsetY, 0) rotate(145deg);
}
100% {
transform: translate3d(0, -$menu-icon-line-offsetY, 0) rotate(135deg);
}
在.active的line2,加入animate-line2
的動畫,達到縮小不見的效果。
在.active的line3,加入animate-line3
的動畫,達到上升再正向旋轉145度與往回10度的效果。
@keyframes animate-line1-rev{...}
@keyframes animate-line2-rev{...}
@keyframes animate-line3-rev{...}
定義反向動畫效果在三條線上,然後我們需要防止第一次loading進入的動畫效果,這時候.no-animation就派上用場:
.no-animation {
animation: none !important;
}
!important
可以蓋過所有選擇器的語法,讓動畫效果消除(然而 !important 語法請盡量減少使用)。
const menuIcon = document.querySelector('.menu-icon')
const lines = document.querySelectorAll('.no-animation');
menuIcon.addEventListener('click',()=>{
lines.forEach((line)=>{
line.classList.remove('no-animation')
})
menuIcon.classList.toggle('active')
})
定義menuIcon為class="menu-icon"
的元素。
定義lines為所有class="no-animation"
的元素。
在menuIcon安裝監聽器,點擊時,每個在lines裡面的元素(.line1, .line2, .line3)的class會移除"no-animation"
,menuIcon的class如果沒有"active"
會加上"active"
;反之,則會移除。如此一來,在點擊menuIcon時,就會產生常見的漢堡包選單啦!
中秋連假的第二天,好多人都在烤肉呢!!! 我雖然沒有吃到烤肉,但製作個漢堡包也是蠻不錯的吧