Day26 不要躲在下面動! Animate On Scroll 自己做
我們都知道 CSS 動畫可以用 @keyframes
來做,但是他們都是馬上就觸發的。就算元素還沒有出現在畫面上,動畫也已經開始了。
如果要做出滾動到某個位置才觸發的動畫,就需要用到 JavaScript 來偵測滾動位置,然後再加上 CSS 動畫。沒錯,JavaScript 回來了。
原理
我們要做的是當元素出現在畫面上時,才觸發動畫。所以我們要偵測元素是否出現在畫面上。
我們可以用 getBoundingClientRect()
來取得元素相對於螢幕的位置,然後再用 window.innerHeight
來取得畫面的高度,就可以知道元素是否出現在畫面上了。
這裡是一個我做的範例。你可以看到當元素的上方超出畫面時top
就會變負值。當元素的下方超出畫面時bottom
的值會大於螢幕高度。那麼我們只需要有任何一部分有顯示在畫面上就可以觸發動畫了。
https://codepen.io/edit-mr/pen/ExGrxjX
為甚麼不要等整個元素顯示出來在觸發動畫?
因為如果元素很長,可能到半個畫面都空白之後他才出現會很奇怪。所以我們只要有任何一部分有顯示在畫面上就可以觸發動畫了,這樣滾動起來會比較順暢。
如果你想要的話可以自己改成等整個元素顯示出來再觸發動畫,或是設置一些延遲時間以及增加動畫長度。後者我比較推薦。
實作
先打點簡單的內容。我們幫需要動畫的內容加上 aos
這個 class。這樣我們只要偵測這些元素是否出現在畫面上。如果有的話就加上 ed
這個 class。這樣我們就可以用 CSS 來做動畫了。
叫做 ed 是因為英文過去式常常加上 ed,想說蠻直覺野蠻短的。如果你有更好的主意也可以改成其他名字。
1<h1 class="aos">Animate On Scroll</h1>
2<p class="aos">
3 Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad, mollitia magni nemo eius obcaecati aliquam ex nisi maiores. Autem hic illo quas amet ipsam. Eos tempore repellat sint illum tenetur!
4</p>
5<h2 class="aos">Scroll</h2>
6<div></div>
7<div class="aos"></div>
8<div class="aos"></div>
9<div class="aos"></div>
10<div class="aos"></div>
1body {
2 max-width: 600px;
3 margin: 0 auto;
4 font-size: 2em;
5}
6h2 {
7 font-size: 2em;
8}
9div {
10 height: 5em;
11 background: lightblue;
12 margin: 1em;
13}
好的動畫我先簡單做一個淡入的動畫。平常隱藏起來,當加上 ed
這個 class 時就顯示出來。
1.aos {
2 opacity: 0;
3 transition: opacity 1s;
4}
5
6.aos.ed {
7 opacity: 1;
8}
加上 JavaScript ,在頁面滾動時偵測每個有 .aos
的元素是否出現在畫面上。如果有的話就加上 ed
這個 class,沒有的話就回收。
1function isElementInViewport(el) {
2 const rect = el.getBoundingClientRect();
3 return rect.bottom < 0 || rect.top > window.innerHeight;
4}
5
6function addClassToVisibleElements() {
7 var aosElements = document.querySelectorAll(".aos");
8 aosElements.forEach(function (aosElement) {
9 if (!isElementInViewport(aosElement)) aosElement.classList.add("ed");
10 else aosElement.classList.remove("ed");
11 });
12}
13
14document.addEventListener("scroll", addClassToVisibleElements);
15addClassToVisibleElements();
ok 成功,我們來多做幾個更浮誇的動畫。
盡情發揮
我希望文字出來的時候可以有一點浮出水面的感覺。套用這個 class 的元素會先隱藏起來,當加上 ed
這個 class 時就會從下方滑出來。
1.slideIn {
2 transform: translateY(1em);
3}
4.slideIn.ed {
5 transform: translateY(0em);
6}
再來做一個從螢幕左邊滑近來的動畫。
1.slideInLeft {
2 transform: translateX(-100vw);
3}
4.slideInLeft.ed {
5 transform: translateX(0);
6}
最後來示範一個 @keyframes
的動畫,我們讓他放大縮小好了。因為它不需要漸入所以把原本的 opacity
拿掉了。蓋掉
1.zoom {
2 opacity: 1;
3}
4.zoom.ed {
5 animation: zoom 1.5s forwards linear;
6}
7@keyframes zoom {
8 0% {
9 scale: 1;
10 }
11 25% {
12 scale: 1.5;
13 }
14 50% {
15 scale: 1;
16 }
17 75% {
18 scale: 1.25;
19 }
20 100% {
21 scale: 1;
22 }
23}
好啦成果如下,你可以試著滾動一下頁面看看。今天這幾行程式碼就一次取代了 Animate.css、WOW.js、AOS、ScrollReveal 這些函式庫,而且還有更簡單更高的自訂性。
https://codepen.io/edit-mr/pen/rNoPBZe
1<h1 class="aos slideIn">Animate On Scroll</h1>
2<p class="aos slideIn">
3 Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad, mollitia magni nemo eius obcaecati aliquam ex nisi maiores. Autem hic illo quas amet ipsam. Eos tempore repellat sint illum tenetur!
4</p>
5<h2 class="aos slideIn">Scroll</h2>
6<div class="aos"></div>
7<div class="aos"></div>
8<div class="aos slideInLeft"></div>
9<div class="aos zoom"></div>
10<div class="aos slideIn"></div>
1body {
2 max-width: 600px;
3 margin: 0 auto;
4 font-size: 2em;
5}
6h2 {
7 font-size: 2em;
8}
9
10div {
11 height: 5em;
12 background: lightblue;
13 margin: 1em;
14}
15
16.aos {
17 opacity: 0;
18 transition: all 1s;
19}
20
21.aos.ed {
22 opacity: 1;
23}
24
25.slideIn {
26 transform: translateY(1em);
27}
28.slideIn.ed {
29 transform: translateY(0em);
30}
31
32.slideInLeft {
33 transform: translateX(-100vw);
34}
35.slideInLeft.ed {
36 transform: translateX(0);
37}
38
39.zoom {
40 opacity: 1;
41}
42.zoom.ed {
43 animation: zoom 1.5s forwards linear;
44}
45@keyframes zoom {
46 0% {
47 scale: 1;
48 }
49 25% {
50 scale: 1.5;
51 }
52 50% {
53 scale: 1;
54 }
55 75% {
56 scale: 1.25;
57 }
58 100% {
59 scale: 1;
60 }
61}
1function isElementInViewport(el) {
2 const rect = el.getBoundingClientRect();
3 return rect.bottom < 0 || rect.top > window.innerHeight;
4}
5
6function addClassToVisibleElements() {
7 var aosElements = document.querySelectorAll(".aos");
8 aosElements.forEach(function (aosElement) {
9 if (!isElementInViewport(aosElement)) aosElement.classList.add("ed");
10 else aosElement.classList.remove("ed");
11 });
12}
13
14document.addEventListener("scroll", addClassToVisibleElements);
15addClassToVisibleElements();
以上就是我今天的分享,歡迎在 Instagram 和 Google 新聞追蹤毛哥EM資訊密技,也歡迎訂閱我新開的YouTube頻道:網棧。
我是毛哥EM,讓我們明天再見。