前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【总结】1823- 移动端滚动穿透与滚动溢出解决方案

【总结】1823- 移动端滚动穿透与滚动溢出解决方案

作者头像
pingan8787
发布于 2023-10-04 13:27:08
发布于 2023-10-04 13:27:08
67300
代码可运行
举报
文章被收录于专栏:前端自习课前端自习课
运行总次数:0
代码可运行
滚动穿透

问题描述

在移动端 WEB 开发的时候(小程序也雷同),如上录屏所示,如果页面超过一屏高度出现滚动条时,在 fixed 定位的弹窗遮罩层上进行滑动,它下面的内容也会跟着一起滚动,看起来好像事件穿透到下面的DOM元素上一样,我们姑且称之为滚动穿透。

问题原因

能够猜想是文档(document)的滚动事件被触发了,如果能禁用滚动事件就好办了。

案例伪代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div class="btn">点击出现弹窗</div>

<div class="popup">
  <div class="popup-mask"></div>
  <div class="popup-body popup-bottom">
    <div class="header">我是标题</div>
    <div class="content">
      <div>0</div>        
      <div>1</div>
      <div>...</div>
    </div>
  </div>
</div>
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.popup-mask {
  background-color: rgba(0, 0, 0, 0.5);
  position: fixed;
  z-index: 998;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

.popup-body {
  padding: 0 50px 40px;
  background-color: #fff;
  position: fixed;
  z-index: 999;
}

✅ 解决方案A (touch-action)

默认情况下,平移(滚动)和缩放手势由浏览器专门处理,但是可以通过 CSS 特性 touch-action 来改变触摸手势的行为。摘取几个 touch-action 的值如下。

描述

auto

启用浏览器处理所有平移和缩放手势。

none

禁用浏览器处理所有平移和缩放手势。

manipulation

启用平移和缩放手势,但禁用其他非标准手势,例如双击缩放。

pinch-zoom

启用页面的多指平移和缩放。

于是在 popup 元素上设置该属性,禁用元素(及其不可滚动的后代)上的所有手势就可以解决该问题了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.popup {
  touch-action: none;
}

Note: [无障碍设计] 阻止页面缩放可能会影响视力不佳的人阅读和理解页面内容,不过小程序本身好像就不可以缩放!

✅ 解决方案B (event.preventDefault)

来自 W3C 的一个标准。

大意是说,在 touchstart 和 touchmove 事件中调用 preventDefault 方法可以阻止任何关联事件的默认行为,包括鼠标事件和滚动。

因此我们可以这样处理。 Step 1、监听弹窗最外层元素(popup)的 touchmove 事件并阻止默认行为来禁用所有滚动(包括弹窗内部的滚动元素)。 Step 2、释放弹窗内的滚动元素,允许其滚动:同样监听 touchmove 事件,但是阻止该滚动元素的冒泡行为(stopPropagation),使得在滚动的时候最外层元素(popup)无法接收到 touchmove 事件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const popup = document.querySelector('.popup')
const scrollBox = document.querySelector('.content')

popup.addEventListener('touchmove', (e) => {
  // Step 1: 阻止默认事件
  e.preventDefault()
})

scrollBox.addEventListener('touchmove', (e) => {
  // Step 2: 阻止冒泡
  e.stopPropagation()
})

滚动溢出

问题描述

如上录屏所示,弹窗内也含有滚动元素,在滚动元素滚到底部或顶部时,再往下或往上滚动,也会触发页面的滚动,这种现象称之为滚动链(scroll chaining), 但是感觉滚动溢出(overscroll)这个名字更言辞达意。

❌ 解决方案A (overscroll-behavior)

overscroll-behavior 是 CSS 的一个特性,允许控制浏览器滚动到边界的表现,它有如下几个值。

描述

auto

默认效果,元素的滚动可以传播到祖先元素。

contain

阻止滚动链,滚动不会传播到祖先元素,但是会显示节点自身的局部效果。例如 Android 上过度滚动的发光效果或 iOS 上的橡皮筋效果。

none

与 contain 相同,但是会阻止自身的过度效果。

所以可以这样解决问题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.content {
  overscroll-behavior: none;
}

简洁干净高性能,不过 Safari 全系不支持,兼容性如下,有没有感觉 Safari 就是现代版的 IE(偶然听路人说的)!

✅ 解决方案B (event.preventDefault)

借用 event.preventDefault 的能力,当组件滚动到底部或顶部时,通过调用 event.preventDefault 阻止所有滚动,从而页面滚动也不会触发了,而在滚动之间则不做处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let initialPageY = 0

scrollBox.addEventListener('touchstart', (e) => {
    initialPageY = e.changedTouches[0].pageY
})

scrollBox.addEventListener('touchmove', (e) => {
    const deltaY = e.changedTouches[0].pageY - initialPageY
    
    // 禁止向上滚动溢出
    if (e.cancelable && deltaY > 0 && scrollBox.scrollTop <= 0) {
        e.preventDefault()
    }

    // 禁止向下滚动溢出
    if (
        e.cancelable &&
        deltaY < 0 && 
        scrollBox.scrollTop + scrollBox.clientHeight >= scrollBox.scrollHeight
    ) {
        e.preventDefault()
    }
})

解决方案完整 Demo

https://github.com/Barrior/cases/blob/main/overscroll.html

作者:Barrior https://segmentfault.com/a/1190000040675446

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-10-03 09:33,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端自习课 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
移动端事件穿透的原理与解决方案
移动设备的流行,带动了移动互联网的快速发展,很多开发者开始进入移动开发领域。目前市面上主流的移动设备一般都使用触摸屏,触摸屏所使用的触摸事件模型与传统网页的鼠标事件模型有所区别,这种差异往往使初涉移动端的开发工程师陷入困境,事件穿透问题便是其中一个,本文将带你了解事件穿透及如何在实际项目中选择合适的方案解决事件穿透问题。
用户6167509
2020/07/27
1.5K0
📚一站式解决:H5开发全攻略,看这篇让你省时又省力
在 H5 中,我们通常会使用 REM 和 VW 这两种单位来实现页面的响应式布局。这两种单位可以让页面元素的大小随着根元素(对于 REM)或视口宽度(对于 VW)的大小变化而变化,从而适应不同尺寸的屏幕。
linwu
2023/07/27
1.1K0
移动端点击事件延迟的诞生消亡史
快速反馈对于任何 UI 的实现都是至关重要的。研究表明,100ms 是界面让用户感到即时的最大延迟。尽管如此,移动网络仍然受到一个巨大的反馈问题的困扰:触摸任何元素后,延迟 300 毫秒。这种延迟是许多用户认为基于 HTML 的 Web 应用程序“卡顿”的最重要原因之一。在本文中,本文将带你了解移动端点击事件延迟的从诞生到消亡的过程。
用户6167509
2020/07/25
3K0
【No Problem】如何解决 Mac 左右滚动误触返回事件?
如果 Mac 设置了触控板如下所示,在浏览器中浏览页面的时候,双指不仅可以控制左右滚动,而且可以控制前进后退
GopalFeng
2022/08/01
2.4K0
【No Problem】如何解决 Mac 左右滚动误触返回事件?
控制页面的滚动:自定义下拉到刷新和溢出效果
通过阅读本文,你可以通过css 中overcroll-behavior属性值的设置,处理浏览器溢出滚动,以及禁用移动设备上刷新,下拉滚动时的发光和橡皮圈回弹效果,当然也可以看到css中 Houndini(胡迪宁),也就是css中也可以写变量等知识,如果文有误导的地方,欢迎路过的老师拍砖指正
itclanCoder
2020/10/28
3.6K0
控制页面的滚动:自定义下拉到刷新和溢出效果
蒙层禁止页面滚动的方案
弹窗是一种常见的交互方式,而蒙层是弹窗必不可少的元素,用于隔断页面与弹窗区块,暂时阻断页面的交互。但是在蒙层出现的时候滚动页面,如果不加处理,蒙层底部的页面会开始滚动,实际上我们是不希望他进行滚动的,因此需要阻止这种行为。当弹出蒙层时禁止蒙层下的页面滚动,也可以称为滚动穿透的问题,文中介绍了一些常用的解决方案。
WindRunnerMax
2022/05/06
6.5K0
移动端click事件300ms延迟
一般情况下,如果没有经过特殊处理,移动端浏览器在派发点击事件的时候,通常会出现300ms左右的延迟。也就是说,当我们点击页面的时候移动端浏览器并不是立即作出反应,而是会等上一小会儿才会出现点击的效果。在移动WEB兴起的初期,用户对300ms的延迟感觉不明显。但是,随着用户对交互体验的要求越来越高,现今,移动端300ms的点击延迟逐渐变得明显而无法忍受。
Dawnzhang
2018/12/28
2.8K0
探究 css touch-action 属性
今天在写vue项目的时候碰到一个 Unable to preventDefault inside passive event listener due to target being treated as passive. See <URL> 这样的bug 然后找了一通发现可以用 *{touch-action:none}这个方法 用法是禁用元素(及其不可滚动的后代)上的所有手势,以使用自己提供的拖放和缩放行为(如地图或游戏表面)。 由此找了其他的属性值 发现还挺强大的
河湾欢儿
2018/09/06
1.9K0
Unable to preventDefault inside passive event listener
于是 Google 了一番,找到这篇文章,有了详细解释。Making touch scrolling fast by default
yaphetsfang
2020/07/30
1.4K0
移动端触屏事件
移动端浏览器兼容性较好,我们不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android和 IOS 都有。
星辰_大海
2020/10/09
3K0
移动端触屏事件
学会一行CSS即可提升页面滚动性能
一般情况下 CSS 并不会影响 JS 事件,但有一个 CSS 属性则比较特殊,那就是 pointer-events,它可以用来规避鼠标事件,其中大部分属性值只适用于 SVG(可缩放矢量图形)操作,而我们只需要关注其 none 属性值,该值表示鼠标事件“穿透”该元素并且指定该元素“下面”的任何东西。
茶无味的一天
2022/10/08
3.3K1
学会一行CSS即可提升页面滚动性能
Unable to preventDefault inside passive event listener due to target being treated as passive 怎么办?
原因:google浏览器为了最快速的相应touch事件,做出的改变。 历史:当浏览器首先对默认的事件进行响应的时候,要检查一下是否进行了默认事件的取消。这样就在响应滑动操作之前有那么一丝丝的耽误时间。 现在:google就决定默认取消了对这个事件的检查,默认时间就取消了。直接执行滑动操作。这样就更加的顺滑了。 但是浏览器的控制台就会进行错误提醒了。
全栈程序员站长
2022/11/01
1K0
【移动端】touch事件及穿透事件
2007 苹果推出iphone,浏览器网页在iphone上显示时字体特别小,根本看不清楚
用户9914333
2022/12/14
2.1K0
【移动端】touch事件及穿透事件
一张刮刮卡竟包含这么多前端知识点
刮刮卡是大家非常熟悉的一种网页交互元素了。实现刮涂层的效果,需要借助canvas来实现,想必每个前端工程师都清楚。实现刮刮卡并不难,但其中却涉及很多知识点,掌握这些知识点,有助于我们更深刻理解原理,对于提升举一反三的能力很有帮助。本期以实现刮刮卡为例,分享下如何科学合理地封装函数,并对涉及的相关知识点进行讲解。
Nealyang
2019/12/10
1.4K0
一张刮刮卡竟包含这么多前端知识点
【兼容性】H5滚动穿透解决方案
大家肯定不陌生了,做移动端开发的,肯定都碰到过,比如 我明明滚动的是弹窗,但是底下的 document 却在滚动
神仙朱
2021/12/29
6.3K0
【兼容性】H5滚动穿透解决方案
滚动穿透的6种解决方案【已自测】
在移动端中,如果我们使用了一个固定定位的遮罩层,且其下方的dom结构的宽度|高度超出屏幕的宽度|高度,那么即使遮罩层弹出后铺满了整个屏幕,其下方的dom结构依然可以滚动,这就是大家所说的“滚动穿透”。
xing.org1^
2019/03/22
13.9K1
滚动穿透的6种解决方案【已自测】
网页|利用touch实现下拉刷新
下拉刷新在常见的手机app上大多都有运用。下拉刷新即向下拉重新加载、刷新。下拉刷新在下拉到松手的过程中,经历了三个状态分别是:当前手势滑动位置与初始位置差值大于零时,提示正在进行下拉刷新操作。之后当下拉到一定值时,显示松手释放后的操作提示。最后当下拉到达设定最大值松手时,执行回调,提示正在进行更新操作。如下图则为下拉刷新的实现效果:
算法与编程之美
2020/07/16
1.8K0
网页|利用touch实现下拉刷新
从 antDesign 来窥探移动端“滚动穿透”行为
上述是 MDN 中对于 overscroll-behavior 属性的描述,上述这段话恰恰描述了为什么会发生"滚动穿透"现象。
19组清风
2023/07/31
6650
从 antDesign 来窥探移动端“滚动穿透”行为
「移动端」touch事件,touchEvent对象
随着智能手机普及,有越来越多的手机网页和网页版游戏,手机触摸、移动、旋转等等,多种操作。一般电脑的人机交互靠的是鼠标,而手机用的就是触摸。区别有:
呆呆
2021/09/30
1.2K0
原生 JS 手写一个优雅的图片预览功能,带你吃透背后原理
本文将用一个极简的例子详细讲解如何用原生JS一步步实现完整的图片预览和查看功能,无任何第三方依赖,兼容PC与H5,实现了触屏双指缩放等,干货满满。
茶无味的一天
2022/11/02
3.7K0
原生 JS 手写一个优雅的图片预览功能,带你吃透背后原理
相关推荐
移动端事件穿透的原理与解决方案
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验