这篇文章发布于 2019年09月19日,星期四,00:02,归类于 JS API。 阅读 28526 次, 今日 6 次 14 条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=8972
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。
一、问题的由来
有时候我们希望元素被focus的时候页面不发生滚动,例如我们点击一个按钮打开一个弹框,此时点击弹框中的关闭按钮隐藏弹框后,希望键盘的焦点回到之前的按钮上,我们就会执行如下JavaScript代码:
button.focus();
但是有时候会带来另外一个比较严重的体验问题,那就是如果弹框显示之后我们页面发生了滚动,原本点击的按钮跑到了屏幕显示区域之外,这个时候,按钮再次focus的时候就会触发按钮元素scrollIntoView重定位,浏览器发生滚动,表现为突然的跳动,体验很不好。
我们预期的目标是:按钮focus,然后无论按钮在不在屏幕显示区内,都不会发现浏览器的滚动重定位。
如何实现呢?
二、全新的API参数preventScroll
如果想要聚焦同时不发生滚动,其实很简单,使用一个全新的API参数preventScroll就可以了,例如:
button.focus({ preventScroll: true });
preventScroll
是一个可选参数,默认值是false
,表示不阻止聚焦滚动。如果preventScroll
参数值是true
则表示只聚焦不滚动。
我们来看一个例子,您可以狠狠地点击这里:JS focus preventScroll参数使用demo
demo页面有两个按钮,一个按钮点击直接focus,另外一个是设置了{preventScroll:true}
。
结果最终的效果如下GIF录屏所示:
兼容性
preventScroll
参数兼容性如下表:
64+ ✔ | 68+ ✔ | ✘ | ✘ | 51+ ✔ | ❓ |
手头没有Safari浏览器,因此兼容性不详,欢迎大家反馈。
三、IE浏览器下的处理
IE浏览器不支持这个非常棒的API,如果我们要让这个浏览器支持怎么办呢?
方法一:放弃IE/Edge
IE/Egde连自己都放弃自己投奔Chrome了,我们还有什么理由支持他呢!
方法二:polyfill
这里有个人写了个focus的polyfill:https://github.com/calvellido/focus-options-polyfill
然而,根据我在IE浏览器下的实地使用,有坑,效果很奇怪,因此,上面这个polyfill不建议使用。
方法三:临时补丁
拿垂直滚动距离,我们可以这样JS处理:
var y = window.pageYOffset;
button.focus({
preventScroll: true
});
// IE浏览器的处理
if (window.pageYOffset != y) {
setTimeout(function () {
document.documentElement.scrollTop = y;
}, 0)
}
但此方法并不完美,有一定概率页面会抖一下。
我在实际项目中的处理方法就是方法一,直接忽略IE浏览器,即使项目要兼容IE浏览器,毕竟是体验增强的东西,使用IE浏览器的用户能够忍受的糟糕体验要比我们预想的大的多,因为IE浏览器本身就是个体验糟糕的产品。
四、短文也要结束语
focus()
方法的API在文档中都是写作HTMLElement.focus(),说明所有的HTML元素都有focus方法,因为虽然普通元素默认是不能被focus的,但是如果我们设置合适的tabindex
属性值,情况就会发生变化,可以被focus,更多更深入更有趣知识可以参见这篇文章:“HTML tabindex属性与web网页键盘无障碍访问”。
因此,我们直接下面这样使用都是不会报错的:
document.body.focus(); document.createElement('div').focus();
但是如果是其他方法,例如submit
就会报错:
// 会出错,不支持
document.body.submit();
document.createElement('div').submit();
好,就说这么多,比原本预计的多写了半小时。
本文为原创文章,欢迎分享,勿全文转载,如果内容你实在喜欢,可以加入收藏夹,永不过期,而且还会及时更新知识点以及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=8972
(本篇完)
- 尝试使用JS IntersectionObserver让标题和导航联动 (0.450)
- 细说iOS Safari下focus的行为 (0.395)
- 完善:HTML5表单新特征简介与举例 (0.330)
- 来了来了,scrollend滚动停止事件也支持了 (0.285)
- 还算有点用的scrollTo和scrollBy两个JS API (0.247)
- CSS scroll-behavior和JS scrollIntoView让页面滚动平滑 (0.234)
- 小tip: 子元素scroll父元素容器不跟随滚动JS实现 (0.203)
- CSSOM视图模式(CSSOM View Module)相关整理 (0.165)
- 几个常见功能重合DOM API的细节差异 (0.165)
- 小tips: 滚动容器尺寸变化子元素视觉上位置不变JS实现 (0.162)
- 小tip:我是如何初体验uglifyjs压缩JS的 (RANDOM - 0.031)
https://caniuse.com/#search=HTMLElement%20API%3A%20focus%3A%20preventScroll
Safari不支持
幸好 IE/Egde 连自己都放弃自己。不然依然要混沌下去。
Safari 浏览器 版本 13.0.1 (14608.2.11.1.11)
不支持
好的,感谢反馈!
赞?
学到
get
问大神个问题。
移动端html5页面有个图片,点击图片图片全屏显示(后面有蒙板),然后可以手动2指放大。点击右上角X可以关闭图片全屏查看(同时隐藏蒙板)。
现在问题是:关闭预览的图片后,原页面也被放大了。
有没有办法在关闭图片预览时,将原页面恢复到默认devide-width的大小?我试过修改meta或使用transform都不行。
没研究过~这个需求谁提的呀,建议是忽略。或者自己实现而不使用浏览器的行为。
记得H5网页有个neta标签可以设置缩放和放大比例
Safari 12.1 (14607.1.40.1.4) 不支持
Safari13不支持
o
讲道理移动端需要滚动,因为键盘弹出来了? ?