忍法沮峡,scroll 翻滾之術!

前言

在日常的開發(fā)中亿柑,我們對 scroll 這個單詞肯定不陌生邢疙。

例如因為看不慣瀏覽器默認樣式而用 JS 一頓猛如虎操作的 自定義滾動條

或者是嗖~一下就到頂?shù)?回到頂部 望薄。

又或者是想去哪點哪的 標題導航 疟游。

image

但是在過去的開發(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察绷。

(吃瓜群眾:“很難嘛?是你太菜了吧津辩,大叔拆撼!”)

image

但其實隨著時間的推移容劳, web api 以及 css 規(guī)范的不斷改進,那些我們曾經(jīng)認為實現(xiàn)起來很麻煩的功能也變得簡單了起來闸度。下面我們可以一起來探討一下這些改進的內容竭贩。

Web API 中的 scroll 家族

我們來康康 scroll 家族 里有趣的 API。

scroll 與 scrollTo

scroll()scrollTo 方法是用于在給定的元素中滾動到某個特定坐標的 Element 接口莺禁。

語法如下:

  1. scroll/scrollTo(x, y)

    • x:元素要移動的位置橫坐標留量。
    • y:元素要移動的位置縱坐標。
  2. scroll/scrollTo(options)

    options支持屬性有left哟冬,top以及behavior

    • top:元素要移動的位置橫坐標楼熄。
    • left:元素要移動的位置縱坐標。
    • behavior:元素的運動模式浩峡,如果是auto可岂,則沒有動畫效果,如果是smooth翰灾,則是平滑滾動缕粹。

我們來康康栗子:

image

上面例子來自 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 接口。

語法如下:

  1. scrollBy(x, y)

    • x:元素要移動的位置橫坐標纸淮。
    • y:元素要移動的位置縱坐標平斩。
  2. scrollBy(options)

    options支持屬性有lefttop以及behavior

    • top:元素要移動的位置橫坐標萎馅。
    • lef::元素要移動的位置縱坐標双戳。
    • behavior:元素的運動模式,如果是auto糜芳,則沒有動畫效果飒货,如果是smooth,則是平滑滾動峭竣。

再舉個栗子:

image

核心代碼如下:

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而已皆撩。非常的機智~

image

我們再來看看上述三個API的兼容性:

image

Mmmm扣墩,兼容性挺好的。

(吃瓜群眾:IE沒有人權扛吞?呻惕??滥比?亚脆??盲泛?濒持?键耕?)

Element.scrollIntoView

Element.scrollIntoView() 方法可以讓當前的元素滾動到瀏覽器窗口的可視區(qū)域內。

語法如下:

  1. scrollIntoView(alignToTop)

    alignToTop是一個布爾值柑营,如果不填則默認為true屈雄。相當于{block: 'start', inline: ‘nearest‘}

    如果值為true官套,則元素的頂端將和其所在滾動區(qū)的可視區(qū)域的頂端對齊酒奶。如果為false,則是底端對齊虏杰。相當于{block: 'end', inline: 'nearest'}

  2. scrollIntoView(scrollIntoViewOptions)

    scrollIntoViewOptions包含下列屬性的對象:

    • behavior:元素的運動模式讥蟆,如果是auto,則沒有動畫效果纺阔,如果是smooth瘸彤,則是平滑滾動。
    • block:定義垂直方向的對齊方式笛钝,值可以是 start质况,centerendnearest之一玻靡。默認為 nearest结榄。
    • inline:定義水平方向的對齊方式,值可以是 start囤捻,center臼朗, endnearest之一。默認為 nearest蝎土。

來來來视哑,我給大家解釋一下blockinline的可選值到底是怎么回事:

  • start:跟當前元素它爹的頭發(fā)(頂部)對齊。
  • center:跟當前元素它爹的肚子(中間)對齊誊涯。
  • end:跟當前元素它爹的 jio(底部)對齊挡毅。
  • nearest:就近原則,挨哪里近去哪暴构,如果在中間就不動跪呈。

如果是block,就當元素是站著的(從上往下)取逾,如果是inline耗绿,就當元素是躺著的(從左到右)。當然砾隅,前提是默認的writing-mode: horizontal-tb缭乘。

有點繞?快來康康栗子呀:https://codepen.io/krischan77/pen/mdJMQpz

image

好了,上述就是殺馬特堕绩,哦不是,scroll家族的特性了邑时。(廢棄或準備廢棄的就沒往上寫了奴紧。)

最后我們同樣來看看兼容性:

image

嗯,還行晶丘,IE都能用了黍氮。。浅浮。

至此沫浆,我們Web AP里的殺馬特家族,哦不是滚秩,scroll家族已介紹完畢专执,像Element.scrollIntoViewIfNeed這種不染發(fā)(不是標準)的API,就沒有介紹了郁油,有興趣的可以自己去看看它到底能干啥本股。

image

CSS scroll

分享完 JS 中的 scroll ,我們再來了解下 CSS 中的 scroll 桐腌。

scroll-behavior

我們上面在講這個 JS 中的 scroll 時拄显,多次提到一個單詞叫“behavior”。

Mmmm案站,所以你們猜猜這個scroll-behavior跟 JS 里的behavior有木有關系躬审?

嗯,沒錯蟆盐,你們猜對啦承边,是有關系的。

(吃瓜群眾:“都沒人理你~”)

scroll-behavior跟上述各個scrollAPI 里的behavior一樣舱禽,是用來定義頁面進行滾動操作時的動畫效果炒刁。

如果定義為smooth,則頁面觸發(fā)滾動操作時誊稚,就會有滾動的效果翔始,如果為auto,則跟原來一樣里伯,是瞬間移動到指定位置城瞎。這指的是類似于點擊#hash跳轉一樣的觸發(fā),而不是滑動滾動條疾瓮。

其效果可以參照本文第一小節(jié)的 DEMO脖镀。

兼容性就如圖:

image

Scroll Snap

CSS Scroll Snap 是 CSS 中一個比較新的獨立模塊,它的第一個正式版本CSS Scroll Snap 模塊 Level 1也是在 2019 年 3 月 19 日才發(fā)布狼电。

CSS Scroll Snap 模塊 可以讓頁面容器停止?jié)L動時蜒灰,捕捉并讓其自動滑動到指定元素的指定位置弦蹂。

一給我哩 giaogiao!這可是非常了不起的特性啊~

image

它分了兩部分强窖,一部分作用于滾動容器上凸椿,一部分作用于相對的滾動子元素上,具體關系如下表:

作用于滾動容器 作用于滾動子元素
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動時就肯定能對齊燥撞。

我們來康康這玩意到底是啥效果:

image

以上 DEMO 來自于 MDN 的scroll-snap-type

scroll-snap-align

scroll-snap-align屬性指定捕捉容器要捕捉的捕捉子元素位置座柱。可選的值如下:

  • none :默認值物舒,啥也不干 0.0色洞。
  • start :跟開始位置對齊。
  • end :跟結束位置對齊冠胯。
  • center :居中對齊火诸。

效果如下:

image

以上 DEMO 來自于 Andy Adams 的scroll-snap-align

scroll-snap-stop

因為 Scroll Snap 元素會有幾個捕捉的位置,而scroll-snap-stop可以控制到達這些位置之后是否被捕獲荠察,還是到了指定的位置才被捕獲置蜀。可選屬性如下:

  • normal :默認值悉盆,滾動的時候盯荤,可以忽略捕捉位置。
  • always :滾動的時候焕盟,不能忽略捕捉位置秋秤,還必須定位到第一個捕捉元素的位置。

栗子如下:

image

以上 DEMO 來自于 MDN 的scroll-snap-stop

scroll-margin

scroll-margin是一個簡寫屬性,跟margin一樣灼卢,有不同的邏輯屬性可以選绍哎。它可以設置元素跟滾動條之間的外邊框大小。我們看兩個動圖對比下區(qū)別芥玉。

當我們點擊#hash跳轉時蛇摸。

普通操作:

image
h3 {
}

添加了scroll-margin-top

image
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:

image

以上 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-paddingscroll-margin類型,只不過跟paddingmargin的一樣雪标,有內外邊距的區(qū)別零院。

來個 DEMO:

image

以上 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兼容性如下:

image

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;

image

默認情況

image

兼容性如下:

image

課外姿勢

新舊邏輯屬性

不知道各位有沒有注意上述各個屬性的值芭毙,除了有常規(guī)的xy蟋字,top稿蹲,rightbottomleft之外鹊奖,還有四個比較少見的值block苛聘,inlinestartend

所以這到底是什么呢设哗?

其實是因為 W3C 為了照顧到非西文排序國家的書寫習慣唱捣,特意修改了 CSS 的邏輯屬性。

對于像我們國家或者是美國這樣网梢,文檔排列是從上到下震缭,從左到右的,top 战虏、 right 拣宰、 bottomleft就很好理解。

但是像日本或者阿拉伯等書寫排列跟我們不一樣的國家烦感,在邏輯上就會有不合理的地方巡社,例如:

  • 在阿拉伯,他們的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姜胖。

image

最后來個特效

這是一個利用scroll-behavior: smooth的特性寫出來的效果,之前跟朋友們一起出去玩舟茶,我們進行了許多的活動谭期。其中有一項游戲就是“你比劃我猜”,作為策劃者的魚頭吧凉,自然不能放過這次機會隧出,遂用技術小秀了一把。

我們先來看看效果阀捅。

image

源碼地址在這:

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;

大家也不妨嘗試下用所掌握的姿勢增添點生活情趣呀~

image

后記

吃瓜群眾:我看完了整篇忍级,沒看到哪里有跟忍術相關的內容胺?騙我流量轴咱,賠錢汛蝙。

魚頭:沒有又咋啦烈涮?說好的寵我,你現(xiàn)在兇我是什么意思窖剑?

image

參考資料

  1. scrollIntoView block vs inline
  2. CSSOM View Module
  3. Element.scrollIntoView()
  4. CSS Scroll Snap Module Level 1
  5. CSS TRICK scroll-snap-type
  6. MDN scroll-snap-type
  7. CSS TRICK scroll-snap-align
  8. scroll-snap-stop
  9. scroll-margin
  10. scroll-padding
  11. Fixed Headers and Jump Links? The Solution is scroll-margin-top
  12. caniuse

后記

如果你喜歡探討技術坚洽,或者對本文有任何的意見或建議,非常歡迎加魚頭微信好友一起探討西土,當然讶舰,魚頭也非常希望能跟你一起聊生活,聊愛好,談天說地。
魚頭的微信號是:krisChans95
也可以掃碼關注公眾號,訂閱更多精彩內容。

https://user-gold-cdn.xitu.io/2020/3/4/170a55cc795174aa?w=1000&h=480&f=png&s=311000
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末囊陡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌潭袱,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件历帚,死亡現(xiàn)場離奇詭異滔岳,居然都是意外死亡,警方通過查閱死者的電腦和手機挽牢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門谱煤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人禽拔,你說我怎么就攤上這事刘离。” “怎么了睹栖?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵硫惕,是天一觀的道長。 經(jīng)常有香客問我野来,道長恼除,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任曼氛,我火速辦了婚禮豁辉,結果婚禮上,老公的妹妹穿的比我還像新娘舀患。我一直安慰自己徽级,他們只是感情好,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布聊浅。 她就那樣靜靜地躺著餐抢,像睡著了一般现使。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上弹澎,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天朴下,我揣著相機與錄音,去河邊找鬼苦蒿。 笑死殴胧,一個胖子當著我的面吹牛,可吹牛的內容都是我干的佩迟。 我是一名探鬼主播团滥,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼报强!你這毒婦竟也來了灸姊?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤秉溉,失蹤者是張志新(化名)和其女友劉穎力惯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體召嘶,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡父晶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了弄跌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甲喝。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖铛只,靈堂內的尸體忽然破棺而出埠胖,到底是詐尸還是另有隱情,我是刑警寧澤淳玩,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布直撤,位于F島的核電站,受9級特大地震影響凯肋,放射性物質發(fā)生泄漏谊惭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一侮东、第九天 我趴在偏房一處隱蔽的房頂上張望圈盔。 院中可真熱鬧,春花似錦悄雅、人聲如沸驱敲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽众眨。三九已至握牧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間娩梨,已是汗流浹背沿腰。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留狈定,地道東北人颂龙。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像纽什,于是被迫代替她去往敵國和親措嵌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內容

  • 一芦缰、CSS Scroll Snap簡介 CSS Scroll Snap是CSS中一個獨立的模塊企巢,可以讓網(wǎng)頁容器滾動...
    pansly閱讀 1,955評論 0 2
  • 1. tab列表折疊效果 html: 能源系統(tǒng)事業(yè)部 崗位名稱: 工作地點 崗位名...
    lilyping閱讀 1,843評論 0 1
  • day01-_起源和結構 結構:Xhtml xml 表現(xiàn):CSS 行為:DOM ECMAScript 以上都屬于W...
    Sakura_明妃閱讀 1,174評論 0 1
  • 一探孝、在什么場景下會出現(xiàn)外邊距合并罗丰?如何合并?如何不讓相鄰元素外邊距合并再姑?給個父子外邊距合并的范例 在CSS當中,相...
    dengpan閱讀 571評論 0 0
  • 前端開發(fā)面試題 面試題目: 根據(jù)你的等級和職位的變化找御,入門級到專家級元镀,廣度和深度都會有所增加。 題目類型: 理論知...
    怡寶丶閱讀 2,572評論 0 7