5

细说iOS Safari下focus的行为

 3 years ago
source link: https://www.zhangxinxu.com/wordpress/2020/10/ios-safari-input-button-focus/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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浏览器支持很多年了,兼容性如下图所示。

:focus-within伪类最新的兼容性

那为何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>按钮元素的点击和聚焦的关系有专门的整理,具体参见下表。

是否点击按钮元素可以focus 桌面浏览器 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 是否轻触按钮元素可以被focus 手机浏览器 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>标签按钮。

二、focus无法失焦blur事件不触发

例如如下代码所示的<a>元素再点击之后会被focus,但是此时你再点击页面空白区域,该元素是不会失焦的,也就是不会blur。

<a href tabindex="0">点击我</a>

这个现象只会出现在iOS Safari浏览器下,微信和原生Safari浏览器都会遇到这个体验问题。

我专门做了个demo演示这个问题,您可以狠狠地点击这里:iOS Safari blur无法触发demo

此demo需要在iOS Safari浏览器下访问,因为如果是PC电脑,可以拿出手机打开微信扫一扫进行体验:

demo页面二维码

此时,点击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,以上就是本文的全部内容,希望可以对你的工作有所帮助。

感谢阅读,欢迎分享!

2764.svg

(本篇完)1f44d.svg 是不是学到了很多?可以分享到微信
1f44a.svg 有话要说?点击这里


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK