[貝聊科技]粘性導航問題總結

@韓永豪 貝聊科技 移動開發部 前端 菜鳥工程師前端

什麼是粘性導航

本文討論的粘性導航是指,常規狀態下爲靜態定位,且因頁面滾動而超出屏幕顯示範圍時,仍然固定在屏幕某個地方的元素。效果以下:web

案例
案例

對應的HTML結構以下:瀏覽器

<header id="banner" class="header">banner</header>

<div class="wrap">
    <nav id="nav" class="nav">------ 粘性方塊 ------</nav>
</div>

<ul id="list" class="list">
    ......
</ul>複製代碼

實現粘性的方式

fixed定位

導航欄的常規狀態是靜態定位,所以,要實現粘性效果,就須要監測導航欄是否超出屏幕顯示範圍。利用JS添加滾動事件監聽,當導航欄開始滾出屏幕顯示範圍時設置CSS樣式「position: fixed」,讓它固定在頁面頂部,反之,恢復爲常規狀態。關鍵代碼以下:bash

.wrap {
    height: 1rem;
}
.nav {
    height: 1rem;
    line-height: 1rem;
    background: #67CAEF;
    text-align: center;
    color: white;
}
.nav.fixed {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    z-index: 999;
}複製代碼
var $nav = document.querySelector('#nav');
var $list = document.querySelector('#list');
var offsetTop = $nav.offsetTop; // 粘性方塊與頁面頂部的距離
window.addEventListener('scroll', function() {
    var scrollTop = this.scrollY || this.scrollTop;
    if (scrollTop > offsetTop) {
        $nav.classList.add('fixed');
    } else {
        $nav.classList.remove('fixed');
    }
});複製代碼

因爲fixed定位會使導航欄脫離文檔流,所以導航欄外面要包一層固定高度的元素(div.wrap),佔據導航欄的高度。dom

這種實現方案在PC和安卓平臺下均表現正常,而在iOS的UIWebView中卻出現了奇怪的現象:當頁面滾動時,粘性導航並無切換到fixed定位,而是保留static定位,直到滾動結束後,纔會切換到fixed定位。這是由於,在UIWebView中,滾動結束後纔會觸發滾動事件,而WKWebView就沒有這個問題。異步

sticky定位

sticky定位是一種比較新的定位方式。初始狀態下,此類定位元素的表現與「position: relative」類似,但不受定位(top、left等)影響。當頁面滾動至元素的「offsetTop - top」或「offsetLeft - left」時,元素就會切換成「position: fixed」的效果。可是「position: fixed」的效果是有範圍限制的,它只在sticky定位元素的父元素範圍內有效。ui

使用方法也很簡單,只須要設置CSS樣式「position: sticky」便可。關鍵代碼以下:this

.sticky {
    width: 100%;
    position: sticky;
    position: -webkit-sticky;
    top: 0;
    left: 0;
    z-index: 999;
}複製代碼

做爲一種比較新的定位方式,sticky定位在低版本的瀏覽器中沒法兼容,它的兼容狀況以下:
spa

sticky兼容性
sticky兼容性

由圖可見:code

  1. iOS須要6.1版本以上才能支持sticky定位。
  2. Android 4.x都不支持sticky定位。

那如何判斷瀏覽器是否支持sticky呢?很遺憾,目前沒有很完善的檢測方式,且Android下的瀏覽器比較多,因此只能粗略地認爲只有iOS ≥ 6.1才能支持sticky。而iOS的UIWebView中,sticky定位明顯比fixed定位效果更好。

動態加載數據

在粘性導航上新增兩個按鈕,點擊不一樣按鈕,異步加載不一樣的列表內容。效果圖以下:

案例
案例

關鍵代碼以下:

var $tabs = document.querySelector('#tabs');
var $list = document.querySelector('#list');
var $tabItem = $tabs.querySelectorAll('.item'); // 點擊加載列表的按鈕

// 動態加載列表
function loadList(type) {
    var template = '';
    var len = (Math.random() * 45) + 5; // 隨機生成 5 ~ 49 條數據
    for (var i = 0; i < len; i++) {
        template += '<li class="item">' +
            '<img src="../common/icon.png" alt="圖標" />' +
            '<div class="title">' + type + '(' + (i + 1) + ')</div>' +
            '<div class="text">這是一段內容</div>' +
        '</li>'
    }
    $list.innerHTML = template;
}

// 綁定標籤頁點擊事件
for (var i = 0; i < $tabItem.length; i++) {
    var item = $tabItem[i];
    (function(i) {
       item.onclick = function() {
            $list.innerHTML = '加載中...';
            // 模擬異步加載
            setTimeout(function() {
                loadList(i);
            }, 500);
        };
    })(i);
};

loadList(0); // 加載列表數據複製代碼

當標籤頁切換,異步更新列表數據時,因爲列表有短暫的時間是處於內容加載中的狀態,沒法維持原來的高度,因此會跳到頁面的頂部。

要解決這種很差的體驗,只須要在點擊加載數據的時候,設置列表的最小高度爲屏幕高度的一倍便可。關鍵代碼以下:

$list.style.minHeight = window.screen.height + 'px';複製代碼
相關文章
相關標籤/搜索