那麼這是怎麼實現的呢?本文將引用烏徒幫的跟隨畫面滾動程式碼,對此效果做詳解。
一、原始碼
下面是烏徒幫的跟隨螢幕捲動程式碼,它的作用域為烏徒幫網頁兩側的邊欄,以及雙擊螢幕後的右側隱藏欄。
var $catalogueOffsetTop = $('aside#catalogue').offset().top;
var $archiveOffestTop = $('aside#archive').offset().top;
var $archiveOffestLeft = $('aside#archive').offset().left;
$(window).bind('scroll resize',function(){
// #right-area 螢幕緊接著滾動效果
if($('#right-area').height ( ) $('#right-area').stop(true,true).animate({'top': $(document).scrollTop() ' px '},800);
}else if($('#right-area').height() > $(window).height() && $('#right-area').height( ) //可能範圍內是最關鍵的,允許滑動
if(($(document).scrollTop() $(window).height( )) $('#right-area').stop(true,true).css('top','0')
}else if(($(document).scrollTop() $(window).height()) $right_top = $(document).scrollTop () $(window ). height() - $('#right-area').height();
$('#right-area').stop(true,true).animate({'top ': $right_top ' px' },800);
}else{
$right_top = $(document).height() - $('#right-area').height(); ).stop(true,true).css ({'top': $right_top 'px'});
//alert($(document).scrollTop() $(window) ).height() - $ (文檔).height());
}
}else if($('#right-area').height() >= $(document).height( )){
$('#right-area').height ($(document).height()).stop(true,true).css({'overflow':'hidden','overflow-y ':'滾動'});
}
if( $(document).scrollLeft() == 0){ // 下面下面僅在螢幕旁邊,旁邊的時候需要進行跟隨滾動,同時注意的if($(window) .width() > 1024),是為了防止在小螢幕下也發生這種變化
//aside#catalogue的上下滑動
if($('aside#catalogue').outerHeight() if($(document).scrollTop() $('aside#catalogue').css({'position': '靜態','頂部':$catalogueOffsetTop}) ;
if($(window).width() > 1024)$('#main').css({'padding-left':'0'});
}else{
$ ( 'aside#catalogue').css({'position':'固定','top':'0'});
if($(window).width() > 1024)$('#main ' ).css({'padding-left':$('aside#catalogue').outerWidth() 5 'px' });
}
}else if($('aside#catalogue') . height() >= $(window).height() && $('aside#catalogue').outerHeight() if (($(document).scrollTop() $(window).height()) $('aside#catalogue' ) .css({'position':'static','top':$catalogueOffsetTop});
if($(window).width() > 1024)$('#main').css({'padding-left':'0'});
}else if(($(document).scrollTop() $(window).height()) $catalogue_top = $(window) ).height() - $('aside#catalogue').outerHeight() - 20;
$('aside#catalogue').css({'position':'fixed','top': $catalogue_top 'px'});
if($(window).width() > 1024)$('#main').css({'padding-left':$('aside#catalogue').outerWidth() 5 'px' } );
}else{
$catalogue_top = $(window).height() - $('aside#catalogue').outerHeight() - 20 - ($(document).height() - $('footer ').offset().top);
$('aside#catalogue').css({'position':'fixed','top':$catalogue_top 'px'});
if($(window).width() > 1024)$('#main').css({'padding-left':$('aside#catalogue').outerWidth() 5 'px' } );
}
}
//aside#archive的上下滑動
if($('aside#archive').outerHeight() if($(document).scrollTop() $('aside#archive').css({'position':'static','top':$archiveOffestTop,'left ': $archiveOffestLeft 'px'});
}else{
$('aside#archive').css({'position':'fixed','top':'0','left':$archiveOffestLeft 'px'});
}
}else if($('aside#archive').height() >= $(window).height() && $('aside#archive').outerHeight() if(($(document).scrollTop() $(window).height()) $('aside#archive').css({'position':'static','top':$archiveOffestTop,'left':$archiveOffestLeft 'px 'px ' ) ;
}else if(($(document).scrollTop() $(window).height()) $catalogue_top = $(window) ).height() - $('aside#archive').outerHeight();
$('aside#archive').css({'position':'fixed','top': $catalogue_top 'px','left':$archiveOffestLeft 'px'});
}else{
$catalogue_top = $(window).height() - $('aside#archive').outerHeight() - ($(document).height() - $('footer') .offset().top);
$('aside#archive').css({'position':'fixed','top':$catalogue_top 'px','left':$archiveOffestLeft 'px'});
}
}
}else{ // 如果螢幕不在左邊,就讓這兩個緊靠著位置
$('aside#catalogue').css({'position': '靜態','頂部':$catalogueOffsetTop});
$('#main').css({'padding-left':'0'});
$('aside#archive').css({'position':'static','top':$archiveOffestTop,'left':$archiveOffestLeft 'px'});
}
}
}).scroll().resize();
網路上有很多相關的程式碼,更有7行程式碼解決此問題的方法,甚至還有通用性的插件來實現此效果。然而它們都太過普遍化,對於不同的網站,特殊性不同,在一些細節上要做更多的考慮。
二、選擇用什麼方式跟隨螢幕滾動
方案有三種:
1、使用position:absolute;然後對top值進行動態賦值;
2、使用position:fixed;然後對top值進行動態賦值;
3、對padding-top或margin-top進行動態賦值;
前兩種都是用到了postion對元素的位置進行安排,和float一樣,position將元素從正常的文字流中拖出來。而padding或margin的方法則是控制元素的邊距來實現。到底哪一種好呢?
使用position:absolute;會出現滾動時發生抖動(火狐中不會) ,使用padding-top時會讓有背景的元素看上去難看,也會發生抖動,使用position:fixed不支持IE6,使用margin-top沒有嘗試過,應該會發生抖動。本段程式碼選擇的是position:fixed,唯一不會發生抖動的方案,但在IE6下不會有該效果。
三、要考慮的情況
之所以烏徒幫要將本站的程式碼拿出來講解,是因為網路上的程式碼沒有具體分析,很多問題都沒有考慮到。
1、要跟隨的元素的高度和螢幕的高度進行比較
網路上所有的程式碼考慮的是該區域的高度小於視窗高度的情況,因此程式碼很簡單。當區域高度等於和大於視窗高度時,我們又會有新的考慮。
2、如果區域高度超出窗口,何時開始跟隨滾動?
這要看我們想向用戶展示什麼,如果是一個廣告,如果是一段文字,如果是一個列表。我的設計是,當螢幕往下捲動,但是還沒有將要顯示的元素全部顯示完整時,不進行任何效果,當螢幕滾動到元素的底部臨界處時,效果觸發,再往下滾動時,元素的底端和螢幕的底端對齊,元素的下部一直呈現在螢幕內。當然,不同的網頁,你的設計自然不同,你也可能設計為,向下滾動時先沒有效果,當滾動到某一個廣告之後,這個廣告和屏幕頂端對齊跟隨滾動。
圖一 跟著螢幕捲動邏輯設計圖
從圖一我們來看這一設計思路。圖中綠色部分為要跟隨滾動的區域,灰色部分為整個網頁,淺灰色部分為屏幕(能看到的區域)我們通過向下移動淺灰色的屏幕來模擬向下滾動滾動條。在①的階段為初始階段,這個時候網頁一切照初始運作,沒有任何動作。到②的階段,螢幕向下捲動到一個臨界點,也就是要跟隨滾動區域的最低端。 ③階段是捲動過臨界點之後,元素開始跟著螢幕捲動,我們可以看到,元素的底端和螢幕的底端對齊,元素的頂端已經看不到。第④個階段的螢幕滾動到底部,可以想像,網頁的底部是存在一些版權資訊的,元素不能跟隨滾到底部把這些資訊遮住,因此在紅線的地方就不再跟隨滾動。
這是螢幕向下滾動的示意圖,當螢幕向上滾動時,這是這個順序的逆向。但還有另一個考慮,當螢幕在向上滾動時實現和向下滾動初始狀的一種效果,即臨界點是此時④中的綠色區域頂端,向上滾動時螢幕頂端和元素頂端對齊。出於技術難度的考慮,烏徒幫並沒有達到這個效果。
3、數和量的計算
在滾動時,我們要掌握好那些量是變化的,哪些又不變,在不變中找變,在變中找不變,總之要保持頭腦清晰,分辨如何計算各種高度關係。
在圖一中,我用了一條藍色豎線來輔助高度計算,用紅色的線指示螢幕和元素的位置,將藍色豎線分成了a、b、c、d、 e、f六段。那麼他們之間有哪些變化數量關係呢? (我們將綠色區域的元素定義為#myDiv,將版權資訊在內的底部定義為#footer)
a b c d e f=$(document).height();//文件高度,固定值
程式碼如下:
a= $('#myDiv').offset().top;//#myDiv頂部到文件頂部的初始值,隨著滾動,$('#myDiv').offset(). top會改變
b=$('#myDiv').height();//元素的高度,固定值
a b c=$(window).scrollTop()=$ (docment).scrollTop();//捲軸的位置,即文檔頂端到當前螢幕頂端的距離,不斷變化中
d=$(window).height();//螢幕的高度,固定值
f=$('#footer').height();//#footer的高度,固定值
a b c d e=$('#footer').offset( ).top=$(document).height()-$('#footer').height();//#footer頂部到文檔頂部的距離,固定值,不過需要注意的是,$('#footer ').offset().top $('#footer').height()並非一定等於$(document).height(),你要看#footer下面是否已經沒有了空白。
在整個變化過程中,變化的值只有$(window).scrollTop()=$(docment).scrollTop()和$('#myDiv').offset().top ,因此我們要抓住這些數值之間的加減數量關係,並做好邏輯判斷和賦值。
4、值何時取得
你可以看到,我在scroll事件之前事先取得了
var $catalogueOffsetTop = $('aside#catalogue').offset().top;
var $archiveOffestTop = $('aoffset().top;
var $archiveOffestTop = $('aside #archive').offset().top;
var $archiveOffestLeft = $('aside#archive').offset().left;
正是由於他們在scroll事件發生時會發生變化,因此要提前存放在變數中。
四、特殊情況特殊考慮
在寫出這麼多程式碼之前,我曾想過寫出一個可以通用的程式碼,然而事情並非那麼簡單,在烏徒幫中,三個要滾動的區域都具有特殊性,因此必須認真考慮他們的事件邏輯和仔細賦值。
1、元素是否自由隨意
由於烏徒幫雙擊螢幕滑向右側時出現的區域是自由的,頂部和底部沒有阻擋訊息,因此我們的處理更方便一些,不用取得頂部距離的初始值和考慮滾到底部時空出一段。但仍要考慮下面第2點,螢幕和元素高度的比較。
而對於側邊欄的滾到,我們要考慮邊側欄頂部到文件頂部還有一段距離,底部還有版權資訊。滾到的位置要透過上文所得的值,再配合css中所得的值進行精確計算。
2、判斷元素的高度和螢幕高度之間的關係
當元素高度小的時候,我們的處理比較簡單,只需要將元素頂端和螢幕頂端對齊,和上面第1點結合,也會出現不同的情況:如果元素頂部到文檔頂部還有一段距離的話,我們還不能屏幕一滾動就開始讓它和屏幕頂端對齊,而必須滾到它的頂端這個臨界點的時候才可以開始。
而當元素的高度大於螢幕的高度的時候,我們要進行更複雜的判斷,和第1點判斷何時開始跟隨滾動:只有當螢幕的底端和元素底端對齊時,元素開始跟隨螢幕滾動。
但是還有一種情況,即元素的高度超出了我們想要的高度,我們可以使用overflow來對元素進行處理,這時我們透過元素的高度和頁面中一些固定值的比較來處理這一環節。烏徒幫透過比較右側元素的高度和底部的關係來進行overflow的處理:
程式碼如下:
......
}else if($('#right-area').height() >= ($('footer').offset().top $ ('footer').height())){
$('#right-area').height($('footer').offset().top $('footer').height()) .stop(true,true).css({'overflow':'hidden','overflow-y':'scroll'});
}
3、自己網頁內特殊情況的變化
烏徒幫由於左右還可以滾動,因此產生了一系列問題,position:fixed時左右方向上元素的距離並沒有固定值,因此在進行左右滾動時,元素會遮住滾動完的螢幕,因此我又對$(document).scrollLeft()進行了判斷,進行了一些處理。
另外,烏徒幫還是一個自適應的網頁設計網站,在不同寬度的屏幕上顯示的效果也不同,js的特點是當屏幕發生變化時仍然起作用,因此,我也增加了螢幕寬度的判斷。
總結在跟隨螢幕滾動這個問題上,原始的思路是很簡單的,即透過本文列舉的三種方案進行位置或距離的動態改變,然而,要在具體細節上把握好,必須對動態變化中的各個數值有所把握。同時,結合自己的網頁,對不同情況下的動態效果有一個好的設計和規劃,也是實現跟隨螢幕滾動的關鍵環節。