【技術博客】移動端的點擊事件與Sticky Hover問題

移動端的點擊事件與Sticky Hover問題

v1.0css

做者:ZBWhtml

TL;DR

解決辦法是:在:hover僞類外使用@media區分設備,在移動設備上使hover效果不生效。java

@media (hover: hover) {
    .desexp-text:hover  {
        opacity:1;
    }
}

這一方法的缺點是問題在帶有觸控的PC上仍可能存在,但對於大多移動設備來講足以應付了。jquery

前言

筆者起初認爲該問題是JS的點擊事件綁定有誤致使的,但以後卻發現問題出在CSS上。所以本文除了解決問題外,也會介紹如下筆者的踩坑歷程,順帶介紹一下移動端點擊事件的不一樣。ios

問題描述

背景

在Beta階段,團隊想要在項目中實現設計性實驗複習的頁面。該頁面的主要使用方式是團隊預先在整理好的複習資料中挖一些空,而後用戶經過交互來顯示/隱藏答案。計劃的交互方式是:git

  1. 鼠標放在空上,答案顯示出來。鼠標移開答案消失github

  2. 鼠標點一下空,答案顯示,移開鼠標也不會消失。再次點擊將恢復隱藏的狀態。web

  3. 實現一個清空答案的按鈕,能夠一鍵清空全部顯示的答案。gulp

實現方式

該功能的實現方式很是簡單。對於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上原先的問題仍可能存在,但對於解決移動端問題來講該方法很是實用。

相關文章
相關標籤/搜索