【技术博客】移动端的点击事件与Sticky Hover问题
移动端的点击事件与Sticky Hover问题
v1.0
作者:ZBW
TL;DR
解决办法是:在:hover伪类外使用@media区分设备,在移动设备上使hover效果不生效。
@media (hover: hover) {
.desexp-text:hover {
opacity:1;
}
}
这一方法的缺点是问题在带有触控的PC上仍可能存在,但对于大多移动设备来说足以应付了。
前言
笔者起初认为该问题是JS的点击事件绑定有误导致的,但之后却发现问题出在CSS上。因此本文除了解决问题外,也会介绍以下笔者的踩坑历程,顺带介绍一下移动端点击事件的不同。
问题描述
背景
在Beta阶段,团队想要在项目中实现设计性实验复习的页面。该页面的主要使用方式是团队预先在整理好的复习资料中挖一些空,然后用户通过交互来显示/隐藏答案。计划的交互方式是:
鼠标放在空上,答案显示出来。鼠标移开答案消失
鼠标点一下空,答案显示,移开鼠标也不会消失。再次点击将恢复隐藏的状态。
实现一个清空答案的按钮,可以一键清空所有显示的答案。
实现方式
该功能的实现方式非常简单。对于1,直接使用CSS的:hover伪类配合透明度即可解决。对于2和3,可以使用JS来监听点击事件,并且根据点击事件和目前的显示状态对透明度进行切换。
为了实现这一功能,首先我们对所有挖空的文本外套了两个html标签(span和text),并分别以class区分,形如:
<span class='desexp-span'><text class='desexp-text'>被挖空的内容</text></span>
并且分别以如下的CSS和JS实现上述的效果
span.desexp-span {
border-bottom: 1px solid rgb(200, 200, 200);
}
.desexp-text {
opacity:0;
transition: opacity 1s;
-webkit-transition: opacity 1s;
}
.desexp-text:hover {
opacity:1;
}
var inners = document.getElementsByClassName("desexp-text");
var myfunction = function () {
if (this.style.opacity === 1)
this.style.opacity = "";
else
this.style.opacity = 1;
};
for (var i = 0; i < inners.length; i++) {
inners[i].addEventListener('click', myfunction, false);
}
清空答案的按钮实现也很简单(代码中是从iframe内读取内容):
let inners = document.getElementById("desexp-iframe").contentWindow.document.getElementsByClassName("desexp-text");
for (var i = 0; i < inners.length; i++) {
inners[i].style.opacity = "";
}
实现的效果如下:

问题
该实现在PC端的浏览器下表现正常,但当使用手机进行操作时就会出现问题。
在手机上点击挖空的位置,答案显示正常。当再次点击挖空时,答案却不会消失,而如果此时点击另一个空,之前的答案便会消失。除此之外清空答案按钮不起作用。

关于移动端浏览器的点击事件
自第一代iPhone于2007年发布以来,人们在手机上浏览网页的方式发生了很大的变化。2007年时大多数网页并没有考虑过在手机上被浏览的问题,为了在iPhone上方便浏览桌面网页,工程师们实现了双击放大的功能,使在手机浏览器上双击屏幕就能将网页内容放大。从而为了区分双击放大和点击操作,浏览器在监听到点击事件后,会等待300ms判断用户是否再次点击屏幕,只有300ms后才会触发正常的点击事件。
初次发现问题后各种解决尝试:从点击事件本身下手
cursor: pointer
该方法来源于此:stackoverflow
看起来iOS Safari中的点击事件是一个非常麻烦的问题,回答提出的解决办法非常简单,在CSS中开头添加:
cursor: pointer
区分设备分别使用click和touchend
var clickEvent = 'ontouchend' in document ? 'touchend' : 'click';
$(ele).on(clickEvent, function(event) {
// 如果在移动端,一定要记得阻止默认事件
event.preventDefault();
// do something
})
以上的方法并不凑效。
问题的根源:CSS中:hover伪类在移动端的表现问题
实际上在笔者尝试了很多办法之后,意识到了问题的所在其实不在点击事件上,因为点击显示的效果是正常的,300ms的影响也不大,点击事件在设备上能够被正常触发。
使用Chrome的响应式界面调试时发现,第二次触摸后标签上的style属性被正常移除了,说明JS代码工作正常。因而让文字透明度保持为1的也只有:hover属性了。
经查资料后发现,:hover在移动端的表现类似于PC端的:focus,由于没有鼠标指针的存在,点击元素时:hover就会生效,并且直到点击别的地方时:hover的作用才会消失。
除此之外,iOS Safari在以上问题上还存在bug,点击别的地方时:hover也不会消失,被称为Sticky Hover问题:iOS 'Sticky Hover' Fix。只有点击另一个可以被focus的元素时之前的hover才会失效
解决办法
来源:How to prevent sticky hover effects for buttons on touch devices
该方法应用了CSS中的媒体查询(media query),检查浏览器是否支持hover功能。支持hover功能的设备往往具有独立的鼠标指针输入(不限于PC,也可能是某些游戏机内的浏览器,使用摇杆操作鼠标指针)。
在CSS中应用方法如下:
@media (hover: hover) {
.desexp-text:hover {
opacity:1;
}
}
简而言之,即用@media将:hover伪类的内容括起来即可。从而在不能使用鼠标指针的设备上就不存在该效果了。
该方法的一些小问题是在一些支持触控的PC上原先的问题仍可能存在,但对于解决移动端问题来说该方法非常实用。
【技术博客】移动端的点击事件与Sticky Hover问题的更多相关文章
- 【转】【技术博客】Spark性能优化指南——高级篇
http://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651745207&idx=1&sn=3d70d59cede236e ...
- 技术博客——微信小程序的架构与原理
技术博客--微信小程序的架构与原理 在两个月的微信小程序开发过程中,我曾走了不少弯路,也曾被很多现在看来十分可笑的问题所困扰.这些弯路与困扰,基本上都是由于当时对小程序的架构理解不够充分,对小程序的原 ...
- 【新版】Android技术博客精华汇总
[新版]Android技术博客精华汇总(原文链接内持续更新) http://www.apkbus.com/thread-313856-1-1.html Kotlin Kotlin学习资料汇总 http ...
- 一文搞定scrapy爬取众多知名技术博客文章保存到本地数据库,包含:cnblog、csdn、51cto、itpub、jobbole、oschina等
本文旨在通过爬取一系列博客网站技术文章的实践,介绍一下scrapy这个python语言中强大的整站爬虫框架的使用.各位童鞋可不要用来干坏事哦,这些技术博客平台也是为了让我们大家更方便的交流.学习.提高 ...
- 李洪强iOS开发之iOS技术博客
李洪强iOS开发之iOS技术博客 注意:访问博客请直接点击博客,不要点击后面的RSS地址 博客地址 RSS地址 南峰子的技术博客 剑尖博客 图拉鼎 Henry Lee Dev Talk ...
- 技术人如何利用 github+Jekyll ,搭建一个独立免费的技术博客
上次有人留言说,技术博客是程序员的标配,但据我所知绝大部分技术同学到现在仍然没有自己的技术博客.原因有很多,有的是懒的写,有的是怕写不好,还有的是一直想憋个大招,幻想做到完美再发出来,结果一直胎死腹中 ...
- [技术博客]使用wx.downloadfile将图片下载到本地临时存储
目录 目标 代码展示 重点讲解 目标 在上一篇技术博客中,我们生成的海报中包含图片,这些图片是存储到服务器上的,而canvas的drawimage函数只能读取本地文件,因此我们在drawCanvas之 ...
- [技术博客]海报图片生成——小程序canvas画布
目录 背景介绍 canvas简介 代码实现 难点讲解 圆角矩形裁剪失败之PS的妙用 编码不要过硬 对过长的文字进行截取 真机首次生成时字体不对 drawImage只能使用本地图片 背景介绍 目标:利用 ...
- [技术博客] Android 自动化测试
[技术博客] Android 自动化测试 安卓自动化测试工具与平台的搭建 类似于网页端自动化,安卓测试的自动化也主要是针对控件的自动化.其原理就是通过python(其他语言) 的脚本来代替我们手动完成 ...
随机推荐
- kvm虚拟机vnc配置
通过vnc方式访问虚拟主机上的KVM虚拟机 通过虚拟主机的IP地址与端口进行访问 1. 修改qemu.conf # vi /etc/libvirt/qemu.conf vnc_listen = &q ...
- python 练习题:请利用Python内置的hex()函数把一个整数转换成十六进制表示的字符串
# -*- coding: utf-8 -*- # 请利用Python内置的hex()函数把一个整数转换成十六进制表示的字符串 n1 = 255 n2 = 1000 print(hex(n1)) pr ...
- alpine使用的避坑指南
alpine,是一个重量仅为5 MB的最小Linux发行版.它还有基本的linux工具和一个不错的包管理器APK.APK非常稳定,有相当数量的包.由于体积小,在容器中很受欢迎,但是使用上坑也很多,大部 ...
- 教你玩转Linux系统目录结构
Linux 内核最初只是由芬兰人林纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的.Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POS ...
- tcp 3次握手和4次挥手
TCP标志位 (参考来源:https://blog.csdn.net/ltstud/article/details/73995933和 https://blog.csdn.net/weixin_308 ...
- Gin-Go学习笔记六:Gin-Web框架 Api的编写
Api编写 1> Gin框架的Api返回的数据格式有json,xml,yaml这三种格式.其中yaml这种格式是一种特殊的数据格式.(本人暂时没有实现获取节点值得操作) 2> ...
- 解决 new file()在IOS下不兼容 的问题
最近 做项目,做的要是拍照后上传相片,以file格式上传..所以 拍照 后用canvas生成base64格式再转file..在PC和安卓都是没有问题,到IOS上面不行..new file后就是生成一个 ...
- 【转载】Gradle学习 第八章:依赖管理基础
转载地址:http://ask.android-studio.org/?/article/10 This chapter introduces some of the basics of depend ...
- FPM九:配置FPM Launchpad
1.事物代码LPD_CUST,点击新建输入角色和实例保存. 2.新建文件夹: 3.新建应用程序 这样一个菜单的LAUNCHPAD就好了. 4.FPM_WB运行FPM工作台,新建OVP应用程序. 保存本 ...
- hadoop hdfs 有内网、公网ip后,本地调试访问不了集群解决
问题背景: 使用云上的虚拟环境搭建测试集群,导入一些数据,在本地idea做些debug调试,但是发现本地idea连接不上测试环境 集群内部配置hosts映射是内网映射(内网ip与主机名映射),本地只能 ...