- 作者:陳大魚頭
- github: KRISACHAN
前言
在日常的開發(fā)中亿柑,我們對 scroll
這個單詞肯定不陌生邢疙。
例如因為看不慣瀏覽器默認樣式而用 JS 一頓猛如虎操作的 自定義滾動條 。
或者是嗖~一下就到頂?shù)?回到頂部 望薄。
又或者是想去哪點哪的 標題導航 疟游。
但是在過去的開發(fā)中,要實現(xiàn)這些功能并不是那么輕松的一件事情痕支。
例如我們要實現(xiàn)一個有滾動效果的 回到頂部 功能颁虐,我們可能需要寫下這些代碼。
let timer = null;
let backTop = document.querySelector("#backTop");
backTop.addEventListener("click", () => {
cancelAnimationFrame(timer);
let startTime = +new Date();
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
let totalTime = 300;
timer = requestAnimationFrame(() => {
let lastTime = totalTime - Math.max(0, startTime - +new Date() + totalTime);
document.documentElement.scrollTop = document.body.scrollTop =
(lastTime * -scrollTop) / totalTime + scrollTop;
timer = requestAnimationFrame(func);
if (lastTime === totalTime) {
cancelAnimationFrame(timer);
}
});
});
(免責聲明:偽代碼未經(jīng)測試卧须,如有 BUG聪廉,跪求原諒。)
嚶故慈,意思就是要寫個動畫,不斷修改當前頁面的垂直滾動距離框全,直到為 0察绷。
(吃瓜群眾:“很難嘛?是你太菜了吧津辩,大叔拆撼!”)
但其實隨著時間的推移容劳, web api 以及 css 規(guī)范的不斷改進,那些我們曾經(jīng)認為實現(xiàn)起來很麻煩的功能也變得簡單了起來闸度。下面我們可以一起來探討一下這些改進的內容竭贩。
Web API 中的 scroll 家族
我們來康康 scroll 家族 里有趣的 API。
scroll 與 scrollTo
scroll()
與 scrollTo
方法是用于在給定的元素中滾動到某個特定坐標的 Element 接口莺禁。
語法如下:
-
scroll/scrollTo(x, y)
-
x
:元素要移動的位置橫坐標留量。 -
y
:元素要移動的位置縱坐標。
-
-
scroll/scrollTo(options)
options
支持屬性有left
哟冬,top
以及behavior
-
top
:元素要移動的位置橫坐標楼熄。 -
left
:元素要移動的位置縱坐標。 -
behavior
:元素的運動模式浩峡,如果是auto
可岂,則沒有動畫效果,如果是smooth
翰灾,則是平滑滾動缕粹。
-
我們來康康栗子:
上面例子來自 MDN 的 GitHub 倉庫dom-examples
核心 JS 代碼如下:
let scrollOptions;
const form = document.querySelector("form");
const leftInput = document.getElementById("left");
const topInput = document.getElementById("top");
const scrollInput = document.getElementById("scroll");
form.addEventListener("submit", e => {
e.preventDefault();
scrollOptions = {
left: leftInput.value,
top: topInput.value,
behavior: scrollInput.checked ? "smooth" : "auto"
};
window.scrollTo(scrollOptions);
});
scrollBy
scrollBy()
方法是使得元素滾動一段特定距離的 Element 接口。
語法如下:
-
scrollBy(x, y)
-
x
:元素要移動的位置橫坐標纸淮。 -
y
:元素要移動的位置縱坐標平斩。
-
-
scrollBy(options)
options
支持屬性有left
,top
以及behavior
-
top
:元素要移動的位置橫坐標萎馅。 -
lef:
:元素要移動的位置縱坐標双戳。 -
behavior
:元素的運動模式,如果是auto
糜芳,則沒有動畫效果飒货,如果是smooth
,則是平滑滾動峭竣。
-
再舉個栗子:
核心代碼如下:
let scrollOptions;
const form = document.querySelector("form");
const leftInput = document.getElementById("left");
const topInput = document.getElementById("top");
const scrollInput = document.getElementById("scroll");
form.addEventListener("submit", e => {
e.preventDefault();
scrollOptions = {
left: leftInput.value,
top: topInput.value,
behavior: scrollInput.checked ? "smooth" : "auto"
};
window.scrollBy(scrollOptions);
});
Mmmmm塘辅,沒錯,就是只是把上面的 DEMO 中的scrollTo
改為scrollBy
而已皆撩。非常的機智~
我們再來看看上述三個API的兼容性:
Mmmm扣墩,兼容性挺好的。
(吃瓜群眾:IE沒有人權扛吞?呻惕??滥比?亚脆??盲泛?濒持?键耕?)
Element.scrollIntoView
Element.scrollIntoView()
方法可以讓當前的元素滾動到瀏覽器窗口的可視區(qū)域內。
語法如下:
-
scrollIntoView(alignToTop)
alignToTop
是一個布爾值柑营,如果不填則默認為true
屈雄。相當于{block: 'start', inline: ‘nearest‘}
。如果值為
true
官套,則元素的頂端將和其所在滾動區(qū)的可視區(qū)域的頂端對齊酒奶。如果為false
,則是底端對齊虏杰。相當于{block: 'end', inline: 'nearest'}
-
scrollIntoView(scrollIntoViewOptions)
scrollIntoViewOptions
包含下列屬性的對象:-
behavior
:元素的運動模式讥蟆,如果是auto
,則沒有動畫效果纺阔,如果是smooth
瘸彤,則是平滑滾動。 -
block
:定義垂直方向的對齊方式笛钝,值可以是start
质况,center
,end
或nearest
之一玻靡。默認為nearest
结榄。 -
inline
:定義水平方向的對齊方式,值可以是start
囤捻,center
臼朗,end
或nearest
之一。默認為nearest
蝎土。
-
來來來视哑,我給大家解釋一下block
跟inline
的可選值到底是怎么回事:
-
start
:跟當前元素它爹的頭發(fā)(頂部)對齊。 -
center
:跟當前元素它爹的肚子(中間)對齊誊涯。 -
end
:跟當前元素它爹的 jio(底部)對齊挡毅。 -
nearest
:就近原則,挨哪里近去哪暴构,如果在中間就不動跪呈。
如果是block
,就當元素是站著的(從上往下)取逾,如果是inline
耗绿,就當元素是躺著的(從左到右)。當然砾隅,前提是默認的writing-mode: horizontal-tb
缭乘。
有點繞?快來康康栗子呀:https://codepen.io/krischan77/pen/mdJMQpz
好了,上述就是殺馬特堕绩,哦不是,scroll
家族的特性了邑时。(廢棄或準備廢棄的就沒往上寫了奴紧。)
最后我們同樣來看看兼容性:
嗯,還行晶丘,IE都能用了黍氮。。浅浮。
至此沫浆,我們Web AP里的殺馬特家族,哦不是滚秩,scroll家族已介紹完畢专执,像Element.scrollIntoViewIfNeed
這種不染發(fā)(不是標準)的API,就沒有介紹了郁油,有興趣的可以自己去看看它到底能干啥本股。
CSS scroll
分享完 JS 中的 scroll
,我們再來了解下 CSS 中的 scroll
桐腌。
scroll-behavior
我們上面在講這個 JS 中的 scroll
時拄显,多次提到一個單詞叫“behavior
”。
Mmmm案站,所以你們猜猜這個scroll-behavior
跟 JS 里的behavior
有木有關系躬审?
嗯,沒錯蟆盐,你們猜對啦承边,是有關系的。
(吃瓜群眾:“都沒人理你~”)
scroll-behavior
跟上述各個scroll
API 里的behavior
一樣舱禽,是用來定義頁面進行滾動操作時的動畫效果炒刁。
如果定義為smooth
,則頁面觸發(fā)滾動操作時誊稚,就會有滾動的效果翔始,如果為auto
,則跟原來一樣里伯,是瞬間移動到指定位置城瞎。這指的是類似于點擊#hash
跳轉一樣的觸發(fā),而不是滑動滾動條疾瓮。
其效果可以參照本文第一小節(jié)的 DEMO脖镀。
兼容性就如圖:
Scroll Snap
CSS Scroll Snap 是 CSS 中一個比較新的獨立模塊,它的第一個正式版本CSS Scroll Snap 模塊 Level 1也是在 2019 年 3 月 19 日才發(fā)布狼电。
CSS Scroll Snap 模塊 可以讓頁面容器停止?jié)L動時蜒灰,捕捉并讓其自動滑動到指定元素的指定位置弦蹂。
一給我哩 giaogiao!這可是非常了不起的特性啊~
它分了兩部分强窖,一部分作用于滾動容器上凸椿,一部分作用于相對的滾動子元素上,具體關系如下表:
作用于滾動容器 | 作用于滾動子元素 |
---|---|
scroll-snap-type | scroll-snap-align |
scroll-padding | scroll-snap-stop |
scroll-margin |
scroll-snap-type
scroll-snap-type
屬性指定能不能去捕捉當前滾動的容器并讓它對齊翅溺,以及所執(zhí)行的方向跟嚴格程度脑漫。
它可選的方向值有:
-
x
:捕捉 X 軸上的位置 -
y
:捕捉 Y 軸上的位置 -
block
:捕捉塊軸上的位置(邏輯意義上與 y 一樣) -
inline
:捕捉內聯(lián)軸上的位置(邏輯意義上與 x 一樣) -
both
:捕捉兩個方向上的位置
它可選的嚴格值有:
-
none
:默認值,Mmmm咙崎,啥也不干 -
proximity
:一個感性的值优幸,如果元素進入到了容器的捕捉位置范圍內,則進行捕捉并滾動褪猛,否則就不管网杆,至于這個范圍是多少,約莫著 45%的位置吧(手動測的握爷,W3C 沒給出具體算法跛璧,瞎猜吧,哈哈哈)新啼。 -
mandatory
:一個靠譜點的值追城,只要有參數(shù),停止?jié)L動時就肯定能對齊燥撞。
我們來康康這玩意到底是啥效果:
以上 DEMO 來自于 MDN 的scroll-snap-type
scroll-snap-align
scroll-snap-align
屬性指定捕捉容器要捕捉的捕捉子元素位置座柱。可選的值如下:
-
none
:默認值物舒,啥也不干 0.0色洞。 -
start
:跟開始位置對齊。 -
end
:跟結束位置對齊冠胯。 -
center
:居中對齊火诸。
效果如下:
以上 DEMO 來自于 Andy Adams 的scroll-snap-align
scroll-snap-stop
因為 Scroll Snap 元素會有幾個捕捉的位置,而scroll-snap-stop
可以控制到達這些位置之后是否被捕獲荠察,還是到了指定的位置才被捕獲置蜀。可選屬性如下:
-
normal
:默認值悉盆,滾動的時候盯荤,可以忽略捕捉位置。 -
always
:滾動的時候焕盟,不能忽略捕捉位置秋秤,還必須定位到第一個捕捉元素的位置。
栗子如下:
以上 DEMO 來自于 MDN 的scroll-snap-stop
scroll-margin
scroll-margin
是一個簡寫屬性,跟margin
一樣灼卢,有不同的邏輯屬性可以選绍哎。它可以設置元素跟滾動條之間的外邊框大小。我們看兩個動圖對比下區(qū)別芥玉。
當我們點擊#hash
跳轉時蛇摸。
普通操作:
h3 {
}
添加了scroll-margin-top
:
h3 {
scroll-margin-top: 5rem;
}
上面 DEMO 來自于 Chris Coyier 的Fixed Headers and Jump Links? The Solution is scroll-margin-top
從上面的兩個 DEMO,我們可以清晰地對比灿巧,假設#hash
導航的元素有修改scroll-margin
,那么最終跳轉的位置是會以scroll-margin
的值為邊界的揽涮。
不僅如此抠藕,我們再看下面的 DEMO:
以上 DEMO 源自于 Andy Adams 的scroll-margin
當我們設置了scroll-margin
的元素進入 scroll 的可視區(qū)域時,瀏覽器會根據(jù)當前元素就近的scroll-margin
值蒋困,移動到相應的位置盾似。
scroll-margin
的復寫屬性有以下幾個:
scroll-margin-top
scroll-margin-right
scroll-margin-bottom
scroll-margin-left
scroll-margin-block
scroll-margin-inline
scroll-margin-block-start
scroll-margin-inline-start
scroll-margin-block-end
scroll-margin-inline-end
scroll-padding
scroll-padding
跟scroll-margin
類型,只不過跟padding
與margin
的一樣雪标,有內外邊距的區(qū)別零院。
來個 DEMO:
以上 DEMO 源自于 Andy Adams 的scroll-padding
scroll-padding
的復寫屬性也同樣有以下幾個:
scroll-padding-top
scroll-padding-right
scroll-padding-bottom
scroll-padding-left
scroll-padding-block
scroll-padding-inline
scroll-padding-block-start
scroll-padding-inline-start
scroll-padding-block-end
scroll-padding-inline-end
以上API兼容性如下:
CSS overscroll
overscroll-behavior
overscroll-behavior
是 2019 年 6 月份 W3C 第一次發(fā)布的CSS 過渡滾動行為模塊 Level 1里唯一一個屬性。
overscroll-behavior
讓你可以控制瀏覽器滾動到邊界時的表現(xiàn)村刨。
它也是個簡寫屬性告抄,具體的屬性有:
-
overscroll-behavior-x
:正常情況下,處理橫軸滾動條滾動到邊界時的表現(xiàn)嵌牺。 -
overscroll-behavior-y
:正常情況下打洼,處理縱軸滾動條滾動到邊界時的表現(xiàn)。 -
overscroll-behavior-inline
:跟overscroll-behavior-x
一樣逆粹。 -
overscroll-behavior-block
:跟overscroll-behavior-y
一樣
可選的值為:
-
auto
:默認值募疮。 -
contain
:當一個元素滾動到邊界時,不會再影響臨近的滾動元素僻弹。 -
none
:當一個元素滾動到邊界時阿浓,不僅不會不會再影響臨近的滾動元素,連默認滾動到邊界的表現(xiàn)都會被阻止蹋绽。
栗子如下:
使用了overscroll-behavior: contain;
默認情況
兼容性如下:
課外姿勢
新舊邏輯屬性
不知道各位有沒有注意上述各個屬性的值芭毙,除了有常規(guī)的x
,y
蟋字,top
稿蹲,right
,bottom
跟left
之外鹊奖,還有四個比較少見的值block
苛聘,inline
,start
跟end
。
所以這到底是什么呢设哗?
其實是因為 W3C 為了照顧到非西文排序國家的書寫習慣唱捣,特意修改了 CSS 的邏輯屬性。
對于像我們國家或者是美國這樣网梢,文檔排列是從上到下震缭,從左到右的,top
战虏、 right
拣宰、 bottom
跟 left
就很好理解。
但是像日本或者阿拉伯等書寫排列跟我們不一樣的國家烦感,在邏輯上就會有不合理的地方巡社,例如:
- 在阿拉伯,他們的
padding-left
實際上方向是我們的padding-right
- 在日本手趣,他們的
padding-left
實際上方向是我們的padding-top
按照上面的情況晌该,這就比較詭異。所以 W3C 出來新的邏輯屬性绿渣,新舊的對比如下:
舊的邏輯屬性 | 新的邏輯屬性 |
---|---|
top | inset-block-start |
bottom | inset-block-end |
left | inset-inline-start |
right | inset-inline-end |
margin-top | margin-block-start |
margin-right | margin-inline-end |
margin-bottom | margin-block-end |
margin-left | margin-inline-start |
border-top | border-block-start |
border-right | border-inline-end |
border-bottom | border-block-end |
border-left | border-inline-start |
padding-top | padding-block-start |
padding-right | padding-inline-end |
padding-bottom | padding-block-end |
padding-left | padding-inline-start |
width | inline-size |
height | block-size |
總結一下就是橫坐標為inline
朝群,縱坐標為block
,起始位置為start
中符,結束位置為end
姜胖。
最后來個特效
這是一個利用scroll-behavior: smooth
的特性寫出來的效果,之前跟朋友們一起出去玩舟茶,我們進行了許多的活動谭期。其中有一項游戲就是“你比劃我猜”,作為策劃者的魚頭吧凉,自然不能放過這次機會隧出,遂用技術小秀了一把。
我們先來看看效果阀捅。
源碼地址在這:
https://codepen.io/krischan77/pen/zYOjyry
由于代碼太長胀瞪,就不完全貼出來了,但是核心邏輯就是利用scroll-behavior: smooth;
來控制#hash
跳轉時的效果饲鄙,為了不污染 url凄诞,同時利用了 history api 來維護正常的 url。大概就是醬紫:
let pageIndex = 1;
const urlChangeHandler = event => {
const { newURL } = event;
const current = newURL.replace(/.+\#page\-(\d)/, "$1");
pageIndex = +current;
console.log(pageIndex);
history.pushState(
{},
window.location.href,
window.location.origin + window.location.pathname
);
};
window.onhashchange = urlChangeHandler;
大家也不妨嘗試下用所掌握的姿勢增添點生活情趣呀~
后記
吃瓜群眾:我看完了整篇忍级,沒看到哪里有跟忍術相關的內容胺?騙我流量轴咱,賠錢汛蝙。
魚頭:沒有又咋啦烈涮?說好的寵我,你現(xiàn)在兇我是什么意思窖剑?
參考資料
- scrollIntoView block vs inline
- CSSOM View Module
- Element.scrollIntoView()
- CSS Scroll Snap Module Level 1
- CSS TRICK scroll-snap-type
- MDN scroll-snap-type
- CSS TRICK scroll-snap-align
- scroll-snap-stop
- scroll-margin
- scroll-padding
- Fixed Headers and Jump Links? The Solution is scroll-margin-top
- caniuse
后記
如果你喜歡探討技術坚洽,或者對本文有任何的意見或建議,非常歡迎加魚頭微信好友一起探討西土,當然讶舰,魚頭也非常希望能跟你一起聊生活,聊愛好,談天說地。
魚頭的微信號是:krisChans95
也可以掃碼關注公眾號,訂閱更多精彩內容。