[贝聊科技]粘性导航问题总结

@韩永豪 贝聊科技 移动开发部 前端 菜鸟工程师

什么是粘性导航

本文讨论的粘性导航是指,常规状态下为静态定位,且因页面滚动而超出屏幕显示范围时,仍然固定在屏幕某个地方的元素。效果如下:

案例

对应的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」,让它固定在页面顶部,反之,恢复为常规状态。关键代码如下:

.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),占据导航栏的高度。

这种实现方案在PC和安卓平台下均表现正常,而在iOS的UIWebView中却出现了奇怪的现象:当页面滚动时,粘性导航并没有切换到fixed定位,而是保留static定位,直到滚动结束后,才会切换到fixed定位。这是因为,在UIWebView中,滚动结束后才会触发滚动事件,而WKWebView就没有这个问题。

sticky定位

sticky定位是一种比较新的定位方式。初始状态下,此类定位元素的表现与「position: relative」相似,但不受定位(top、left等)影响。当页面滚动至元素的「offsetTop - top」或「offsetLeft - left」时,元素就会切换成「position: fixed」的效果。但是「position: fixed」的效果是有范围限制的,它只在sticky定位元素的父元素范围内有效。

使用方法也很简单,只需要设置CSS样式「position: sticky」即可。关键代码如下:

.sticky {
    width: 100%;
    position: sticky;
    position: -webkit-sticky;
    top: 0;
    left: 0;
    z-index: 999;
}复制代码

作为一种比较新的定位方式,sticky定位在低版本的浏览器中无法兼容,它的兼容情况如下:

sticky兼容性

由图可见:

  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';复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值