吸顶效果方案与实现

一、场景

需求:tab需要在划出视口的时候吸顶(sticky),方便点击切换下方内容。

二、方案

1、采用scroll监听+fixed定位。a) 监听页面被卷高度scrollTop,和 要sticky的元素距离页面的高度offsetTop,如果前者大于后者,设置fixed样式。b)通过getBoundingClientRect()监听要sticky元素的位置top 和0,stickyHeight和bottom进行比较,如果前者小于后者,设置fixed样式。

2、采用position:sticky定位。

三、position : sticky

粘性定位是相对定位和固定定位的混合。元素在跨越特定阈值例如,从视口顶部10像素)前为相对定位,之后为固定定位。

须指定top,right,bottom或left四个阈值其中之一,才可使粘性定位生效。否则其行为与相对定位相同。

四、方案实现

.fixed-top{

    position: fixed;

    left:0;

    top:0; //num

    z-index:10;

}

1-a、scroll + scrollTop + offsetTop + fixed

$(window).scroll(function(){

    var $stickyEl = $('.sticky');

    var scrollT = $(window).scrollTop();

    if (scrollT > (_stickyT-num)) { //num是吸顶时距离viewport顶部的距离

        $stickyEl.addClass('fixed-top');

    } else {

        $stickyEl.removeClass('fixed-top');

    }

});

1-b、scroll + getBoundingClientRect + fixed

$(window).scroll(function() {

    var $stickyEl = $('.sticky');

    var rect = $stickyEl.getBoundingClientRect();

    if(rect.top < 0 && (rect.bottom - stickyHeight) > 0) {

        !$stickyEl.hasClass('fixed-top') && $stickyEl.addClass('fixed-top').css('width', stickyWidth +'px');

    }else{

        $stickyEl.hasClass('fixed-top') && $stickyEl.removeClass('fixed-top').css('width','auto');

    }

});

或者

vardocClientWidth = document.documentElement.clientHeight;

rect.bottom > docClientWidth && (rect.top + stickyHeight) < docClientWidth;

2、sticky样式

.sticky-top{

    position: -webkit-sticky;

    position: sticky;

    top:0;

    left:0;

    z-index:10;

}

五、整体实现

思路:

1)通过sticky属性值是否可用的监测,如果可以,采用方案2,如果不可以,采用方案1-a;

2)在使用方案1-a时,滚动实时监听会带来频繁的调用回调函数,引来性能问题,在此采用函数截流的方式解决;

3)在接触到阀值临界是会有跳动,这是因为当sticky元素被固定的时候,它会脱离普通文档流,所以要利用它的父元素把sticky元素的高度在普通文档流中撑起来,以免在固定效果出现的时候,target元素的内容出现跳动的情况。

ps:(1)一般还是采用scroll,但是ios只有在滚动停止时才会调用回调函数;所以找到了sticky;但是sticky对低版本兼容度不够,但是对目前主流及高版本android和ios兼容度还ok,所以采用sticky优先的原则,判断是否支持sticky,来实现。

整体实现:

js:

//吸顶start

varfixTop={

    stickyEl :$('.sticky'),

    stickyT:function() {

        returnthis.stickyEl.offset().top;

    },

    num      :0,    

    // bannerImg: document.getElementById("bannerImg"),

    init:function(){

        // var u = navigator.userAgent;

        // var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;    

        // var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);

        var_num=this.num;

        varisSupportSticky=this.isSupportSticky();

        if(isSupportSticky) {

            this.sticky();

            return;

        }

        this.scroll(_num);

    },

    scroll:function(num){//滚动监听添加fixed样式

        var_this=this;

        var_stickyT=_this.stickyT();

        this.stickyHolder();

        $(window).scroll(this.throttle(function(){

        // var scrollT = document.body.scrollTop;

        varscrollT=$(window).scrollTop();

        // console.log(scrollT,_stickyT-num);

        if(scrollT>(_stickyT-num)) {

            _this.stickyEl.addClass('fixed-top');

        }else{

            _this.stickyEl.removeClass('fixed-top');

        }

    },10));

    },    

    sticky:function(){//添加sticky样式

        var_this=this;

        _this.stickyEl.addClass('sticky-top');

    },

       isSupportSticky:function(){//判断是否支持sticky

       varprefixTestList=['','-webkit-'];

        varstickyText='';

        for(vari=0;i

stickyText+='position:'+prefixTestList[i]+'sticky;';

}

// 创建一个dom来检查

vardiv=document.createElement('div');

div.style.cssText=stickyText;

document.body.appendChild(div);

varisSupport=/sticky/i.test(window.getComputedStyle(div).position);

document.body.removeChild(div);

div=null;

returnisSupport;

},

stickyHolder:function(){//守家占位符

varstickyHolder=document.createElement('div');

varstickyElDom=this.stickyEl.get(0);

varrect=stickyElDom.getBoundingClientRect();

// console.log(rect);

stickyElDom.parentNode.replaceChild(stickyHolder,stickyElDom);

stickyHolder.appendChild(stickyElDom);

stickyHolder.style.height=rect.height+'px';

},

throttle:function(func, wait){//函数截流

vartimer=null;

returnfunction() {

varself=this,

args=arguments;

if(timer)clearTimeout(timer);

timer=setTimeout(function() {

returntypeoffunc==='function'&&func.apply(self,args);

},wait);

}

}

}

fixTop.init();

//吸顶end

html:

    

    

    

css:

body{

margin:0;

}

div{

width:100%;

}

.banner{

/* overflow: hidden; */

height:500px;

background-color: yellowgreen;

}

.tab{

height:80px;

background-color: blue;

}

.content{

height:3000px;

}

.fixed-top{

position: fixed;

/*width: 100%;*/

left:0;

top:0;

z-index:10;

}

.sticky-top{

/* 滚过初始位置时自动吸顶 */

/*  */

position: -webkit-sticky;

position: sticky;

top:0;

left:0;

z-index:10;

}

你可能感兴趣的:(吸顶效果方案与实现)