摘要:這個界限就是該元素頂部距離窗口頂部的距離等于該元素設置的值比如以下像素分割線當我的頂部距離窗口頂部為值時,我就會像一樣在距離窗口值處的時代發送分效果圖當頁面滾動到距離黃色區塊頂部時,黃色區塊就會在窗口頂部處,頁面再往下滾動距離也不會變。
position: sticky;
fixed 吸頂
頁面滾動結束后頁面才渲染
需求經常會有這樣的需求,當頁面滾動到某一個位置fixedTopValue時,需要某個元素fixedElement固定在屏幕頂部?;痉椒ㄊ谦@取頁面的scrollTop值做判斷:
如果 scrollTop > fixedTopValue; 則添加position:fixed;top: 0;否則刪除position:fixed;屬性。
當在pc瀏覽器操作的時候正常。真機測試時總會出現千奇百怪的現象。比如:
1、 當頁面往下滾時,fixedElement需要等頁面滾動停止之后才會出現。
2、往上滾動時出現到固定的位置時不恢復原樣,而是到達頂部、等頁面停止滾動之后才會唰的一下恢復原樣
3、滾動到頂部之后,會出現兩個一樣的fixedElement, 過一會才恢復正常。
這樣的用戶體驗真的很差,所以迫切需要解決這個問題。
解決方法主要涉及一下三個方面
1、使用新的定位屬性 position: sticky; (如果支持)
2、如果不支持1,使用window.requestAnimationFrame方法確保改變定位屬性在固定時間內執行一次
3、 給fixedElement開啟硬件加速
基本邏輯如下圖:
測試頁面二維碼:
position:sticky是個什么鬼?對與css的position屬性我們只知道有static、relative、absolute、fixed這四個值,什么時候又多出了sticky這個值??聪翸DN文檔解釋
Sticky positioning
Sticky positioning is a hybrid of relative and fixed positioning. The element is treated as relative positioned until it crosses a specified threshold, at which point it is treated as fixed positioned.
大概意思是:sticky定位時relative定位與fixed定位的混合體。對于設置了sticky定位的元素,在它的頂部到達一個指定的界限之前會被當作relative定位,超過這個界限字后則被當作fixed定位。這個界限就是 該元素頂部距離窗口頂部的距離等于該元素設置的top值
比如以下demo:
60像素分割線當我的頂部距離窗口頂部為10px(top值)時,我就會像fixed一樣fixed在距離窗口10px(top值處)sticky的co時代發送分ntent
.top{height:60px;background:#f20;width:100%;color: #fff;font-size:16px;text-align:center;line-height:60px;} .sticky{position:sticky;position:-webkit-sticky;top:10px;height:40px;background:#dd5;color:#fff;line-height:20px;text-align:center;} .sticky-t10{top:0px;} .content{height:1000px;width:100%;background:#f8f8f8;text-align:center;padding-top:40px;color:#333;}
效果圖:
當頁面滾動到距離黃色區塊頂部10px時,黃色區塊就會fixed在窗口頂部10px處,頁面再往下滾動距離也不會變。當頁面網上滾動時,頁面頂部距離黃色區塊頂部大于10px時,黃色區塊又會恢復原樣固定在原來的位置。
position:sticky這個屬性并不會出現當頁面滾動停止之后才會出現的bug,因為它本身就是屬于正常流。并不會像fixed 與static相互切換時引起重排于重繪,而移動端瀏覽器滾動時是禁止重排跟重繪的,所以才會導致以上出現的問題。下圖是對于position:sticky的支持情況:
發現支持的瀏覽器一般般,但是經過測試像微信、safari、uc等瀏覽器是支持的,雖然chrome不支持,但是在chrome使用優化后的fixed定位也可以解決這個問題,基本能滿足主流的瀏覽器就夠了,其他的見鬼去吧。
滾動時減少性能損耗,強制觸發瀏覽器的同步布局如果瀏覽器不支持position:sticky,那么就使用js動態的在節點在fixed定位于static定位中切換,但是需要對切換過程做一些優化。
1、使用函數節流防抖減少dom操作頻繁粗發,但是保證在規定時間內必須執行一次。
2、使用window.requestAnimationFrame 方法在下一幀前觸發瀏覽器的強制同步布局,是對dom的操作能及時渲染到頁面上。
3、減少對dom的讀寫操作,或者把dom操作把讀、寫操作分開,可以減少渲染次數。
由于移動設備的硬件限制,導致移動端的瀏覽器的渲染能比較差。此時對需要定位的元素開啟硬件加速,會把需要渲染的元素放到特定的復合層『Composited Layer』中,當該元素改變時可以較少重繪或重排的范圍。給元素添加 transform: translateZ(0);屬性就行。
參考:硬件加速:
http://div.io/topic/1348
http://www.cnblogs.com/shyton...
提升頁面性能:
https://developer.mozilla.org...
http://www.ruanyifeng.com/blo...
http://www.jianshu.com/p/a32b...
具體實現請參考以下jquery版本的代碼:
//jquery (function() { function Sticky(){ this.init.apply(this, arguments); } /** * 滾動fixed組件初始化 * @param {object} setting allocate傳進來的參數 * @param {object} setting.stickyNode 需要設置position:sticky的節點,通常是最外層 * @param {object} setting.fixedNode 當滾動一定距離時需要fixed在頂部的節點 * @param {int} setting.top fixed之后距離頂部的top值 * @param {int} setting.zIndex fixed之后的z-index值 * @param {string} setting.fixedClazz fixed時給fixedNode添加的類 * @param {function} setting.runInScrollFn 滾動期間額外執行的函數 * @return {void} */ Sticky.setting = { stickyNode: null, fixedNode: null, top: 0, zIndex: 100, fixedClazz: "", runInScrollFn: null }; var sPro = Sticky.prototype; var g = window; /** * 初始化 * @param {object} options 設置 * @return {void} */ sPro.init = function(options){ this.setting = $.extend({}, Sticky.setting, options, true); if (options.fixedNode) { this.fixedNode = options.fixedNode[0] || options.fixedNode; this.stickyNode = options.stickyNode[0] || options.stickyNode; this.cssStickySupport = this.checkStickySupport(); this.stickyNodeHeight = this.stickyNode.clientHeight; this.fixedClazz = options.fixedClazz; this.top = parseInt(options.top, 10) || 0; this.zIndex = parseInt(options.zIndex) || 1; this.setStickyCss(); this.isfixed = false; // 把改變定位的操作添加到節流函數與window.requestAnimationFrame方法中,確保一定事件內必須執行一次 this.onscrollCb = this.throttle(function() { this.nextFrame(this.sticky.bind(this)); }.bind(this), 50, 100); this.initCss = this.getInitCss(); this.fixedCss = this.getFixedCss(); this.addEvent(); } }; /** * 獲取原始css樣式 * @return {string} 定位的樣式 */ sPro.getInitCss = function() { if (!!this.fixedNode) { return "position:" + this.fixedNode.style.position + ";top:" + this.fixedNode.style.top + "px;z-index:" + this.fixedNode.style.zIndex + ";"; } return ""; }; /** * 生成fixed時的css樣式 * @return {void} */ sPro.getFixedCss = function() { return "position:fixed;top:" + this.top + "px;z-index:" + this.zIndex + ";"; }; /** * 給fixedNode設置fixed定位樣式 * @param {string} style fixed定位的樣式字符串 */ sPro.setFixedCss = function(style) { if(!this.cssStickySupport){ if (!!this.fixedNode){ this.fixedNode.style.cssText = style; } } }; /** * 檢查瀏覽器是否支持positon: sticky定位 * @return {boolean} true 支持 false 不支持 */ sPro.checkStickySupport = function() { var div= null; if(g.CSS && g.CSS.supports){ return g.CSS.supports("(position: sticky) or (position: -webkit-sticky)"); } div = document.createElement("div"); div.style.position = "sticky"; if("sticky" === div.style.position){ return true; } div.style.position = "-webkit-sticky"; if("-webkit-sticky" === div.style.position){ return true; } div = null; return false; }; /** * 給sticyNode設置position: sticky定位 */ sPro.setStickyCss = function() { if(this.cssStickySupport){ this.stickyNode.style.cssText = "position:-webkit-sticky;position:sticky;top:" + this.top + "px;z-index:" + this.zIndex + ";"; } }; /** * 監聽window的滾動事件 */ sPro.addEvent = function() { $(g).on("scroll", this.onscrollCb.bind(this)); }; /** * 讓函數在規定時間內必須執行一次 * @param {Function} fn 定時執行的函數 * @param {int} delay 延遲多少毫秒執行 * @param {[type]} mustRunDelay 多少毫秒內必須執行一次 * @return {[type]} [description] */ sPro.throttle = function(fn, delay, mustRunDelay){ var timer = null; var lastTime; return function(){ var now = +new Date(); var args = arguments; g.clearTimeout(timer); if(!lastTime){ lastTime = now; } if(now - lastTime > mustRunDelay){ fn.apply(this, args); lastTime = now; }else{ g.setTimeout(function(){ fn.apply(this, args); }.bind(this), delay); } }.bind(this); }; /** * window.requestAnimationFrame的兼容性寫法,保證在100/6ms執行一次 * @param {Function} fn 100/16ms需要執行的函數 * @return {void} */ sPro.nextFrame = (function(fn){ var prefix = ["ms", "moz", "webkit", "o"]; var handle = {}; handle.requestAnimationFrame = window.requestAnimationFrame; for(var i = 0; i < prefix.length && !handle.requestAnimationFrame; ++i){ handle.requestAnimationFrame = window[prefix[i] + "RequestAnimationFrame"]; } if(!handle.requestAnimationFrame){ handle.requestAnimationFrame = function(fn) { var raf = window.setTimeout(function() { fn(); }, 16); return raf; }; } return function(fn) { handle.requestAnimationFrame.apply(g, arguments); } })(); /** * 判斷stickyNode的當前位置設置fixed|static|sticky定位 * @return {void} */ sPro.sticky = function() { this.setting.runInScrollFn && this.setting.runInScrollFn(); var stickyNodeBox = this.stickyNode.getBoundingClientRect(); if(stickyNodeBox.top <= this.top && !this.isfixed){ this.setFixedCss(this.fixedCss); this.fixedClazz && $(this.fixedNode).addClass(this.fixedClazz); this.isfixed = true; $(this).trigger("onsticky", true); } else if(stickyNodeBox.top > this.top && this.isfixed) { this.setFixedCss(this.initCss.replace(/position:[^;]*/, "position:static")); g.setTimeout(function() { this.setFixedCss(this.initCss) }.bind(this), 30); this.fixedClazz && $(this.fixedNode).removeClass(this.fixedClazz); this.isfixed = false; $(this).trigger("onsticky", true); } }; $.initSticky = function(options){ return new Sticky(options); }; })();
html 結構
css 結構
.g-page-box .m-nav?{ height:?1.33333rem; } .g-page-box .m-nav .nav-fixed?{ height:?.86667rem; padding:?.22667rem .50667rem; background-color:?#1aadbb; position:?relative; transform:?translate3d(0, 0, 0); -webkit-transform:?translate3d(0, 0, 0); transition:?height 4s; } .fixed{ position:?fixed; top:?0px; z-index:?100; }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/50343.html
摘要:這個界限就是該元素頂部距離窗口頂部的距離等于該元素設置的值比如以下像素分割線當我的頂部距離窗口頂部為值時,我就會像一樣在距離窗口值處的時代發送分效果圖當頁面滾動到距離黃色區塊頂部時,黃色區塊就會在窗口頂部處,頁面再往下滾動距離也不會變。 position: sticky; fixed 吸頂 頁面滾動結束后頁面才渲染 需求 經常會有這樣的需求,當頁面滾動到某一個位置fixedTopV...
摘要:這個界限就是該元素頂部距離窗口頂部的距離等于該元素設置的值比如以下像素分割線當我的頂部距離窗口頂部為值時,我就會像一樣在距離窗口值處的時代發送分效果圖當頁面滾動到距離黃色區塊頂部時,黃色區塊就會在窗口頂部處,頁面再往下滾動距離也不會變。 position: sticky; fixed 吸頂 頁面滾動結束后頁面才渲染 需求 經常會有這樣的需求,當頁面滾動到某一個位置fixedTopV...
摘要:用于獲得當前元素到定位父級頂部的距離偏移值。后來在項目中總會遇到滾動吸頂的效果需要實現,現在我將我知道的種滾動吸頂實現方式做詳細介紹。有兼容性問題,在微信瀏覽器某些版本中的值會為,于是乎也就有了第三種方案的兼容性寫法。修改版預覽 這篇文章是三天前寫就的,有大佬給我提了一些修改意見,我覺得這個意見確實中肯。所以就有了這個升級的修改版本。代碼同步更新到 GitHub 了。 修改內容如下: 添加...
摘要:因為項目需求,最近開始轉到微信公眾號開發,接觸到了框架,這個效果的實現雖說是基于框架下實現的,但是同樣也可以借鑒到其他地方,原理都是一樣的。上面我們得到了一個的屬性值,接下來我們只需要根據它的值來設置吸頂元素的屬性就可以了。 因為項目需求,最近開始轉到微信公眾號開發,接觸到了Vue框架,這個效果的實現雖說是基于Vue框架下實現的,但是同樣也可以借鑒到其他地方,原理都是一樣的。 進入正題...
閱讀 2233·2021-09-23 11:52
閱讀 1899·2021-09-02 15:41
閱讀 3018·2019-08-30 10:47
閱讀 1984·2019-08-29 17:14
閱讀 2337·2019-08-29 16:16
閱讀 3192·2019-08-28 18:29
閱讀 3418·2019-08-26 13:30
閱讀 2610·2019-08-26 10:49