先放個圖看看滑動固頂是啥效果:
中間那個 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,但是平常開啟是沒用的,要在開發選單那裡選擇 進入響應式設計模式
原始碼地址:
github.com/bob-chen/de…
結語
好久沒發文章了,最近實在太忙,不知道是不是加班多了,還生病了,身體是革命的本錢啊,2017 祝大家身體健康。
碎碎念
記錄一些所思所想,寫寫科技與人文,寫寫生活狀態,寫寫讀書感悟,主要是扯淡和感悟,歡迎關注,交流。
微信公眾號:程式設計師的詩和遠方
公眾號ID : MonkeyCoder-Life