完美實(shí)現(xiàn)一個“回到頂部”

前言

在實(shí)際應(yīng)用中,經(jīng)常用到滾動到頁面頂部或某個位置弥咪,一般簡單用錨點(diǎn)處理或用js將document.body.scrollTop設(shè)置為0,結(jié)果是頁面一閃而過滾到指定位置,不是特別友好姐呐。我們想要的效果是要有點(diǎn)緩沖效果。

現(xiàn)代瀏覽器陸續(xù)意識到了這種需求转唉,scrollIntoView意思是滾動到可視皮钠,css中提供了scroll-behavior屬性,js有Element.scrollIntoView()方法赠法。

scroll-behavior

scroll-behavior屬性可取值auto|smooth|inherit|unset

scroll-behavior: smooth;是我們想要的緩沖效果麦轰。在PC瀏覽器中乔夯,頁面默認(rèn)滾動是在<html>標(biāo)簽上,移動端大多數(shù)在<body>標(biāo)簽上款侵,在我們想要實(shí)現(xiàn)平滑“回到頂部”末荐,只需在這兩個標(biāo)簽上都加上:

html,?body?{

??scroll-behavior:?smooth;

}

準(zhǔn)確的說,寫在容器元素上新锈,可以讓容器(非鼠標(biāo)手勢觸發(fā))的滾動變得平滑甲脏,而不局限于<html>,<body>標(biāo)簽妹笆。

利用這個css屬性可以一步將原來純css標(biāo)簽直接切換块请,變成平滑過渡切換效果。

.tab?label?{

??padding:?10px;??

??border:?1px?solid?#ccc;??

??margin-right:?-1px;??

??text-align:?center;??

??float:?left;??

??overflow:?hidden;

}

.tab::after?{

??content:?"";??

??display:?table;??

??clear:?both;

}

.box?{

??height:?200px;??

??border:?1px?solid?#ccc;??

??scroll-behavior:?smooth;??

??overflow:?hidden;??

??margin-top:?10px;

}

.item?{

??height:?100%;??

??position:?relative;??

??overflow:?hidden;

}

.item?input?{

??position:?absolute;??

??top:?0;??height:?100%;??

??width:?1px;??

??border:?0;??

??padding:?0;??

??margin:?0;??

??clip:?rect(0?0?0?0);

}

<h1>純CSS選項(xiàng)卡</h1>

<div?class="tab">

??<label?for="tab1">選項(xiàng)卡1</label>

??<label?for="tab2">選項(xiàng)卡2</label>

??<label?for="tab3">選項(xiàng)卡3</label>

</div>

<div?class="box">

??<div?class="item">

????<input?type="text"?id="tab1">

????<p>選項(xiàng)卡1內(nèi)容</p>

??</div>

??<div?class="item">

????<input?type="text"?id="tab2">

????<p>選項(xiàng)卡2內(nèi)容</p>

??</div>

??<div?class="item">

????<input?type="text"?id="tab3">

????<p>選項(xiàng)卡3內(nèi)容</p>

??</div>

</div>

實(shí)現(xiàn)效果

也可以戳這里

再來看一下這個css屬性scroll-behavior在各大瀏覽器中的支持情況

呃~支持度不是很好拳缠,這樣一行css代碼能應(yīng)用上當(dāng)然是最好的墩新,不行就退化成一閃而過的效果咯。下面再看下js提供的api窟坐。

Element.scrollIntoView()

Element.scrollIntoView()方法讓當(dāng)前的元素滾動到瀏覽器窗口的可視區(qū)域內(nèi)海渊。

element.scrollIntoView(); // 等同于element.scrollIntoView(true)

element.scrollIntoView(alignToTop); // Boolean型參數(shù)

element.scrollIntoView(scrollIntoViewOptions); // Object型參數(shù)

參數(shù)alignToTop

一個Boolean值:

如果為true,元素的頂端將和其所在滾動區(qū)的可視區(qū)域的頂端對齊哲鸳。相應(yīng)的scrollIntoViewOptions: {block: "start", inline: "nearest"}臣疑。這是這個參數(shù)的默認(rèn)值。

如果為false徙菠,元素的底端將和其所在滾動區(qū)的可視區(qū)域的底端對齊讯沈。相應(yīng)的scrollIntoViewOptions: {block: "end", inline: "nearest"}。

參數(shù)scrollIntoViewOptions

一個帶有選項(xiàng)的object:

{?

?behavior:?"auto"??|?"instant"?|?"smooth",??

?block:????"start"?|?"end",

}

behavior可選

定義緩動動畫婿奔, "auto", "instant", 或 "smooth" 之一芙盘。默認(rèn)為 "auto"。

block可選

"start","center","end", 或"nearest"之一脸秽。默認(rèn)為"center"儒老。

inline可選

"start","center","end", 或"nearest"之一。默認(rèn)為"nearest"记餐。

瀏覽器支持

可以看到對于無參數(shù)的情況支持還是很好的驮樊,有參數(shù)的該API在瀏覽器中支持不是很好,我們可以同時結(jié)合CSS設(shè)置scroll-behavior: smooth;滾動效果片酝,在執(zhí)行滾動使用target.scrollIntoView()囚衔,即可達(dá)到“完美滾動”(不太完美)效果。

向下兼容

要達(dá)到所有瀏覽器都有相同(類似)效果雕沿,那就要把剩余不支持scroll-behavior屬性的瀏覽器揪出來练湿,用js去完成使命了。

判斷是否支持scroll-behavior屬性

很簡單审轮,用以下這一行代碼

if(typeof?window.getComputedStyle(document.body).scrollBehavior?===?'undefined')?{

??//?兼容js代碼

}?else?{??

?//?原生滾動api

?//?Element.scrollIntoView()

}

判斷是否支持scroll-behavior屬性肥哎,直接利用原生Element.scrollIntoView()滾動辽俗,否則向下兼容處理。

緩沖算法

緩沖的直觀效果是越來越慢篡诽,直到停止崖飘,也就是在相同時間內(nèi)運(yùn)動的距離越來越短。這樣可以設(shè)置一個定時器杈女,移動到當(dāng)前點(diǎn)到目標(biāo)點(diǎn)距離的緩沖率(比如1/2朱浴,1/3,...)處达椰,比如翰蠢,緩沖率設(shè)為2,當(dāng)前距離目標(biāo)點(diǎn)64px啰劲,下一秒就是32px躏筏,然后16px,8px...呈枉,到達(dá)某個閾值結(jié)束,也就是:

var?position?=?position?+?(destination?-?position)?/?n;

下面來簡單實(shí)現(xiàn)一個點(diǎn)擊右下方的”回到頂部“按鈕埃碱,頁面緩動滾動到頂部的demo猖辫。

<div?class="content">

????<p>很多內(nèi)容。砚殿。啃憎。</p>

????...??

????</div>

??<section?class="back-to-top">

????回到頂部??

???</section>

.content?{

??height:?3000px;??

??border:?1px?solid?#ccc;??

??box-shadow:?0?0?2px?solid;

}

.back-to-top?{

??width:?18px;??

??padding:?10px;??

??border:?1px?solid?#ccc;??

??box-shadow:?0?0?2px?#333;??

??position:?fixed;??

??right:?20px;??

??bottom:?40px;

}

.back-to-top:hover?{

??cursor:?pointer;

}

var?scrollTopSmooth?=?function?(position)?{

??//?不存在原生`requestAnimationFrame`,用`setTimeout`模擬替代

??if?(!window.requestAnimationFrame)?{

??????window.requestAnimationFrame?=?function?(cb)?{

????????return?setTimeout(cb,?17);

????};

??}

??//?當(dāng)前滾動高度

??var?scrollTop?=?document.documentElement.scrollTop?||?document.body.scrollTop;??

??//?step

??var?step?=?function?()?{

????var?distance?=?position?-?scrollTop;

????scrollTop?=?scrollTop?+?distance?/?5;????

????if?(Math.abs(distance)?<?1)?{??????

??????window.scrollTo(0,?position);

????}else?{???

?????window.scrollTo(0,?scrollTop);

?????requestAnimationFrame(step);

????}

??};

??step();

}

$backToTop?=?document.querySelector('.back-to-top')

$backToTop.addEventListener('click',?function?()?{

??scrollTopSmooth(0);

},?false);

</script>

效果圖

或者戳這里

簡單封裝

上面的小demo中似炎,緩沖算法和當(dāng)前滾動業(yè)務(wù)代碼耦合在一起了辛萍,下面單獨(dú)拆解出單獨(dú)一個函數(shù)。

/**

*?緩沖函數(shù)

*?@param?{Number}?position?當(dāng)前滾動位置

*?@param?{Number}?destination?目標(biāo)位置

*?@param?{Number}?rate?緩動率

*?@param?{Function}?callback?緩動結(jié)束回調(diào)函數(shù)?兩個參數(shù)分別是當(dāng)前位置和是否結(jié)束

*/var?easeout?=?function?(position,?destination,?rate,?callback)?{

??if?(position?===?destination?||?typeof?destination?!==?'number')?{?

????return?false;

??}

??destination?=?destination?||?0;

??rate?=?rate?||?2;?


?//?不存在原生`requestAnimationFrame`羡藐,用`setTimeout`模擬替代

??if?(!window.requestAnimationFrame)?{

??????window.requestAnimationFrame?=?function?(fn)?{??????

??????return?setTimeout(fn,?17);

????}

??}??


??var?step?=?function?()?{

????position?=?position?+?(destination?-?position)?/?rate;????

????if?(Math.abs(destination?-?position)?<?1)?{

??????callback(destination,?true);??????

??????return;

????}

????callback(position,?false);

????requestAnimationFrame(step);

??};

??step();

}

拆分后贩毕,這個小緩沖算法就可以被重復(fù)調(diào)用啦,而且仆嗦,適用于滾動到指定位置(不僅僅是到頂部)和緩沖率(控制滾動快慢)辉阶,當(dāng)前小demo調(diào)用:

var?scrollTopSmooth?=?function?(position)?{??

??//?當(dāng)前滾動高度

??var?scrollTop?=?document.documentElement.scrollTop?||?document.body.scrollTop;

??easeout(scrollTop,?position,?5,?function?(val)?{?

????window.scrollTo(0,?val);

??});

}

$backToTop?=?document.querySelector('.back-to-top')

$backToTop.addEventListener('click',?function?()?{

??scrollTopSmooth(200);

},?false);

總結(jié)

綜合來看,簡單實(shí)現(xiàn)一個完美滾動注意以下即可

<html>瘩扼,<body>標(biāo)簽加上scroll-behavior: smooth;屬性谆甜;

判斷當(dāng)前瀏覽器是否支持scrollBehavior屬性;

如果支持直接用原生滾動apiElement.scrollIntoView()集绰;

如果不支持則用js小緩沖算法兼容處理规辱。

完~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市栽燕,隨后出現(xiàn)的幾起案子罕袋,更是在濱河造成了極大的恐慌改淑,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炫贤,死亡現(xiàn)場離奇詭異溅固,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)兰珍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門侍郭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掠河,你說我怎么就攤上這事亮元。” “怎么了唠摹?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵爆捞,是天一觀的道長。 經(jīng)常有香客問我勾拉,道長煮甥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任藕赞,我火速辦了婚禮成肘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘斧蜕。我一直安慰自己双霍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布批销。 她就那樣靜靜地躺著洒闸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪均芽。 梳的紋絲不亂的頭發(fā)上丘逸,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機(jī)與錄音掀宋,去河邊找鬼鸣个。 笑死,一個胖子當(dāng)著我的面吹牛布朦,可吹牛的內(nèi)容都是我干的囤萤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼是趴,長吁一口氣:“原來是場噩夢啊……” “哼涛舍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唆途,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤富雅,失蹤者是張志新(化名)和其女友劉穎掸驱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體没佑,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡毕贼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛤奢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鬼癣。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖啤贩,靈堂內(nèi)的尸體忽然破棺而出待秃,到底是詐尸還是另有隱情,我是刑警寧澤痹屹,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布章郁,位于F島的核電站,受9級特大地震影響志衍,放射性物質(zhì)發(fā)生泄漏暖庄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一楼肪、第九天 我趴在偏房一處隱蔽的房頂上張望培廓。 院中可真熱鬧,春花似錦淹辞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至爷速,卻和暖如春央星,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惫东。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工莉给, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人廉沮。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓颓遏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親滞时。 傳聞我的和親對象是個殘疾皇子叁幢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容