iOS 与 惯性滚动
注:以下所有例子均 只 在 iOS 的微信中测试过,但对于饿了么APP的内置浏览器同样适用(两者使用相同内核)
引题
工作中常常有需要显示大量信息的情况,列表超出一屏就涉及到滚动的问题。例如
- var n = 1
ul
while n <= 100
li= n++
在 iOS 中用微信打开,滚动非常顺滑,so far so good!但某天产品需求有变,要求加一个固定在头部的标题,于是改成这样:
- var n = 1
h1= "Momentum Scrolling on iOS"
ul
while n <= 100
li= n++
body, ul {
margin: 0;
}
html, body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
}
h1 {
flex-shrink: 0;
}
ul {
flex: 1;
overflow: scroll;
}
直接用 flex 盒模型实现,动态适应标题的高度,很简单不是么。但是这时在 iOS 上打开后测试,发现有问题,下半部分区域滚动起来感觉很不顺滑,用老板的话说就像“卡齿轮”
这时就有大牛推荐了传说中的神器:-webkit-overflow-scrolling: touch
ul {
flex: 1;
overflow: scroll;
-webkit-overflow-scrolling: touch;
}
很简单的一个属性,顺滑滚动效果就回来了!虽然不太明白是怎么回事,解决问题就好。 但是产品经理又说了,需要在滚动时获取滚动条的位置做些其他操作。太简单了,加个 scroll
事件搞定。
document.querySelector('ul').addEventListener('scroll', function() {
this.previousElementSibling.textContent = 'ScrollTop: ' + this.scrollTop;
})
随手写好在浏览器中测试通过,然而在手机上测试就不太对劲:那个值是会变,然而滚动的时候不变,只有在滚动结束后变一次。
整个滚动过程中 scroll 事件只在滚动结束后会被触发一次,问题是出在这个所谓的神器 -webkit-overflow-scrolling
上面
-webkit-overflow-scrolling 究竟是什么鬼?
一个只有 iOS 设备支持的非标准属性。苹果自己的解释:指定是否在 overflow: scroll
的元素中使用“原生”的滚动方式
他包含两个可选值:auto
和 touch
- auto:就是普通的无惯性滚动效果
- touch:原生的滚动效果。使用此效果会构造一个 stacking context
什么是 stacking context
?这可以说是CSS里一个阴暗面,极其晦涩。有兴趣的朋友可以去看高人的解释,这里不做讨论(其实笔者自己也不是非常明白:cry:),总之所有的坑都是由此而起。
-webkit-overflow-scrolling 引发了那些坑?
下面列出我遇到过的坑:
滚动中 scrollTop 属性不会变化。
严格来说,上面的 scroll 事件不触发只是本坑的一个副作用,所以说不必考虑通过 touchmove
事件转发 scroll
事件等点子,scroll
事件触发了一样检测不到 scrollTop
属性的变化(当然检测手指的移动距离另说)。同样,检测滚动区域内部元素的 getBoundingClientRect
同样无效。
例中起了一个无限的rAF循环不停地获取 scrollTop
的值,然并卵。
手势可穿过其他元素触发元素滚动
这个更奇葩。例中用一个半透明的 div
盖在了滚动区域 ul
上面(实践中可能是一个弹框的背部蒙版),甚至给 ul
自己加上了 pointer-events: none
,手指在 div
上滑动仍然会触发 ul
的滚动。你可以在显示半透明蒙版时将 ul
的 -webkit-overflow-scrolling: touch
或 overflow: scroll
去掉,但是会造成屏幕明显的闪烁。如果给 body
的 touchmove
事件 preventDefault()
可以防止触发滚动,但是是所有滚动区域都会失效。
运行时通过 JS 动态添加元素溢出高度导致滚动失效
Google 上一搜一片,但是笔者没有遇到过,或许在新版本系统中已经修正,这里不展开讨论。
滚动时暂停其他 transition
还有没有其他未踩的坑呢?
……
有没有什么好的解决方案
使用 WKWebView
替换 UIWebView
内核
可能有些读者已经发现,scroll
事件不能触发的坑在 iOS Safari 和 iOS Chrome 浏览器中不存在,为什么呢?这里要从 iOS 上浏览器的发展史说起。
由于苹果公司对安全性等原因的考虑,苹果公司静止第三方浏览器在 iOS 设备上使用自己的浏览器的内核,换句话说,使用自己内核的浏览器都被禁止上架 AppStore。各大厂商无奈,于是长久以来,包括 Chrome
在内的所有第三方浏览器,都只是使用 iOS 系统内置的浏览器控件包一层外壳,这个控件就是 UIWebView
。这个 UIWebView
不仅速度差,HTML5 支持率低,占用内存高,还有各种各样奇怪的问题。然而苹果公司却给自己的 Safari 浏览器开了后门。首先 Safari 使用的支持 JIT 编译的 JS 引擎内核 Nitro
比 UIWebView
里老旧的解释性 JavaScriptCore
内核速度搞数倍,然后 HTML5 支持度也比 UIWebView
高,还少了某些奇葩bug。久而久之就形成了 iOS 设备上 Safari 浏览器全面碾压其他第三方浏览器的现象。
在乔帮主撒手人寰不久之后,苹果公司口气终于松动,虽然没有放开第三方浏览器内核的限制,但把 Safari
的浏览器内核提取了出来开放第三方浏览器使用,那就是如今的 WKWebView
(WK 即 Webkit 的缩写)。但由于 WKWebView
只支持 iOS8 以上系统,各大浏览器厂商并未立刻跟进。直到最近的 iOS9 时代,Chrome 成为第一个吃螃蟹的 APP,使用了 WKWebView
内核。测试数据表明,使用 WKWebView
内核的 Chrome 浏览器在速度和 HTML5 支持率上已经与 Safari 浏览器不相上下。紧接着 Mozilla 公司宣布 Firefox 登录 iOS 平台,使用的也是 WKWebView
内核(于是有了第一款基于 Webkit
内核的火狐浏览器 :)
不知苹果做了什么手脚,也许苹果的开发人员认为 WKWebView
的效能已经足以支撑在 scroll
事件中执行额外代码而不造成 UI 卡顿,总之在 WKWebView
内核中滚动可以正常触发 scroll
事件,当然也能正常获得 scrollTop
的值。然而经过测试第二个问题仍然存在。
在这里笔者强烈建议各个 APP 迁移内嵌浏览器至新的 WKWebView
内核。但是就我看到的,包括微信和饿了么在内,几乎所有的国产 APP 都还在使用 UIWebView
内核,这不得不说是一大前端开发之殇。
自己实现一套滚动逻辑
比如前段时间很火的 iScroll,笔者曾近也使用过一段时间。最后得出的结论是:iScroll 挖出的坑不比它填上的坑少,比如在 iScroll 里加个 click
事件都要小心翼翼、特别对待(因为绝大多数情况绑定 touch
事件的回调函数里第一件做的事情就是 preventDefault
)。
最值得一提的是 iScroll 的速度问题,比原生实在相差太多,在中低端安卓机型上卡顿明显,如果还要绑定 scroll
事件做些别的事情就更卡了。
总之笔者并不建议使用。
放弃 H5,拥抱 Native
也许这才是真正的终极解决之道
iOS 与 惯性滚动的更多相关文章
- H5手机开发锁定表头和首列(惯性滚动)解决方案
前端时间移动端在做表格的时候需要这个功能,由于还有实现类似原生的惯性滚动功能,于是使用了iscroll插件. iscroll插件下载地址:iscroll5 该功能demo github地址: http ...
- 源生js惯性滚动与回弹效果
在写移动端的APP或者页面时,经常会遇到惯性滚动与回弹效果.用插件iscroll可以轻松解决这个问题,大多数的移动框架也能轻松解决这个问题,它们内部都封装了这个效果. 一直好奇这个效果原生JS是怎么实 ...
- ios固定高度禁止惯性滚动
最近测试pad改H5的项目时,固定高度的div,超出部分滚动,但在ios下滑动特别卡顿,安卓上没问题.搜索找到解决办法 固定高度的div设置超出页面滚动,ios会出现卡顿,非常不爽.通过下面css就可 ...
- iOS用contenteditable滚动时,光标不会刷新定位的处理方法
分析 iOS的 wkwebview 在滚动时会暂停许多动画,作为优化 解决思路 监听滚动事件,利用文档重绘即可刷新动画 ps:因为滚动有惯性,touchmove事件只能监听到手指松开的那一刻,所以只能 ...
- iOS无限循环滚动scrollview
经常有园友会问"博主,有没有图片无限滚动的Demo呀?", 正儿八经的图片滚动的Demo我这儿还真没有,今天呢就封装一个可以在项目中直接使用的图片轮播.没看过其他iOS图片无限轮播 ...
- iOS开发-网易滚动导航栏
HACursor,是一个对横向ScrollView中的视图进行管理的UI控件.只要几行代码就可以集成类似于网易新闻对主题页面进行排序,删除操作的功能.主srollview参考iOS原生的UITable ...
- 处理ios的overflow滚动bug
先说说这个bug的场景 .container{ height:100vh; overflow-y:scroll; } 没毛病,总有这种类似的情况,需要在容器内滚动,但是!这种容器内的滚动在ios上面处 ...
- [iOS] UICollectionView初始化滚动到中间的bug
转载请保留地址wossoneri.com 问题 首先看一下我之前写的demo:link demo是封装了一个控件,直接在MainViewController的viewWillAppear里初始化,并且 ...
- iOS学习笔记——滚动视图(scrollView)
滚动视图:在根视图中添加UIScrollViewDelegate协议,声明一些对象属性 @interface BoViewController : UIViewController<UIScro ...
随机推荐
- HTML <input type="file">上传文件——结合asp.net的一个文件上传示例
HTML的代码:(关键是要在form里设置enctype="multipart/form-data",这样才能在提交表单时,将文件以二进制流的形式传输到服务器) 一. <fo ...
- 项目vue2.0仿外卖APP(六)
goods 商品列表页开发 布局编写 除了商品之外还有购物车,还有个详情页,挺复杂的. 两栏布局:左侧固定宽度,右侧自适应,还是用flex. 因为内容可能会超过手机高度,超过就隐藏.左右两侧的内容是可 ...
- static修饰符
static修饰符表示静态的,可修饰字段.方法.内部类,其修饰的成员属于类,也就是说static修饰的资源属于类级别,而不是对象级别. static的正真作用:用来区别字段,方法,内部类,初始化代码块 ...
- TI PDK3.0 qt 交叉编译环境设置
上午剑锋给的方法,成功在qtcreator上面加入TI官方的qmake以及他的交叉编译器. 1. 步骤如下: 1. 我假设TI PDK3.0 安装目录为顶层目录. 2. 进入linux-devkit ...
- Archlinux安装MySQL5.7.14压缩包版
现在Arch官方源里是MariaDB,MySQL扔到AUR里去了...感觉还是自己安装好些... (参考资料:度娘.官方文档) 贴配置: lts版的 在Vbox虚拟机测试 按照官方文档的安装步骤: 创 ...
- pullToRefreshListView的简单使用
1.加入library后直接布局 library下载地址:http://pan.baidu.com/s/1dFJu8pF <com.handmark.pulltorefresh.library. ...
- Django(4)html模板继承、模板导入、分页实现
1.获取所有请求信息 导入模块:from django.core.handlers.wsgi import WSGIRequest request.environ:包含所有的请求信息,可以打印看一下, ...
- Unity3D 计算FPS
using UnityEngine; using System.Collections; public class FPS : MonoBehaviour { private const string ...
- Python之Web前端jQuery扩展
Python之Web前端: 一. jQuery表单验证 二. jQuery扩展 三. 滚动菜单 一. jQuery表单验证: 任何可以交互的站点都有输入表单,只要有可能,就应该对用户输入的数据进行验证 ...
- tp5 model 中的查询范围(scope)
查询范围scope在model中定义,在controller中使用 namespace app\index\model; use think\Model; class User extends Mod ...