粘性布局


受豎向滾動條滑動影響,當滾動條滑動到設置的位置時;再次往下滾動期望html中某個元素可以像粘在屏幕上一樣,位置不隨滾動條的滑動而變動。

效果如下:

實現過程有一些特別要注意的事項,我沒有直接貼最終代碼,而是一步步來做,記錄錯誤過程和現象:

首先准備好多個元素,這里准備了大概36個div,里面內容都是“這是一行文字”,需要粘性布局的div內容就是“粘性布局的文字”,然后一些基本的css

<style>
    *{margin:0;padding:0;}div{margin:20px;height: 20px;line-height: 30px;}
</style>

<div>這是一行文字</div>
<div>這是一行文字</div>
<div>這是一行文字</div>
<div>這是一行文字</div>
<div>這是一行文字</div>
<div>這是一行文字</div>
<div>這是一行文字</div>
<div>這是一行文字</div>
<div>這是一行文字</div>
<p id="target" style="top: 40px;background-color: blueviolet;color: #fff;width: 120px;">粘性布局的文字</p>
</div>
<div>這是一行文字</div>
<div>這是一行文字</div>
<div>這是一行文字</div>
···
···
···

 

其次,假設粘性布局的元素定位的top為40px,即元素變為粘性元素的時候距離可視區域的頂部距離為40px;

然后添加js代碼,監聽滾動條滾動事件;當粘性元素距離可視區域頂部距離為40px時,設置粘性元素position:fixed;否則position置為空;

window.onload = function () {
    let target = document.querySelector('#target')
    window.addEventListener('scroll', handleScroll, false)
    function handleScroll() {
        let top = target.getBoundingClientRect().top //獲取元素可視區域頂部的距離
        console.log(top);
        if (top < 40 || top == 40) {
            sticky()
        } else {
            reset()
        }
    }
    function sticky() {
        target.style.position = 'fixed'
    }
    function reset() {
        target.style.position = ''
    }
}

此時效果是有點問題的,如下,控制台打印的數字是粘性元素距離可視區域頂部的距離,即 target.getBoundingClientRect().top:

問題一,會看到當鼠標往下滑動時會一閃一閃的,控制台打印的數字往下滑動會一直是60和一個負數;負數是正常的 target.getBoundingClientRect().top,而60則是position是fixed之后的top值,這是60而不是40是因為粘性元素設置了margin:20px;

一閃一閃的原因是:

1、當滾動條往下滑動,粘性元素的top小於40時,會執行sticky方法,然后position為fixed,top是60

2、再往下滑動,此時top是60,那么又會去執行reset方法;此時position為空,粘性元素回到了最初的狀態,此時的top就是負數了

3、然后再往下滑動,檢測到top小於40,那么就會執行sticky方法;然后繼續滑動就會重復上述步驟了;

問題二,當然這里把margin:20去掉就不會出現一閃一閃了,但是會出現新的問題,(這里去掉margin並不是最終解決一閃一閃的方法,因為后面分析中設置了margin:20px也是不會出現一閃一閃的情況;)

1、當滑動到小於40后,此時粘性元素的position為fixed,top設置成了40px

2、滾動條繼續向下滑動,或者元素的top值,target.getBoundingClientRect().top,因為之前top被設置成了40px,所以這里獲取的top就會一直是40px

 

解決辦法

粘性元素布局的時候需要用一個占位元素將粘性元素包裹起來

··
··
<div>這是一行文字</div>
<div>這是一行文字</div>
<div id="targetBox">
    <div id="target" style="top: 40px;background-color: blueviolet;color: #fff;width: 120px;">粘性布局的文字</div>
</div>
<div>這是一行文字</div>
<div>這是一行文字</div>
··
··

當target的position  fixed和空互相切換時,占位元素依然在那里,而且這里判斷粘性元素的top值時,需要判斷的是targetBox的top值,而不是target的top,這也就解決了問題一的一閃一閃和問題二;

window.onload = function () {
    let active = false //是否已經是粘性布局了
    let target = document.querySelector('#target')
    let targetBox = document.querySelector('#targetBox')
    window.addEventListener('scroll', handleScroll, false)
    function handleScroll() {
        let top = targetBox.getBoundingClientRect().top //獲取元素可視區域頂部的距離
        console.log(top);
        if (top < 40 || top == 40) {
            sticky()
        } else {
            reset()
        }
    }
    function sticky() {
        if (active) { return } //已經是粘性布局了,則不再往下執行
        target.style.position = 'fixed'
        active = true
    }
    function reset() {
        if (!active) { return }
        target.style.position = ''
        active = false
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM