Tips-移動端滑動固頂效果(position: sticky)

先放個圖看看滑動固頂是啥效果:javascript

中間那個 tab 條,日常的時候是固定的,等到頁面滑上去的時候,又像 fixed 同樣貼在頂部。
position: sticky 就是用來實現這個效果的,元素不脫離文檔流,仍然保留高度,因此這個屬性真是人畜無害啊,並且效果如絲般潤滑,堪比原生。css

事實上,不少看起來人畜無害的東西,其背後都有一個大坑。html

咱們的 html 結構是這樣的:java

<body ontouchstart="">
    <div class="page-wrapper">
      <div id="contentA" class="content-a">
        A
      </div>
      <div class="sticky-wrap ">
        <ul class="ui-tab-nav ui-border-b frown ">
          <li class="current">推薦</li>
          <li>分類</li>
        </ul>
      </div>
      <div id="contentB" class="content-b">
        B
      </div>
    </div>
</body>複製代碼

主要的 css 以下:android

.sticky-wrap {
  top: 0;
  width: 100%;
  z-index: 999;
}
.sticky-wrap {
  position: relative;
  position: -webkit-sticky;
}
.page-wrapper.sticky .sticky-wrap {
  position: fixed;
}
.content-a {
  height: 200px;
  background-color: #12b7f5;
  color: #fff;
  font-size: 48px;
  text-align: center;
  line-height: 200px;
}
.content-b {
  height: 800px;
  font-size: 48px;
  text-align: center;
  line-height: 200px;
}複製代碼

這裏須要注意幾點,這裏 sticky-wrap 是咱們設置了position: -webkit-sticky;的元素,這個元素的位置比較重要,不是隨便放哪均可以實現那個效果的,sticky 效果是按照父元素的高度來的,若是你的父元素高度很小,會出現滑完父元素就再也不固頂的奇怪狀況。git

而後咱們設置了 top 值,sticky 的元素必須有 top 或者 bottom 屬性,否則不會生效。程序員

除了一些要設置的東西以外,還有一個不能設置的東西。 sticky 元素的父元素或者祖先元素不能含有 overflow:hidden 或者 overflow:autogithub

基本上小坑就這些,還有一個大坑叫作『只有 iOS 支持這個屬性』。web

Android 上實現相似效果

這裏咱們不得不借助 js 和 positon:fixed設計模式

添加一段 js:

var isStopTimer = null;
        var offsetTop = $('.content-a').offset().height;

        //置頂效果
        if ($('.sticky-wrap').css("position").indexOf("-webkit-sticky") == -1) {
            $('.page-wrapper').on('touchend', function() {
                clearInterval(isStopTimer);
                isStopTimer = setInterval(function() {
                    document.body.scrollTop >= offsetTop ? $('.page-wrapper').addClass('sticky') : $('.page-wrapper').removeClass('sticky');
                }, 200)

            });

            $('.page-wrapper').on('touchmove', function() {
                document.body.scrollTop >= offsetTop ? $('.page-wrapper').addClass('sticky') : $('.page-wrapper').removeClass('sticky');
            });
        }複製代碼

這裏經過計算 $('.sticky-wrap').css("position").indexOf("-webkit-sticky") 是否有效來判斷瀏覽器是否支持 sticky 屬性,而後經過監聽 touchmove 和 touchend 事件,在合適的時候添加一個叫 sticky 的類,這個類設置帶了些樣式:

.page-wrapper.sticky .sticky-wrap {
  position: fixed;
}複製代碼

在須要固頂的時候咱們將元素的 positon 改成 fixed,可是這裏又有個坑,設置元素爲 fixed 的時候,相應元素是脫離文檔流的,也就是沒有高度了,仔細看滑動的時候,底下的元素有一個跳動。

爲了解決這個跳動,咱們可讓本來在下面那個元素加點高度,而後和 sticky 元素重合,爲了之後改動頁面的時候不影響這個邏輯,用 js 去算高度會比較好。

加入以下代碼:

var tabContentTop = $('.ui-tab-nav').offset().height;
        var orgPaddingTop = parseInt($('.content-b').css('padding-top'));
        $('.content-b').css('padding-top', tabContentTop+orgPaddingTop);
        $('.sticky-wrap').css('margin-bottom', -tabContentTop);複製代碼

這裏用 padding-top 來給 content-b 增長高度,給 sticky-wrap 添加負的 margin-bottom 值來讓 content-b 上來和 sticky-wrap 重合。未免覆蓋原來 content-b 的 padding-top 值,最好獲取一下再加,記得用 parseInt 轉一下。

到這裏基本坑都踩完了,雖然 Android 效果沒有 iOS 那麼絲滑舒服,也勉強能接受了。

最後說下調試 sticky 效果,既然是 iOS 才支持的東西,首先你要有 safari,可是日常打開是沒用的,要在開發菜單那裏選擇 進入響應式設計模式

源碼地址:
github.com/bob-chen/de…

結語

很久沒發文章了,最近實在太忙,不知道是否是加班多了,還生病了,身體是革命的本錢啊,2017 祝你們身體健康。

碎碎念

記錄一些所思所想,寫寫科技與人文,寫寫生活狀態,寫寫讀書感悟,主要是扯淡和感悟,歡迎關注,交流。

微信公衆號:程序員的詩和遠方

公衆號ID : MonkeyCoder-Life

相關文章
相關標籤/搜索