吸頂效果方案與實現

一、場景

需求: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,bottomleft四個閾值其中之一,才可使粘性定位生效。否則其行為與相對定位相同。

四、方案實現

.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<prefixTestList.length;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:

<body>

????<div class="banner"></div>

????<div class="tab sticky"></div>

????<div?class="content"></div>

</body>

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;

}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。