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

Bob-Chen發表於2017-01-30

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

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

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

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

我們的 html 結構是這樣的:

<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 如下:

.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 效果是按照父元素的高度來的,如果你的父元素高度很小,會出現滑完父元素就不再固頂的奇怪情況。

然後我們設定了 top 值,sticky 的元素必須有 top 或者 bottom 屬性,不然不會生效。

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

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

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,但是平常開啟是沒用的,要在開發選單那裡選擇 進入響應式設計模式

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

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

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

結語

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

碎碎念

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

微信公眾號:程式設計師的詩和遠方

公眾號ID : MonkeyCoder-Life

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

相關文章