成品連結:Sticky Nav、操作前程式碼 - HTML、操作前程式碼 - CSS、操作後程式碼 - HTML、操作後程式碼 - CSS
今天要做的是類似 CSS 中的 position: fixed 的功能,只不過需滾動至特定的位置才會開始生效。看到這裡或許你會說那就用 position: sticky 就好啦!沒錯,的確可行,但我們還是嘗試使用 JS 實作吧!
scroll)事件首先設定滾動監聽事件
function stickyNav() {
// code here
}
window.addEventListener('scroll', stickyNav);
接著要來設定效果生效的位置。我們要先知道當滾動至哪個距離時會開始生效,這裡有兩個辦法,
header 的高度(offsetHeight)nav 與網頁頂部的距離(offsetTop)今天我們會使用的是第二種方法(第一種方法請自行嘗試)。
先取得 nav 與網頁頂部的距離
const nav = document.querySelector('#main');
const topOfNav = nav.offsetTop;
function stickyNav() {
// code here
}
接著使用 if...else... 來判斷當滾動距離大於或等於 nav.topOfNav 時生效
const nav = document.querySelector('#main');
const topOfNav = nav.offsetTop;
function stickyNav() {
if (window.scrollY >= topOfNav) {
// code here
} else {
// code here
}
}
這裡要注意必須在 function 外面宣告及賦值給 topOfNav 而不能直接在 if...else... 中比較(if (window.scrollY >= nav.offsetTop){..});因為如果直接在 if... 中比較,nav.offsetTop 會隨著滾動越來越小,即便你向上滾動也不會變大(根本原因是設定在監聽事件內,nav.offsetTop 會持續變動,終至 0),所以要將該變數宣告在 function 外面
我們要讓 Navbar 固定的方法就是使用 position: fixed(請暫時忘記 position: sticky 的存在)
/* CSS */
.fixed-nav nav {
position: fixed;
box-shadow: 0 5px rgba(0,0,0,0.1);
}
並加到 JS 中
這裡會把 .fixed-nav 這個 class 加到 body 而不是 nav 是因為如果是加到 nav,那晚點要操作其他元素時會很不方便(需要向上一層 -> 接著再找要設定的元素),綁在 body 並透果選擇器選到要設定樣式的元素會較恰當
function stickyNav() {
if (window.scrollY >= topOfNav) {
document.body.classList.add('fixed-nav');
} else {
document.body.classList.remove('fixed-nav');
}
}
有效果出來了,但怎麼感覺當滾動到該位置時下方的文字區塊會向上跑動?你沒看錯,這是因為當 nav 變成 position: fixed 時它浮起來了,換另一種方式講就是 nav 變得不佔據 HTML 的空間,也因此下方的元素就跑上去了。
所以我們要把 nav 的高度加回去在 body 的 padding-top,這裡提醒一下千萬不要在 CSS 寫死值,要是之後 nav 高度改變會變得很難修改。應該說當一個元素的值可能變動時都不要寫死值,而是要用變數的方式使之更有彈性。
function stickyNav() {
if (window.scrollY >= topOfNav) {
document.body.classList.add('fixed-nav');
document.body.style.paddingTop = `${nav.offsetHeight}px`;
} else {
document.body.classList.remove('fixed-nav');
document.body.style.paddingTop = `0px`;
}
}
其實到這裡功能差不多做完了,但如果 HTML 看得仔細的話會看到 nav ul 當中第一項的 li 是沒有在畫面上的,這是因為 CSS 設定 max-width: 0 所以看不到,而我要把它加回去。
/* CSS */
.fixed-nav .logo {
max-width: 500px;
}
透過更改 max-width 屬性,現在當滾動至一定位置,logo 出現了!
最後當滾動至一定位置時,啟用效果使下方文字有放大效果。
從 CSS 可以看到 .site-wrap 有一個屬性是 transform: scale(0.98) ,而我們要將它稍微放大
/* CSS */
.fixed-nav .site-wrap {
transform: scale(1);
}
這樣就完成啦!
這裡順便留個小任務給各位,如果使用 position: sticky 要如何做出相同效果呢?請練習看看~
如果有不清楚的地方歡迎留言詢問喔!