iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0
自我挑戰組

在30天利用HTML & CSS & JavaScript完成Side Project實作系列 第 6

Day 6 Side Project : Scroll Animation 滾動動畫

  • 分享至 

  • xImage
  •  


今天要來做的是滾動動畫,利用滑鼠滾輪來控制BOX從左右兩邊交叉的出現,倒回去也一樣可以XD! 那我們就直接開始吧/images/emoticon/emoticon30.gif


運用知識點羅列

  • CSS
知識點 使用說明
flexbox 佈局排版
box-shadow 製作BOX的陰影效果
translateX( ) 製作BOX的水平方向位移
transition 控制BOX出現的動畫速度和效果
:nth-of-type() 用來選擇"偶數號"的BOX
  • JS
知識點 使用說明
window.innerHeight 取得視窗內的網頁內容高度
Element.getBoundingClientRect() 取得BOX距離視窗的位子
forEach() 迭代每個BOX,並判斷BOX是否要顯示在畫面

流程講解

  • HTML
  <h1>Scroll to see the animation</h1>
    <div class="box"><h2>放入你想寫的標題</h2></div>
    <div class="box"><h2>放入你想寫的標題</h2></div>
    <div class="box"><h2>放入你想寫的標題</h2></div>
    <div class="box"><h2>放入你想寫的標題</h2></div>
    <!-- 後面都一樣,所以省略 -->
  • CSS
    大局排版
* {
  box-sizing: border-box;
}

body {
  background-color: #efedd6;
  margin: 0;
  padding: 0;
  display: flex; /*讓內容水平垂直置中*/
  flex-direction: column;
  justify-content: center;
  align-items: center;
  overflow-x: hidden;
}

Day 3 progress steps進度條,我們有寫了一個CSS公版,這個公版在往後的賽project中可以作為一個初始模板,不過在這要稍微客製一下,加入flex-direction: column;讓排版轉為直向,不用設height,因為我們要透過滑鼠滾輪去製造效果,如果設定高度就沒意義了

主要內容

h1 {
  margin: 10px;
}
.box {
  background-color: rgb(158, 158, 242);
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 250px;
  height: 150px;
  margin: 10px;
  border-radius: 10px;
  /* offset-x | offset-y | blur-radius | color */
  box-shadow: 2px 4px 5px rgba(0, 0, 0, 0.3);
  transform: translateX(400%);  /*向右移動400%,若不寫預設為0*/
  transition: transform 0.4s ease;
}

.box:nth-of-type(even) {  /*even:偶數*/
  transform: translateX(-400%);
}

.box.show {
  transform: translateX(0);
}

↑ 這一段有幾個重點,第一個是使用了::nth-of-type(even)去找出偶數號的盒子
在最一開始的完成圖中,我們看到盒子是"左右交叉"的出現,但其實只要控制一邊的出現,就可以了做到這個效果了

第二個需要注意的就是,transform: translateX(位移距離)裡的位移距離,在預設情況下,BOX是在 transform: translateX(400%);的位子,因為我們設置overflow-x: hidden;,所以超過瀏覽器的範圍會被隱藏起來,不過要留意如果位移的單位是設%,它所參考的對象並非父元素,而是參考設置transform的那個元素

再來,我們為偶數號的BOX設了 transform: translateX(-400%);,所以所有偶數號的BOX們都會向左移動-400%,不過也因為設置了overflow-x: hidden;,所以也看不到它出現在畫面中

至於.box.show,眼尖的你可能會注意到我們在html中並沒有寫入這個class,疑?? 不過依照前幾篇的操作不是這樣阿! 這裡就是在為後面javaScript埋伏筆呀嘿嘿,因為我們要透過show這個類別去控制BOX的出現,它在預設情況下並沒有要"show",所以就不必寫在html中了


  • JS
    初始位子都用CSS處理的差不多了,再來就是此賽Project的重頭戲了
let boxes = document.querySelectorAll(".box");

window.addEventListener("scroll", checkBoxes);
checkBoxes();

function checkBoxes() {
  console.log(window.innerHeight);
  let triggerBottom = window.innerHeight * 0.8;
  boxes.forEach((box) => {
    let boxTop = box.getBoundingClientRect().top;
    if (boxTop < triggerBottom) {
      box.classList.add("show");
    } else {
      box.classList.remove("show");
    }
  });
}

JS可以拆成兩部分來講解,這時候真希望你有雙螢幕,看程式碼就不用一直滾動那麼辛苦XD

首先,要設置一個checkbox函式,我們要用它來檢查每個BOX的位子,那既然我們需要檢查每個BOX的位子,就必須想辦法知道每個BOX的觸發點(trigger point)在哪,以及當滑鼠滾輪向下,BOX進入畫面時,我們要做甚麼?(好繞口令XD)

那我針對有使用到的方法做簡單的介紹:

Window.innerHeight

擷取MDN上的一段話

The Window interface represents a window containing a DOM document . Read-only innerHeight property of the Window interface returns the interior height of the window in pixels, including the height of the horizontal scroll bar, if present.

意思大致上是說,window是一個包含了DOM document的物件,其中innerHeight這個屬性,它是唯讀(Read-only)的,我們可以透過它取得視窗內的網頁內容高度,如果有水平卷軸也會包含進去。

console.log(window.innerHeight);
從印出來的結果你會發現,當滾動滾輪時它會印出一個正整數,它是固定的數字(如下圖),不過我們為了要做出滑鼠滾輪的效果,它不能是固定的數字,因為在任何時候高度都有可能不同
https://ithelp.ithome.com.tw/upload/images/20220912/20149362TXvh3PwSiw.png

let triggerBottom = window.innerHeight * 0.8;
triggerBottom代表觸發器的底部,值為 window.innerHeight 的 80%,你可以試試看不要乘任何數 or 乘更大 or 乘更小去測試看看,比較彼此的差別


Element.getBoundingClientRect()

一樣擷取MDN上的一段話

The Element.getBoundingClientRect() method returns a DOMRect object providing information about the size of an element and its position relative to the viewport.

意思大致上是說 getBoundingClientRect()可以用來知道一個元素的大小位子,會回傳DOMRect,DOMRect其實就是一個矩形,它提供了這個矩形的大小和位子等相關資訊,可以看底下這張圖比較好理解,left, top, right, bottom, x, y...這些都是它提供的資訊,是可以取用的屬性

https://ithelp.ithome.com.tw/upload/images/20220912/20149362Tp8o8oDTNC.png
本圖擷取自MDN

box.getBoundingClientRect().top; 是我們想知道BOX距離視窗的高度在哪,它有沒有小於triggerBottom 這個變數,如果小於的話,我們要新增(add()) "show"這個類別,否則就移除(remove())

那今天的解說都到這邊,關於計算視窗的高度會比較難理解,自己也是透過實作的過程一邊去消化吸收,不懂的就console.log()印出來看看到底那是甚麼東西,如果有任何問題可以底下留言,我會盡我所能回答你XD

附上codepen連結 https://codepen.io/hangineer/pen/qBYNyYY?editors=1100
所學不精,若有解說不夠詳盡或是錯誤歡迎指教,感激不盡!那明天見囉/images/emoticon/emoticon29.gif

summary 總結

[補充]

  1. Window.innerWidth
  2. Window物件及其的介紹

參考資料

50 Projects In 50 Days - HTML, CSS & JavaScript
網頁座標 - 了解 screen、page、client 差異


上一篇
Day 5 Side Project : Blurry Loading 模糊加載
下一篇
Day 7 Side Project: Split Landing Page 分離一頁式頁面
系列文
在30天利用HTML & CSS & JavaScript完成Side Project實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
小哈片刻
iT邦研究生 5 級 ‧ 2022-09-12 23:22:49

很棒的範例!

hannnahTW iT邦新手 3 級 ‧ 2022-09-13 16:33:18 檢舉

謝謝^^

我要留言

立即登入留言