这篇文章发布于 2020年10月26日,星期一,01:05,归类于 Mobile相关, Web综合。 阅读 26569 次, 今日 26 次 6 条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9621
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。
iOS Safari浏览器下的focus行为和其他浏览器都一些明显不一致的地方,有时候会给开发带来困扰,这里就说说相关的细节知识,均源自于自己日常开发遇到的问题。
一、button点击无法focus
:focus-within
伪类是一个非常实用的CSS伪类,详见我张鑫旭2年前写的这篇文章“详细了解CSS :focus-within伪类及其交互应用”。
这个伪类在Chrome和Firefox浏览器下使用非常OK,但是在Safari浏览器下却有坑,链接和按钮明明点击了,却不能触发祖先元素的:focus-within
伪类匹配。
千万不要认为是Safari浏览器不支持:focus-within
伪类,Safari浏览器支持很多年了,兼容性如下图所示。
那为何Safari浏览器下没有效果呢?
原因就在于Safari浏览器下,<a>
链接元素和<button>
按钮元素在点击的时候,是不会有focus
状态的。
我猜测是Safari浏览器不希望按钮或链接点击的时候有focus轮廓才这么设计的,但是,显然这种一刀切的做法就不如Chrome和Firefox浏览器处理的好,在Chrome浏览器下,默认状态下,按钮和链接在点击的时候是不会有outline
轮廓的,只有键盘访问的时候才有,兼顾视觉和无障碍访问。
那有没有什么办法让Safari浏览器下的链接和按钮在点击的时候也能响应:focus
伪类呢?
<a>
链接focus
要想让Safari浏览器下<a>
链接元素在点击后保持focus状态,可以是设置tabindex="0"
,如下所示:
<a href tabindex="0">点击我</a>
tabindex="0"
不会影响链接元素原本的索引顺序,千万不要设置tabindex
属性为其他值,具体原因详见我写的这篇文章:“HTML tabindex属性与web网页键盘无障碍访问”。
<button>
按钮focus
要想让Safari浏览器下<button>
按钮元素在点击后保持focus状态,目前是没有什么有效方法的。
MDN文档中对于<button>
按钮元素的点击和聚焦的关系有专门的整理,具体参见下表。
桌面浏览器 | Windows 8.1 | OS X 10.X |
---|---|---|
Firefox | Yes – Firefox 30.0 | No (即使使用 tabindex ) Firefox 63 |
Chrome | Yes – Chrome 35 | Yes – Chrome 65 |
Safari | N/A | No (即使使用tabindex ) Safari 12 |
Internet Explorer | Yes – Internet Explorer 11 | N/A |
Presto | Yes – Opera 12 | Yes – Opera 12 |
手机浏览器 | iOS 7.1.2 | Android 4.4.4 |
---|---|---|
Safari Mobile | No (即使使用tabindex ) |
N/A |
Chrome 35 | No (even with a tabindex ) |
Yes |
因此,如果大家要使用:focus-within
伪类,同时需要兼容Safari浏览器,请使用<a>
标签按钮代替<button>
标签按钮。
//zxx: 如果你看到这段文字,说明你现在访问是体验糟糕的垃圾盗版网站,你可以访问原文获得很好的体验:https://www.zhangxinxu.com/wordpress/?p=9621(作者张鑫旭)
二、focus无法失焦blur事件不触发
例如如下代码所示的<a>
元素再点击之后会被focus,但是此时你再点击页面空白区域,该元素是不会失焦的,也就是不会blur。
<a href tabindex="0">点击我</a>
这个现象只会出现在iOS Safari浏览器下,微信和原生Safari浏览器都会遇到这个体验问题。
我专门做了个demo演示这个问题,您可以狠狠地点击这里:iOS Safari blur无法触发demo
此demo需要在iOS Safari浏览器下访问,因为如果是PC电脑,可以拿出手机打开微信扫一扫进行体验:
此时,点击demo页面的链接(有时候需要点击2次),就会看到下拉浮层出现了,如下截图所示:
相关CSS代码如下所示:
.drop-panel { display: none; position: absolute; border: 1px solid #ccc; background-color: #fff; padding: 12px 20px; } :focus + .drop-panel { display: block; }
但是,在iPhone手机下,或者iPad下,浮层出现后,你点击旁边白色的空白区域,浮层死活都不隐藏,导致:focus
伪类交互就出现了问题。
这就是这一小节要说明的focus无法失焦blur事件不触发的问题。
补充于翌日: 上面blur不触发我在iOS 12下测试是存在的,然后今天收到反馈,iPhone 12,iOS 14点击空白处可以隐藏,因此,iOS可能在后续的版本优化了这个交互细节。
实际上,blur失焦是可以触发的,就是当我们点击其他控件元素的时候,比方说浮层显示之后,我们点击的不是空白区域,而是按钮元素、或者是其他链接元素,或者输入框元素,则:focus
会失焦,blur时间会触发,也就是焦点不能消失,只能转移。
有没有什么办法让iOS Safari浏览器下的可以点击空白区域也失焦呢?
可以有。
就是找到层级足够高的祖先元素(不能是<body>
元素,可以是<body>
子元素),然后设置tabindex=-1
,任意的非控件HTML元素在设置了tabindex=-1
属性后,点击的时候是会有focus状态的。
也就是点击空白区域,会把原本附着在链接上的焦点转移到祖先元素上,于是blur失焦就正常触发了。
例如demo页面中的这个按钮点击后,就会给一个祖先元素设置tabindex=-1
。
此时再去点击上面的链接,就会发现此时点击页面空白,出现的浮层正常消失了。
三、focus()方法有时候无效
有这么一种交互需求,就是点击某个按钮,创建了一个新的输入框,希望这个输入框在创建之后就立即被focus呼起输入软键盘。
然后在iOS Safari浏览器下有时候就会出现 input.focus()
无效的情况。
首先明确一点,iPhone浏览器中直接input.focus()
是可以有效的,但是需要有个前提,就是在点击事件中,而且是要在点击事件这个线程中。
也就是直接input.focus()
是无法让输入框focus的,但是写在click事件中是有效的,例如:
button.addEventListener('click', function () {
// zhangxinxu: 有效
input.focus();
});
注意,并不是说input.focus()
语句写在click事件中就是有效的。
例如在Vue等框架中,DOM的渲染是数据驱动的,因此,往往会在click事件中进行数据变化,而此时的DOM渲染实在click事件之后执行的,因此,开发者自然而然会想到使用定时器进行处理。
如下所示:
button.addEventListener('click', function () {
someDataChange();
// zhangxinxu: 无效
setTimeout(function () {
input.focus();
}, 1);
});
此时focus行为就不会触发是无效的,因为加了定时器,focus行为已经不和click在一个执行线程中,处于安全和体验的考虑,iOS系统就没有让输入框focus聚焦。
知道了原因问题就好解决了。
比方说click事件更新的是是否focus的标志量,然后在Vue的updated方法中进行focus聚焦,代码示意如下:
// 新增数据 this.xxxData.push({ type: type, content: 'zhangxinxu.com' }) // 标志量变化 document.isFocusAfterUpdated = true
updated()
方法中:
if (document.isFocusAfterUpdated) {
input.focus()
// focus标志量还原
document.isFocusAfterUpdated = false
}
四、小结一下
我目前遇到的iOS Safari浏览器下focus行为相关的“坑爹”行为有3个:按钮元素无法被focus、控件元素focus后可能无法失焦以及focus()聚焦可能无行为发生。
每个问题都提供了相关的指导建议。
Safari可能还有其他和focus相关的坑,欢迎大家补充。
OK,以上就是本文的全部内容,希望可以对你的工作有所帮助。
感谢阅读,欢迎分享!
本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=9621
(本篇完)
- 详细了解CSS :focus-within伪类及其交互应用 (0.236)
- CSS :placeholder-shown伪类实现Material Design占位符交互效果 (0.236)
- 小tips: 元素focus页面不滚动不定位的JS处理 (0.236)
- CSS touch-action简介与treated as passive错误解决 (0.227)
- 完善:HTML5表单新特征简介与举例 (0.196)
- PhoneGap/Cordova控制iOS7状态栏的显隐/颜色 (0.196)
- CSS :focus-visible伪类让我感动哭了 (0.150)
- 使用CSS将图片转换成模糊(毛玻璃)效果 (0.118)
- 3种纯CSS实现中间镂空的12色彩虹渐变圆环方法 (0.118)
- FDCon2019大会分享之滤镜与混合模式实录 (0.118)
- letter-spacing+first-letter实现按钮文字隐藏 (RANDOM - 0.084)
正好最近遇上了这个 bug,一搜就搜到大佬的文章,写得太好了!
很棒,研究得很仔细,感谢!
还有input元素readonly的时候focus该元素,不会触发滚动,使改元素进入视野
:focus-within + :focus 能够支持得更好一点,就能 纯 css 的实现点击显示下拉菜单,点击外面隐藏下拉菜单的功能了。
focus()方法无效这个问题好像和ios系统版本还是手机型号有关,
就我试的几个,ios10 Ipone6 会出现这个bug,ios14 iPhonexr, iPhone11是可以正常focus的
大佬也开始用Vue了吗