当前位置:首页 > 科技  > 软件

纯 CSS 检测滚动的速度和方向

来源: 责编: 时间:2024-06-27 17:14:26 60观看
导读CSS可以做的事情越来越越多了。我们经常会碰到这样的场景,很多网页会在右下角放一个固定入口,有可能是返回顶部,有可能广告,为了避免干扰,在页面滚动时,会把这些入口临时收起来,停止滚动后再出现,就像这样图片通常我们实现这

CSS可以做的事情越来越越多了。BgT28资讯网——每日最新资讯28at.com

我们经常会碰到这样的场景,很多网页会在右下角放一个固定入口,有可能是返回顶部,有可能广告,为了避免干扰,在页面滚动时,会把这些入口临时收起来,停止滚动后再出现,就像这样BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

通常我们实现这样的效果会借助JS的定时器,并且监听页面滚动,其实也不复杂,大概是这样实现BgT28资讯网——每日最新资讯28at.com

let timer;window.addEventListener('scroll', function(){  // 是否在滚动  isScroll = true  timer && clearTimeout(timer)  timer = setTimeout(() => {    isScroll = false  }, 150)})

现如今,CSS也能实现这样的功能了,也就是可以检测页面是否在滚动,进一步,还能检测滚动的速度和方向,一起来看看吧~BgT28资讯网——每日最新资讯28at.com

一、CSS 检测原理

说起原理,其实和JS是差不多的,都是有个类似于定时、延时的机制。那具体如何做呢?下面一步一步来介绍。BgT28资讯网——每日最新资讯28at.com

BgT28资讯网——每日最新资讯28at.com

比如,我们有这样一个可以滚动的页面;BgT28资讯网——每日最新资讯28at.com

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

简单修饰一下,效果是这样的;BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

然后我们需要用 CSS检测滚动的进度,该如何做呢?没错,就是用 CSS变量。BgT28资讯网——每日最新资讯28at.com

假设有一个这样的动画,--scroll-position从0变到100,如下:BgT28资讯网——每日最新资讯28at.com

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

为了方便演示,我们可以把这个动画的变化过程显示在页面上;BgT28资讯网——每日最新资讯28at.com

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

这里利用CSS计数器,直接用伪元素显示CSS变量值;BgT28资讯网——每日最新资讯28at.com

具体实现如下:BgT28资讯网——每日最新资讯28at.com

: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);}

现在效果如下:BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

现在数字直接从0变到了100,没有中间的过程。BgT28资讯网——每日最新资讯28at.com

这是因为--scroll-position是一个自定义变量,无法直接过渡。为了使这个变量也能像普通的过渡属性自动过渡,需要用到CSS @property,也就是需要注册这个变量,让浏览器认为这是一个合法的 CSS 变量。BgT28资讯网——每日最新资讯28at.com

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

这段代码表示--scroll-position是一个number类型的数据,是一个合法的,可以过渡的类型,自然也就有动画了,效果如下:BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

然后我们加上滚动驱动动画,让这个动画跟随页面滚动。BgT28资讯网——每日最新资讯28at.com

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

效果如下,这样就能检测到滚动的具体位置了。BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

当然,仅仅这样还是不够的,我们只知道了滚动的进度,并不知道滚动的状态。BgT28资讯网——每日最新资讯28at.com

为了知道滚动的速度,我们还需要另一个变量,假设是--scroll-position-delayed。BgT28资讯网——每日最新资讯28at.com

@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;  }}

这样就有了两个变量在同时变化,效果如下:BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

同时变化没有什么意义,我们需要加一点延时,就像 JS的定时器一样,这里我们可以直接通过transition来实现。BgT28资讯网——每日最新资讯28at.com

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

这里的0.15s表示--scroll-position-delayed在变化时需要0.15s的时间,而--scroll-position是瞬时完成的,所以就相当于--scroll-position-delayed始终比--scroll-position慢了0.15秒,也就相当于延时了0.15s,实际效果如下:BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

是不是可以很清楚的看到下面的数值要比上面的慢一点?BgT28资讯网——每日最新资讯28at.com

有了这个时间差,我们就可以判断当前的滚动状态了。BgT28资讯网——每日最新资讯28at.com

比如我们可以用一个变量--scroll-velocity来表示两者的差值。BgT28资讯网——每日最新资讯28at.com

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

效果如下:BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

通过这个差值,我们是不是就能发现一些规律?BgT28资讯网——每日最新资讯28at.com

  1. 当--scroll-velocity为0时,表示滚动停止,否则表示正在滚动中。
  2. 当--scroll-velocity大于0时,表示滚动方向为下。
  3. 当--scroll-velocity小于0时,表示滚动方向为上。
  4. 还可以从--scroll-velocity的绝对值上考虑,绝对值越大,表示滚动速度越快,反之则越慢。

这就是CSS检测的原理了,是不是还算简单呢?不过这还没完,还需要具体实现,比如怎么根据这个变量来匹配对应的样式。BgT28资讯网——每日最新资讯28at.com

二、CSS 样式查询

回到文章开头,我们如何检测是否正在滚动呢,并且在滚动的时候隐藏右下角悬浮按钮呢?下面就来实现这样一个功能。BgT28资讯网——每日最新资讯28at.com

既然当--scroll-velocity为0时,就表示滚动停止,那我们是不是可以直接用样式查询来匹配呢?BgT28资讯网——每日最新资讯28at.com

@container - CSS: Cascading Style Sheets | MDN (mozilla.org)[1]BgT28资讯网——每日最新资讯28at.com

BgT28资讯网——每日最新资讯28at.com

CSS 样式查询是容器查询的一部分,从名称也可以看出,它可以查询元素的样式,进而设置额外的样式。比如默认是隐藏的。BgT28资讯网——每日最新资讯28at.com

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

当匹配到--scroll-velocity:0时,显示这个悬浮按钮,就可以这样来实现。BgT28资讯网——每日最新资讯28at.com

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

效果如下:BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

好像并没有起效果?其实和前面的动画原理差不多,这是一个CSS自定义变量,无法直接检测到变化的值。这里有一个解决方案,为了保证能够样式查询到,需要用@property注册一下:BgT28资讯网——每日最新资讯28at.com

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

这样就能完美检测了。BgT28资讯网——每日最新资讯28at.com

BgT28资讯网——每日最新资讯28at.com

你也可以访问线上链接来查看实际效果。BgT28资讯网——每日最新资讯28at.com

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

是不是非常简单?BgT28资讯网——每日最新资讯28at.com

三、CSS 变量计算

除了使用样式查询外,我们还可以用CSS变量的计算方式来实现。BgT28资讯网——每日最新资讯28at.com

什么意思呢?比如我们想知道是否在滚动,其实就是两个状态,那能不能用0和1来表示是否在滚动呢?那就需要做一点点变换了。BgT28资讯网——每日最新资讯28at.com

现在--scroll-velocity表示差值,范围可能是-50~50,那如何转换成1~0呢,很简单,直接除以自身就行了, 比如-50/-50和50/50结果都是1,有人会奇怪0/0会不会无限大,没关系,这里CSS计算的结果还是0,实现如下:BgT28资讯网——每日最新资讯28at.com

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

这样的话,我们就无需样式查询来改变右下角悬浮按钮的状态了,直接用--scroll-dynamic来控制transformBgT28资讯网——每日最新资讯28at.com

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

看看效果:BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

不一样的实现也能得到相同的效果,你也可以访问线上链接来查看实际效果。BgT28资讯网——每日最新资讯28at.com

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

除了可以得到是否在滚动,还能计算得到滚动方向,比如1表示向下,-1表示向上,我们可以这样来计算。BgT28资讯网——每日最新资讯28at.com

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));}

看似有点复杂,其实也不难理解。比如当前差值是-30,那么,我们可以通过乘以-1,然后取两者较大值,这样就能得到绝对值了。BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

上面其实是个“偏方”,关于绝对值,其实已经有CSS abs()了,只是现在还没有支持,相信以后就能用上了。BgT28资讯网——每日最新资讯28at.com

BgT28资讯网——每日最新资讯28at.com

然后用原值除以这个绝对值,就能得到1或者-1了。BgT28资讯网——每日最新资讯28at.com

利用这个特性,我们可以在不同的方向改变箭头的指向。BgT28资讯网——每日最新资讯28at.com

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

效果如下:BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

你也可以访问线上链接来查看实际效果:BgT28资讯网——每日最新资讯28at.com

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

四、更多有趣的案例

除了上面几个应用,我还找了几个有趣的案例。BgT28资讯网——每日最新资讯28at.com

比如下面这种虫洞效果,在水平或者垂直方向滚动时,会有明显的透视效果https://codepen.io/bramus/pen/wvRqVBmBgT28资讯网——每日最新资讯28at.com

BgT28资讯网——每日最新资讯28at.com

图片图片BgT28资讯网——每日最新资讯28at.com

再比如这种上下滚动,可以看到不同方向上内容的倾斜角度不一样,而且滚动越快,倾斜越大:https://codepen.io/bramus/pen/OJrxBaLBgT28资讯网——每日最新资讯28at.com

BgT28资讯网——每日最新资讯28at.com

图片BgT28资讯网——每日最新资讯28at.com

还有一个比较简单实用的运动模糊滚动,也就是在滚动时,页面会有模糊的效果:https://codepen.io/bramus/pen/XWoREjvBgT28资讯网——每日最新资讯28at.com

BgT28资讯网——每日最新资讯28at.com

BgT28资讯网——每日最新资讯28at.com

五、最后总结一下

说了这么多,核心原理其实就这么几行,如下:BgT28资讯网——每日最新资讯28at.com

@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));}

其实原理还是比较好理解的,下面总结一下:BgT28资讯网——每日最新资讯28at.com

  1. 首先用CSS自定义变量--scroll-position实现一个从0到100的动画,注意需要用@property注册。
  2. 然后用CSS滚动驱动动画将其关联,实现在滚动的时候变量自动变化。
  3. 接着再定义一个相同动画的变量--scroll-position-delayed,并设置过渡时间,这样就会比--scroll-position变化的慢一点。
  4. 将这两个变量相减可以得到差值--scroll-velocity。
  5. 通过这个差值--scroll-velocity就能获得各种状态了。
  6. 当--scroll-velocity为0时,表示滚动停止,否则表示正在滚动中。
  7. 当--scroll-velocity大于0时,表示滚动方向为下。
  8. 当--scroll-velocity小于0时,表示滚动方向为上。
  9. 还可以从--scroll-velocity的绝对值上考虑,绝对值越大,表示滚动速度越快,反之则越慢。
  10. 可以通过样式查询来匹配各种条件,不过需要用@property注册。
  11. 通过 CSS calc 和 max计算可以得到更多状态,比如滚动方向。
  12. 然后就是实际的运用了。

本文链接:http://www.28at.com/showinfo-26-96976-0.html纯 CSS 检测滚动的速度和方向

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 我们一起聊聊如何通过流式渲染提升用户体验?

下一篇: 精选:15款顶尖Python知识图谱(关系网络)绘制工具,数据分析的强力助手

标签:
  • 热门焦点
  • 2023年Q2用户偏好榜:12+256G版本成新主流

    2023年Q2用户偏好榜:12+256G版本成新主流

    3月份的性能榜、性价比榜和好评榜之后,就要轮到2023年的第二季度偏好榜了,上半年的新机潮已经过去,最明显的肯定就是大内存和存储的机型了,另外部分中端机也取消了屏幕塑料支架
  • 6月iOS设备好评榜:第一蝉联榜首近一年

    6月iOS设备好评榜:第一蝉联榜首近一年

    作为安兔兔各种榜单里变化最小的那个,2023年6月的iOS好评榜和上个月相比没有任何排名上的变化,仅仅是部分设备好评率的下降,长年累月的用户评价和逐渐退出市场的老款机器让这
  • 三言两语说透设计模式的艺术-简单工厂模式

    三言两语说透设计模式的艺术-简单工厂模式

    一、写在前面工厂模式是最常见的一种创建型设计模式,通常说的工厂模式指的是工厂方法模式,是使用频率最高的工厂模式。简单工厂模式又称为静态工厂方法模式,不属于GoF 23种设计
  • 服务存储设计模式:Cache-Aside模式

    服务存储设计模式:Cache-Aside模式

    Cache-Aside模式一种常用的缓存方式,通常是把数据从主存储加载到KV缓存中,加速后续的访问。在存在重复度的场景,Cache-Aside可以提升服务性能,降低底层存储的压力,缺点是缓存和底
  • 自律,给不了Keep自由!

    自律,给不了Keep自由!

    来源 | 互联网品牌官作者 | 李大为编排 | 又耳 审核 | 谷晓辉自律能不能给用户自由暂时不好说,但大概率不能给Keep自由。近日,全球最大的在线健身平台Keep正式登陆港交所,努力
  • 阿里大调整

    阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的&ldquo;征求意见版&rdquo;:1、取消P序列
  • 2纳米决战2025

    2纳米决战2025

    集微网报道 从三强争霸到四雄逐鹿,2nm的厮杀声已然隐约传来。无论是老牌劲旅台积电、三星,还是誓言重回先进制程领先地位的英特尔,甚至初成立不久的新
  • iQOO Neo8系列或定档5月23日:首发天玑9200+ 安卓跑分王者

    iQOO Neo8系列或定档5月23日:首发天玑9200+ 安卓跑分王者

    去年10月,iQOO推出了iQOO Neo7系列机型,不仅搭载了天玑9000+,而且是同价位唯一一款天玑9000+直屏旗舰,一经上市便受到了用户的广泛关注。在时隔半年后,
  • 三翼鸟智能家居亮相电博会,让用户体验更真实

    三翼鸟智能家居亮相电博会,让用户体验更真实

    2021电博会在青岛国际会展中心开幕中,三翼鸟直接把“家”搬到了现场,成为了展会的一大看点。这也是三翼鸟继9月9日发布了行业首个一站式定制智慧家平台后的
Top