自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

純 CSS 檢測(cè)滾動(dòng)的速度和方向

開(kāi)發(fā) 前端
說(shuō)起原理,其實(shí)和JS是差不多的,都是有個(gè)類(lèi)似于定時(shí)、延時(shí)的機(jī)制。那具體如何做呢?下面一步一步來(lái)介紹。

CSS可以做的事情越來(lái)越越多了。

我們經(jīng)常會(huì)碰到這樣的場(chǎng)景,很多網(wǎng)頁(yè)會(huì)在右下角放一個(gè)固定入口,有可能是返回頂部,有可能廣告,為了避免干擾,在頁(yè)面滾動(dòng)時(shí),會(huì)把這些入口臨時(shí)收起來(lái),停止?jié)L動(dòng)后再出現(xiàn),就像這樣

圖片圖片

通常我們實(shí)現(xiàn)這樣的效果會(huì)借助JS的定時(shí)器,并且監(jiān)聽(tīng)頁(yè)面滾動(dòng),其實(shí)也不復(fù)雜,大概是這樣實(shí)現(xiàn)

let timer;
window.addEventListener('scroll', function(){
  // 是否在滾動(dòng)
  isScroll = true
  timer && clearTimeout(timer)
  timer = setTimeout(() => {
    isScroll = false
  }, 150)
})

現(xiàn)如今,CSS也能實(shí)現(xiàn)這樣的功能了,也就是可以檢測(cè)頁(yè)面是否在滾動(dòng),進(jìn)一步,還能檢測(cè)滾動(dòng)的速度和方向,一起來(lái)看看吧~

一、CSS 檢測(cè)原理

說(shuō)起原理,其實(shí)和JS是差不多的,都是有個(gè)類(lèi)似于定時(shí)、延時(shí)的機(jī)制。那具體如何做呢?下面一步一步來(lái)介紹。

比如,我們有這樣一個(gè)可以滾動(dòng)的頁(yè)面;

<body>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
	...
</body>

簡(jiǎn)單修飾一下,效果是這樣的;

圖片圖片

然后我們需要用 CSS檢測(cè)滾動(dòng)的進(jìn)度,該如何做呢?沒(méi)錯(cuò),就是用 CSS變量。

假設(shè)有一個(gè)這樣的動(dòng)畫(huà),--scroll-position從0變到100,如下:

@keyframes adjust-pos {
  form {
     --scroll-position: 0;
  }
  to {
    --scroll-position: 100;
  }
}

為了方便演示,我們可以把這個(gè)動(dòng)畫(huà)的變化過(guò)程顯示在頁(yè)面上;

<div class="debug" hidden>
  <div data-id="--scroll-position"></div>
</div>

這里利用CSS計(jì)數(shù)器,直接用偽元素顯示CSS變量值;

具體實(shí)現(xiàn)如下:

:root {
  animation: adjust-pos linear 3s;
}
.debug{
  counter-reset: scroll-position calc(var(--scroll-position) * 1);
}
[data-id="--scroll-position"]::after {
  content: "--scroll-position: " counter(scroll-position);
}

現(xiàn)在效果如下:

圖片圖片

現(xiàn)在數(shù)字直接從0變到了100,沒(méi)有中間的過(guò)程。

這是因?yàn)?-scroll-position是一個(gè)自定義變量,無(wú)法直接過(guò)渡。為了使這個(gè)變量也能像普通的過(guò)渡屬性自動(dòng)過(guò)渡,需要用到CSS @property,也就是需要注冊(cè)這個(gè)變量,讓瀏覽器認(rèn)為這是一個(gè)合法的 CSS 變量。

@property --scroll-position {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

這段代碼表示--scroll-position是一個(gè)number類(lèi)型的數(shù)據(jù),是一個(gè)合法的,可以過(guò)渡的類(lèi)型,自然也就有動(dòng)畫(huà)了,效果如下:

圖片圖片

然后我們加上滾動(dòng)驅(qū)動(dòng)動(dòng)畫(huà),讓這個(gè)動(dòng)畫(huà)跟隨頁(yè)面滾動(dòng)。

:root {
  animation: adjust-pos 3s linear both;
  animation-timeline: scroll();
}

效果如下,這樣就能檢測(cè)到滾動(dòng)的具體位置了。

圖片圖片

當(dāng)然,僅僅這樣還是不夠的,我們只知道了滾動(dòng)的進(jìn)度,并不知道滾動(dòng)的狀態(tài)。

為了知道滾動(dòng)的速度,我們還需要另一個(gè)變量,假設(shè)是--scroll-position-delayed。

@property --scroll-position-delayed {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}
@keyframes adjust-pos {
  form {
     --scroll-position: 0;
    --scroll-position-delayed: 0;
  }
  to {
    --scroll-position: 100;
    --scroll-position-delayed: 100;
  }
}

這樣就有了兩個(gè)變量在同時(shí)變化,效果如下:

圖片圖片

同時(shí)變化沒(méi)有什么意義,我們需要加一點(diǎn)延時(shí),就像 JS的定時(shí)器一樣,這里我們可以直接通過(guò)transition來(lái)實(shí)現(xiàn)。

body{
  margin: 0;
  transition: --scroll-position-delayed 0.15s linear;
}

這里的0.15s表示--scroll-position-delayed在變化時(shí)需要0.15s的時(shí)間,而--scroll-position是瞬時(shí)完成的,所以就相當(dāng)于--scroll-position-delayed始終比--scroll-position慢了0.15秒,也就相當(dāng)于延時(shí)了0.15s,實(shí)際效果如下:

圖片圖片

是不是可以很清楚的看到下面的數(shù)值要比上面的慢一點(diǎn)?

有了這個(gè)時(shí)間差,我們就可以判斷當(dāng)前的滾動(dòng)狀態(tài)了。

比如我們可以用一個(gè)變量--scroll-velocity來(lái)表示兩者的差值。

body{
  --scroll-velocity: calc(var(--scroll-position) - var(--scroll-position-delayed));
}

效果如下:

圖片圖片

通過(guò)這個(gè)差值,我們是不是就能發(fā)現(xiàn)一些規(guī)律?

  1. 當(dāng)--scroll-velocity為0時(shí),表示滾動(dòng)停止,否則表示正在滾動(dòng)中。
  2. 當(dāng)--scroll-velocity大于0時(shí),表示滾動(dòng)方向?yàn)橄隆?/li>
  3. 當(dāng)--scroll-velocity小于0時(shí),表示滾動(dòng)方向?yàn)樯稀?/li>
  4. 還可以從--scroll-velocity的絕對(duì)值上考慮,絕對(duì)值越大,表示滾動(dòng)速度越快,反之則越慢。

這就是CSS檢測(cè)的原理了,是不是還算簡(jiǎn)單呢?不過(guò)這還沒(méi)完,還需要具體實(shí)現(xiàn),比如怎么根據(jù)這個(gè)變量來(lái)匹配對(duì)應(yīng)的樣式。

二、CSS 樣式查詢

回到文章開(kāi)頭,我們?nèi)绾螜z測(cè)是否正在滾動(dòng)呢,并且在滾動(dòng)的時(shí)候隱藏右下角懸浮按鈕呢?下面就來(lái)實(shí)現(xiàn)這樣一個(gè)功能。

既然當(dāng)--scroll-velocity為0時(shí),就表示滾動(dòng)停止,那我們是不是可以直接用樣式查詢來(lái)匹配呢?

@container - CSS: Cascading Style Sheets | MDN (mozilla.org)[1]

CSS 樣式查詢是容器查詢的一部分,從名稱也可以看出,它可以查詢?cè)氐臉邮?,進(jìn)而設(shè)置額外的樣式。比如默認(rèn)是隱藏的。

.back{
  transform: translateX(100%);
  transition: .2s;
}

當(dāng)匹配到--scroll-velocity:0時(shí),顯示這個(gè)懸浮按鈕,就可以這樣來(lái)實(shí)現(xiàn)。

@container style(--scroll-velocity: 0) {
  .back{
    transform: translateX(0);
  }
}

效果如下:

圖片圖片

好像并沒(méi)有起效果?其實(shí)和前面的動(dòng)畫(huà)原理差不多,這是一個(gè)CSS自定義變量,無(wú)法直接檢測(cè)到變化的值。這里有一個(gè)解決方案,為了保證能夠樣式查詢到,需要用@property注冊(cè)一下:

@property --scroll-velocity {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

這樣就能完美檢測(cè)了。

你也可以訪問(wèn)線上鏈接來(lái)查看實(shí)際效果。

  • CSS scroll-speed (juejin.cn)[2]

是不是非常簡(jiǎn)單?

三、CSS 變量計(jì)算

除了使用樣式查詢外,我們還可以用CSS變量的計(jì)算方式來(lái)實(shí)現(xiàn)。

什么意思呢?比如我們想知道是否在滾動(dòng),其實(shí)就是兩個(gè)狀態(tài),那能不能用0和1來(lái)表示是否在滾動(dòng)呢?那就需要做一點(diǎn)點(diǎn)變換了。

現(xiàn)在--scroll-velocity表示差值,范圍可能是-50~50,那如何轉(zhuǎn)換成1~0呢,很簡(jiǎn)單,直接除以自身就行了, 比如-50/-50和50/50結(jié)果都是1,有人會(huì)奇怪0/0會(huì)不會(huì)無(wú)限大,沒(méi)關(guān)系,這里CSS計(jì)算的結(jié)果還是0,實(shí)現(xiàn)如下:

body{
  --scroll-velocity: calc(var(--scroll-position) - var(--scroll-position-delayed));
  --scroll-dynamic: calc(var(--scroll-velocity) / var(--scroll-velocity));
}

這樣的話,我們就無(wú)需樣式查詢來(lái)改變右下角懸浮按鈕的狀態(tài)了,直接用--scroll-dynamic來(lái)控制transform

.back{
  transform: translateX(calc(var(--scroll-dynamic) * 100%));
}

看看效果:

圖片圖片

不一樣的實(shí)現(xiàn)也能得到相同的效果,你也可以訪問(wèn)線上鏈接來(lái)查看實(shí)際效果。

  • CSS scroll-dynamic - (juejin.cn)[3]

除了可以得到是否在滾動(dòng),還能計(jì)算得到滾動(dòng)方向,比如1表示向下,-1表示向上,我們可以這樣來(lái)計(jì)算。

body{
  --scroll-velocity: calc(var(--scroll-position) - var(--scroll-position-delayed));
  --scroll-speed: max(var(--scroll-velocity), -1 * var(--scroll-velocity));
	--scroll-direction: calc(var(--scroll-velocity) / var(--scroll-speed));
}

看似有點(diǎn)復(fù)雜,其實(shí)也不難理解。比如當(dāng)前差值是-30,那么,我們可以通過(guò)乘以-1,然后取兩者較大值,這樣就能得到絕對(duì)值了。

圖片圖片

上面其實(shí)是個(gè)“偏方”,關(guān)于絕對(duì)值,其實(shí)已經(jīng)有CSS abs()了,只是現(xiàn)在還沒(méi)有支持,相信以后就能用上了。

然后用原值除以這個(gè)絕對(duì)值,就能得到1或者-1了。

利用這個(gè)特性,我們可以在不同的方向改變箭頭的指向。

.back{
  transform: scaleY(var(--scroll-direction));
}

效果如下:

圖片圖片

你也可以訪問(wèn)線上鏈接來(lái)查看實(shí)際效果:

  • CSS scroll-dynamic (juejin.cn)[4]

四、更多有趣的案例

除了上面幾個(gè)應(yīng)用,我還找了幾個(gè)有趣的案例。

比如下面這種蟲(chóng)洞效果,在水平或者垂直方向滾動(dòng)時(shí),會(huì)有明顯的透視效果https://codepen.io/bramus/pen/wvRqVBm

圖片圖片

再比如這種上下滾動(dòng),可以看到不同方向上內(nèi)容的傾斜角度不一樣,而且滾動(dòng)越快,傾斜越大:https://codepen.io/bramus/pen/OJrxBaL

圖片

還有一個(gè)比較簡(jiǎn)單實(shí)用的運(yùn)動(dòng)模糊滾動(dòng),也就是在滾動(dòng)時(shí),頁(yè)面會(huì)有模糊的效果:https://codepen.io/bramus/pen/XWoREjv

五、最后總結(jié)一下

說(shuō)了這么多,核心原理其實(shí)就這么幾行,如下:

@property --scroll-position {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}
@property --scroll-position-delayed {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}
@keyframes adjust-pos {
  to {
    --scroll-position: 100;
    --scroll-position-delayed: 100;
  }
}
:root {
  animation: adjust-pos 3s linear both;
  animation-timeline: scroll();
}
body{
  transition: --scroll-position-delayed 0.15s linear;
  --scroll-velocity: calc(var(--scroll-position) - var(--scroll-position-delayed));
  --scroll-speed: max(var(--scroll-velocity), -1 * var(--scroll-velocity));
  --scroll-direction: calc(var(--scroll-velocity) / var(--scroll-speed));
  --scroll-dynamic: calc(var(--scroll-velocity) / var(--scroll-velocity));
}

其實(shí)原理還是比較好理解的,下面總結(jié)一下:

  1. 首先用CSS自定義變量--scroll-position實(shí)現(xiàn)一個(gè)從0到100的動(dòng)畫(huà),注意需要用@property注冊(cè)。
  2. 然后用CSS滾動(dòng)驅(qū)動(dòng)動(dòng)畫(huà)將其關(guān)聯(lián),實(shí)現(xiàn)在滾動(dòng)的時(shí)候變量自動(dòng)變化。
  3. 接著再定義一個(gè)相同動(dòng)畫(huà)的變量--scroll-position-delayed,并設(shè)置過(guò)渡時(shí)間,這樣就會(huì)比--scroll-position變化的慢一點(diǎn)。
  4. 將這兩個(gè)變量相減可以得到差值--scroll-velocity。
  5. 通過(guò)這個(gè)差值--scroll-velocity就能獲得各種狀態(tài)了。
  6. 當(dāng)--scroll-velocity為0時(shí),表示滾動(dòng)停止,否則表示正在滾動(dòng)中。
  7. 當(dāng)--scroll-velocity大于0時(shí),表示滾動(dòng)方向?yàn)橄隆?/li>
  8. 當(dāng)--scroll-velocity小于0時(shí),表示滾動(dòng)方向?yàn)樯稀?/li>
  9. 還可以從--scroll-velocity的絕對(duì)值上考慮,絕對(duì)值越大,表示滾動(dòng)速度越快,反之則越慢。
  10. 可以通過(guò)樣式查詢來(lái)匹配各種條件,不過(guò)需要用@property注冊(cè)。
  11. 通過(guò) CSS calc 和 max計(jì)算可以得到更多狀態(tài),比如滾動(dòng)方向。
  12. 然后就是實(shí)際的運(yùn)用了。
責(zé)任編輯:武曉燕 來(lái)源: 前端偵探
相關(guān)推薦

2024-04-28 09:12:16

CSS文本是否溢出前端

2020-05-11 14:55:44

CSS鼠標(biāo)前端

2013-11-20 13:04:41

css瀏覽器渲染

2017-04-27 14:05:59

CSS動(dòng)畫(huà)前端

2021-01-19 12:16:10

CSS前端UI

2021-10-19 22:23:47

CSSBeautiful按鈕

2024-08-29 08:13:58

2021-01-25 06:37:06

Css前端CSS 特效

2023-05-08 09:08:33

CSS前端

2022-02-21 07:02:16

CSSbeautiful按鈕

2020-11-04 13:55:06

CSS密室逃脫前端

2022-08-10 16:08:38

鴻蒙CSS

2013-04-08 14:07:28

CSS

2022-09-12 08:31:41

CSS3偽類(lèi)URI

2023-11-22 07:47:34

2024-07-31 20:38:18

2021-11-12 05:44:25

XDR威脅檢測(cè)網(wǎng)絡(luò)攻擊

2022-08-29 17:39:53

應(yīng)用開(kāi)發(fā)css動(dòng)畫(huà)

2022-10-31 19:10:39

CSS元素focus

2024-01-22 09:28:23

CSS前端滾動(dòng)驅(qū)動(dòng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)