#不用庫 也能酷 - 玩轉 CSS & Js 特效 #HTML #CSS #JavaScript

Day26 不要躲在下面動!Animate On Scroll 自己做

Date
2023.10.10
Category
網頁開發
Read Time
14 min
Word
4.3k
Last Mod
2023.10.10
課程 2023.10.10

Day26 不要躲在下面動!Animate On Scroll 自己做

我們都知道 CSS 動畫可以用 @keyframes 來做,但是他們都是馬上就觸發的。就算元素還沒有出現在畫面上,動畫也已經開始了。

如果要做出滾動到某個位置才觸發的動畫,就需要用到 JavaScript 來偵測滾動位置,然後再加上 CSS 動畫。沒錯,JavaScript 回來了。

原理

我們要做的是當元素出現在畫面上時,才觸發動畫。所以我們要偵測元素是否出現在畫面上。

我們可以用 getBoundingClientRect() 來取得元素相對於螢幕的位置,然後再用 window.innerHeight 來取得畫面的高度,就可以知道元素是否出現在畫面上了。

這裡是一個我做的範例。你可以看到當元素的上方超出畫面時top就會變負值。當元素的下方超出畫面時bottom的值會大於螢幕高度。那麼我們只需要有任何一部分有顯示在畫面上就可以觸發動畫了。

https://codepen.io/elvismao/pen/ExGrxjX

getBoundingClientRect()
getBoundingClientRect()

為甚麼不要等整個元素顯示出來在觸發動畫?
因為如果元素很長,可能到半個畫面都空白之後他才出現會很奇怪。所以我們只要有任何一部分有顯示在畫面上就可以觸發動畫了,這樣滾動起來會比較順暢。
如果你想要的話可以自己改成等整個元素顯示出來再觸發動畫,或是設定一些延遲時間以及增加動畫長度。後者我比較推薦。

實作

先打點簡單的內容。我們幫需要動畫的內容加上 aos 這個 class。這樣我們只要偵測這些元素是否出現在畫面上。如果有的話就加上 ed 這個 class。這樣我們就可以用 CSS 來做動畫了。

叫做 ed 是因為英文過去式常常加上 ed,想說蠻直覺野蠻短的。如果你有更好的主意也可以改成其他名字。

簡單的版面
簡單的版面
HTML
<h1 class="aos">Animate On Scroll</h1><p class="aos">	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!</p><h2 class="aos">Scroll</h2><div></div><div class="aos"></div><div class="aos"></div><div class="aos"></div><div class="aos"></div>
CSS
body {	max-width: 600px;	margin: 0 auto;	font-size: 2em;}h2 {	font-size: 2em;}div {	height: 5em;	background: lightblue;	margin: 1em;}

好的動畫我先簡單做一個淡入的動畫。平常隱藏起來,當加上 ed 這個 class 時就顯示出來。

CSS
.aos {	opacity: 0;	transition: opacity 1s;}.aos.ed {	opacity: 1;}

加上 JavaScript,在頁面滾動時偵測每個有 .aos 的元素是否出現在畫面上。如果有的話就加上 ed 這個 class,沒有的話就回收。

JS
function isElementInViewport(el) {	const rect = el.getBoundingClientRect();	return rect.bottom < 0 || rect.top > window.innerHeight;}function addClassToVisibleElements() {	var aosElements = document.querySelectorAll(".aos");	aosElements.forEach(function (aosElement) {		if (!isElementInViewport(aosElement)) aosElement.classList.add("ed");		else aosElement.classList.remove("ed");	});}document.addEventListener("scroll", addClassToVisibleElements);addClassToVisibleElements();
淡入動畫
淡入動畫

ok 成功,我們來多做幾個更浮誇的動畫。

盡情發揮

我希望文字出來的時候可以有一點浮出水面的感覺。套用這個 class 的元素會先隱藏起來,當加上 ed 這個 class 時就會從下方滑出來。

CSS
.slideIn {	transform: translateY(1em);}.slideIn.ed {	transform: translateY(0em);}

再來做一個從螢幕左邊滑近來的動畫。

CSS
.slideInLeft {	transform: translateX(-100vw);}.slideInLeft.ed {	transform: translateX(0);}

最後來示範一個 @keyframes 的動畫,我們讓他放大縮小好了。因為它不需要漸入所以把原本的 opacity 拿掉了。蓋掉

CSS
.zoom {	opacity: 1;}.zoom.ed {	animation: zoom 1.5s forwards linear;}@keyframes zoom {	0% {		scale: 1;	}	25% {		scale: 1.5;	}	50% {		scale: 1;	}	75% {		scale: 1.25;	}	100% {		scale: 1;	}}

好啦成果如下,你可以試著滾動一下頁面看看。今天這幾行程式碼就一次取代了 Animate.cssWOW.jsAOSScrollReveal 這些函式庫,而且還有更簡單更高的自訂性。

https://codepen.io/elvismao/pen/rNoPBZe

所有效果
所有效果
HTML
<h1 class="aos slideIn">Animate On Scroll</h1><p class="aos slideIn">	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!</p><h2 class="aos slideIn">Scroll</h2><div class="aos"></div><div class="aos"></div><div class="aos slideInLeft"></div><div class="aos zoom"></div><div class="aos slideIn"></div>
CSS
body {	max-width: 600px;	margin: 0 auto;	font-size: 2em;}h2 {	font-size: 2em;}div {	height: 5em;	background: lightblue;	margin: 1em;}.aos {	opacity: 0;	transition: all 1s;}.aos.ed {	opacity: 1;}.slideIn {	transform: translateY(1em);}.slideIn.ed {	transform: translateY(0em);}.slideInLeft {	transform: translateX(-100vw);}.slideInLeft.ed {	transform: translateX(0);}.zoom {	opacity: 1;}.zoom.ed {	animation: zoom 1.5s forwards linear;}@keyframes zoom {	0% {		scale: 1;	}	25% {		scale: 1.5;	}	50% {		scale: 1;	}	75% {		scale: 1.25;	}	100% {		scale: 1;	}}
JS
function isElementInViewport(el) {	const rect = el.getBoundingClientRect();	return rect.bottom < 0 || rect.top > window.innerHeight;}function addClassToVisibleElements() {	var aosElements = document.querySelectorAll(".aos");	aosElements.forEach(function (aosElement) {		if (!isElementInViewport(aosElement)) aosElement.classList.add("ed");		else aosElement.classList.remove("ed");	});}document.addEventListener("scroll", addClassToVisibleElements);addClassToVisibleElements();

以上就是我今天的分享,歡迎在 InstagramGoogle 新聞追蹤毛哥EM資訊密技,也歡迎訂閱我新開的YouTube 頻道:網棧

我是毛哥EM,讓我們明天再見。

About me

毛哥EM

這裡是毛哥EM,一隻全端開發龍還有英文辯士。
熱愛開源、音樂、設計、獸迷文化,專研人機互動與人工智慧。

本部落格皆屬原創文章,採 CC BY-SA 4.0 授權,
轉載請註明來自毛哥EM資訊密技。
這篇文章對你有幫助嗎? 考慮幫我買瓶 Red Bull?

毛哥EM 角色插圖

Comments

留言區