iT邦幫忙

2024 iThome 鐵人賽

DAY 3
0
Modern Web

Dive into CSS Challenge:從問題到解決方案的實踐之旅系列 第 3

Day 3 - CSS Challenge #2:MenuIcon動畫的實現與解題分析

  • 分享至 

  • xImage
  •  

題目

CSS Challenge Day2
https://ithelp.ithome.com.tw/upload/images/20240917/20169403B5e0gtTa3r.png

上面的圖是題目,而我們要做出幾乎一樣的樣子,題目中還有附上出題官方的CodePen,也有附上給我們解題用的template,當我們真的不會的時候,還是可以參考他們的寫法,所以沒有想像中困難。

我做好的此題CSS Challeage解答

那麼我們就開始吧。

題目分析

題目要求我們使用 CSS 做出類似上方的菜單圖示動畫,並在點擊後,三條水平線會旋轉、縮放,形成交叉的圖示。

  1. 置中顯示一個漢堡圖示,由三條線條組成。
  2. 點擊圖示後,三條線條分別旋轉和縮放形成交叉。
  3. 動畫需要平滑過渡,並考慮線條之間的間距和對齊問題

注意要點

  1. 線條之間的間距必須均勻。
  2. 動畫的過渡效果要流暢,避免突兀。
  3. 確保整體圖示能在不同尺寸下居中對齊。

開始解題

MenuIcon圖示結構設計

<div class="frame">
  <div class="center">
    <div class="menuIcon">
      <div class="line line1 noAnimate"></div>
      <div class="line line2 noAnimate"></div>
      <div class="line line3 noAnimate"></div>
    </div>
  </div>
</div>

我先將三條線條由三個 div 元素構成,統一命名為 .line。並在外面使用 .menuIcon 包起來,加入了 cursor: pointer ,確保滑鼠指上 Icon 圖示範圍時,都會顯示「手指」的滑鼠圖案。

點擊後使用JS在 .menuIcon 上加上一個 .active 的 class,它會觸發動畫。


Icon樣式設計

MenuIcon 中的三個線條,我使用同一個 class 來管理他們三個的樣式,確保看起來是一樣的,並根據不同的需求給予特定的動畫效果。
並且在這裡我使用了變數來定義線條的高度、間距和位移,這樣當需要調整時,只需修改變數即可,方便管理。

$menuIcon_heignt: 8px;
$menuIcon_spaceY: $menuIcon_heignt * 2;
$resetMenuIconOriginSpace: $menuIcon_spaceY + $menuIcon_heignt;

.menuIcon {
  width: 80px;
  cursor: pointer;
}

.line {
  width: 80px;
  height: $menuIcon_heignt;
  border-radius: 3px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
  background: white;
}

.line2 {
  margin: $menuIcon_spaceY 0;
}

動畫設計

1. 未點擊Icon之前

一開始的 HTML 中就加上了 noAnimate 的樣式,所以一開始是沒有動畫的。
我使用 .active 來控制是否播放動畫,並在切換成 .active 時,使用JS移除 noAnimate 的樣式。

// 沒有 active 時的返回動畫 & 沒有動畫時畫面
.line1 {
	animation: animate-line-1-back ease-in-out .7s forwards}
.line2 {
	margin:$menuIcon_spaceY 0;
	animation: animate-line-2-back ease-in-out .7s forwards
}
.line3 {animation: animate-line-3-back ease-in-out .7s forwards}

.noAnimate {
	-webkit-animation: none !important;
          animation: none !important; 
}

2. 點擊Icon後

// active 後的動畫
&.active {
	.line1 {animation: animate-line-1 .7s forwards}
	.line2 {animation: animate-line-2 .7s forwards}
	.line3 {animation: animate-line-3 .7s forwards}
}

當用戶點擊時, .active 被加入在 .menuIcon 上,所以 .active 區塊的 CSS 被套用,動畫開始播放,這邊我使用了 forwards 讓動畫只會播放一次。

第一條線先使用了 translate(x,y) 的特性達成向下移動到 .menuIcon 的中間跟第二條線重疊,並做 rotate(45) 旋轉 45 度。
第二條線則使用 transform: scale(0) 做到縮小並搭配 opacity: 0 在視覺上消失。
第三條線一樣使用了 translate(x,y) 的特性向上移動到跟第二條線重疊,再旋轉 135 度並向上移動。
如此以來,第一條線跟第三條線就完美的話出一個 X 的圖案。

這邊 translate 的位移距離,我使用了變數計算,由於要將第一條線跟第三條線都移動到跟第二條線同樣位置,可以算出位移的距離必須是「一條線的高度,加上他們之間的間距」,等到他們三條線重疊後才開始旋轉。

@keyframes animate-line-1 {
  0% { transform: translate(0, 0) rotate(0); }
  50% { transform: translate(0, $resetMenuIconOriginSpace) rotate(0); }
  100% { transform: translate(0, $resetMenuIconOriginSpace) rotate(45deg); }
}

@keyframes animate-line-2 {
  0% { transform: scale(1); opacity: 1; }
  100% { transform: scale(0); opacity: 0; }
}

@keyframes animate-line-3 {
  0% { transform: translate(0, 0) rotate(0); }
  50% { transform: translate(0, -$resetMenuIconOriginSpace) rotate(0); }
  100% { transform: translate(0, -$resetMenuIconOriginSpace) rotate(135deg); }
}

技巧總結

這一題看起來考驗的是你能否熟練的操作動畫,關鍵點包括:

  1. 變數的應用:用變數統一管理線條高度、間距及動畫移動距離,減少了代碼重複,方便調整。
  2. 動畫設計:使用 @keyframes 定義每條線條的動畫過程,讓線條依次旋轉、位移、縮放,形成菜單開關效果。

Wrap up and go home

那今天就先到這裡,明天我們再繼續來玩下一題。


上一篇
Day 2 - CSS Challenge #1:數字 100 與文字佈局
下一篇
Day 4 - CSS Challenge #3:金字塔的日出日落
系列文
Dive into CSS Challenge:從問題到解決方案的實踐之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言