iPhone / iPadユーザーの:hover疑似クラスを強制的に無視することは可能ですか?


94

私のサイトにはいくつかのcssメニューがあります:hover(jsなしで)

これは、iDeviceで半ば壊れた方法で機能します。たとえば、タップすると:hoverルールがアクティブになり、メニューが展開されますが、他の場所をタップしてもは削除されません:hover。また、要素内にリンクされたリンクがある場合、2 :hover回タップしてリンクをアクティブにする必要があります(最初のタップトリガー:hover、2番目のタップトリガーリンク)。

touchstartイベントをバインドすることで、iPhoneでうまく機能するようになりました。

問題は、モバイルサファリが私のイベントではなく:hover CSSからルールをトリガーすることを選択する場合があることです。touchstart

:hoverCSSですべてのルールを手動で無効にすると、モバイルサファリが適切に機能するためです(ただし、通常のブラウザーでは明らかに機能しません)。

:hoverユーザーがモバイルサファリを使用しているときに、特定の要素のルールを動的に「キャンセル」する方法はありますか?

ここでiOSの動作を確認して比較してください:http : //jsfiddle.net/74s35/3/ 注:一部のcssプロパティのみが2クリック動作をトリガーすることに注意してください。背景ではなく、赤。またはテキスト装飾:下線;


7
「タッチ」イベントが存在するという理由だけでホバリングを無効にしないでください。これは、タッチおよびマウス入力デバイスを備えたラップトップのユーザーに悪影響を及ぼします。詳細については、私の回答を参照してください
Simon_Weaver

回答:


77

「:hover」はiPhone / iPad Safariでは予測できないことがわかりました。要素をタップすると、その要素が ":hover"になる場合がありますが、他の要素に移動する場合もあります。

とりあえず、私はボディで「ノータッチ」クラスを持っています。

<body class="yui3-skin-sam no-touch">
   ...
</body>

また、「。no-touch」の下に「:hover」を含むすべてのCSSルールを設定します。

.no-touch my:hover{
   color: red;
}

ページのどこかに、ボディからノータッチクラスを削除するJavaScriptがあります。

if ('ontouchstart' in document) {
    Y.one('body').removeClass('no-touch');
}

これは完璧に見えませんが、とにかく動作します。


5
これが唯一の方法です。私を悩ませているのは、「通常の」サイトを、そこに属していない無関係なもので汚染していることです。しかたがない。ありがとう。
クリストファーキャンプ、2011年

IEのフォールバックでメディアクエリを使用することもできます
Lime

2
@Shackrock:「1回タップしてホバーし、2回クリックして」というアプローチは良い解決策ではないと思います。タッチデバイスには実際にはホバーが存在しないため(指でホバーすることを感知する画面が表示されるまで)、ホバリングをシミュレートしない方が良いと思います。ボタンやリンクによく見られるような効果については、効果をスキップしてください。ホバーで展開するメニューの場合は、代わりにタップ/クリックで展開します。私の2c。
Adrian Schmidt

18
タッチとマウス入力を備えた新しいWindows 8システムが原因で、この種のアプローチに最近問題が見つかりました
Tom

4
トムのコメントへの+1-外部モニターに接続されている場合でも、タッチ対応のラップトップでontouchstartをチェックするとtrueが返されます(ホバー状態のあるマウス対応サイトがより望ましい)。
gregdev 2013

45

:hoverここでは問題ではありません。iOS用のSafariは非常に奇妙なルールに従います。最初に発砲mouseovermousemoveます。これらのイベント中に変更があった場合、「クリック」および関連するイベントは発生しません。

iOSのタッチイベントの図

mouseenterそしてmouseleave彼らは、チャートに指定されていないが、含まれているように見えます。

これらのイベントの結果として何かを変更した場合、クリックイベントは発生しません。これには、DOMツリーの上位にあるものが含まれます。たとえば、これにより、jQueryを使用してWebサイトでシングルクリックが機能しなくなります。

$(window).on('mousemove', function() {
    $('body').attr('rel', Math.random());
});

編集:明確にするために、jQueryのhoverイベントにはmouseenterおよびが含まれていmouseleaveます。これらは両方ともclick、コンテンツが変更された場合に防止します。


5
もちろん:hoverが問題です:-)またはむしろそれのサファリのバグのある実装。これはこの問題に関する興味深い背景ですが、この恐ろしい動作を修正できるのはAppleだけです。要素の外側をクリックしたときに「ホバー解除」するか、最初から「ホバー」しないようにする必要があります。現在の動作は基本的に、マウスに:
hover

これは、jquery hoverハンドラーが別のclickハンドラーのヒットを妨げていることを理解するのに役立ちました-なんて冗談でしょう!
Simon_Weaver

1
素晴らしい答え、そして私が遭遇した問題の最も良い説明。「ダブルクリック」問題を引き起こすのはCSSホバーだけではなく、マウスオーバー/マウス入力などのイベント後の文字通りのDOM変更です。
Oliver Joseph Ash


@オリバージョセフアッシュ右、したがって、答えのJSの例。;)
Zenexer 2017

18

ブラウザ機能検出ライブラリModernizerには、タッチイベントのチェックが含まれています。

デフォルトの動作では、検出される各機能のHTML要素にクラスを適用します。その後、これらのクラスを使用してドキュメントのスタイルを設定できます。

タッチイベントが有効になっていない場合、Modernizrは次のクラスを追加できますno-touch

<html class="no-touch">

次に、このクラスでホバースタイルをスコープします。

.no-touch a:hover { /* hover styles here */ }

カスタムModernizrビルドダウンロードして、必要な数の機能検出を含めることができます

適用できるクラスの例を次に示します。

<html class="js no-touch postmessage history multiplebgs
             boxshadow opacity cssanimations csscolumns cssgradients
             csstransforms csstransitions fontface localstorage sessionstorage
             svg inlinesvg no-blobbuilder blob bloburls download formdata">

デスクトップ上のChromeの最近のバージョンでは、Modernizrが「タッチ」を報告することに注意してください。これは明らかにタッチイベントのあるバージョン3で修正されています。
Craig Jacobs

18

一部のデバイス(他のユーザーが述べたように)には、タッチイベントとマウスイベントの両方があります。たとえば、Microsoft Surfaceには、タッチスクリーン、トラックパッド、およびスタイラスがあり、画面の上にホバーするとホバーイベントを実際に発生させます。

:hover「タッチ」イベントの存在に基づいて無効になるソリューションは、Surfaceユーザー(および他の多くの同様のデバイス)にも影響します。多くの新しいラップトップはタッチ対応であり、タッチイベントに応答します。そのため、ホバリングを無効にすることは非常に悪い習慣です。

これはSafariのバグです。この恐ろしい振る舞いを正当化する理由はまったくありません。何年にもわたって存在していると思われるiOS Safariのバグのため、私は非iOSブラウザーを妨害することを拒否します。私は本当に彼らが来週iOS8のためにこれを修正することを望みますが、その間...

私の解決策

Modernizrの使用をすでに提案している人もいますが、Modernizrを使用すると、独自のテストを作成できます。私が基本的にここで行っているのは:hover、コードif (iOS)全体でハードコーディングせずにコード全体で使用できるModernizrテストをサポートするブラウザーのアイデアを「抽象化」することです。

 Modernizr.addTest('workinghover', function ()
 {
      // Safari doesn't 'announce' to the world that it behaves badly with :hover
      // so we have to check the userAgent  
      return navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? false : true;
 });

それからCSSはこのようなものになります

html.workinghover .rollover:hover 
{
    // rollover css
}

このテストは失敗し、ロールオーバーは無効になります。

そのような抽象化の最良の部分は、特定のAndroidでそれが壊れていることがわかった場合、またはiOS9で修正されている場合、テストを変更できることです。


この解決策は厄介であり、最高です。ホバーに苦労しているブラウザーがタッチとクリックの両方を持っている場合にのみ壊れますが、ipad / iphoneのタッチ専用ブラウザーの場合はそうではありません。私の提案は、これを最適化の修正としてのみ実装し(すでにfastclick.jsを使用している場合のホバーフリッカーを削除するため)、それなしでもすべてが機能することを確認することです。
Gersom

ありがとう。同意する。この問題に対してiOS 9が何をしているのか知りたい-あれば。
Simon_Weaver 2015

私は反対の方向に行きました:html:not(.no-hover) .category:hover { ...
Chris Marisic

「Safariは:hoverで正しく動作しないことを世界に「告知」しません」+1この問題は、私の意見では、iOSをどのバージョンのIEよりもはるかに悪くしています...
Spencer O'Reilly

16

FastClickライブラリをページに追加すると、モバイルデバイスでのすべてのタップが(ユーザーがクリックした場所に関係なく)クリックイベントに変換されるため、モバイルデバイスでのホバーの問題も修正されるはずです。例としてあなたのフィドルを編集しました:http : //jsfiddle.net/FvACN/8/

fastclick.min.js libをページに含めて、以下を介してアクティブ化するだけです。

FastClick.attach(document.body);

副次的な利点として、モバイルデバイスで発生する煩わしい300ミリ秒のonClick遅延も解消されます。


FastClickを使用すると、サイトにとって重要な場合と重要でない場合のいくつかの小さな影響があります。

  1. ページのどこかをタップして上にスクロールし、下にスクロールしてから、最初に配置した位置とまったく同じ位置で指を離すと、FastClickはそれを「クリック」と解釈します。少なくとも、私が現在使用しているFastClickのバージョン(1.0.0)では、このように動作します。そのバージョン以降、誰かが問題を修正した可能性があります。
  2. FastClickは、誰かが「ダブルクリック」する機能を削除します。

1
私のウェブサイトでこれを行う方法の別の具体例を共有してもよろしいですか。私はjavascriptについて何も知らないので、これがどのように機能するかについて少し混乱しています。ユーザーがクリックする前にこれらのリンクをすべてユーザーがホバーすることが多いのですが、iPad /モバイルの場合、ユーザーが2回クリックする必要がないようにしたいと考えています。
アンディ

@Andy-何が必要で何が不足しているのかが明確ではありません...これまでに何を試しましたか。たぶん、新しいStackoverflow質問を作成することをお勧めします(まだ作成していない場合は、実行しようとしていることの例を使用して(?)または、上記のjsfiddleの例で何を実行しているかを明確にしてください)分かりました
Troy

これは単一ページのアプリケーションで使用できますか?つまり、DOMコンテンツが毎回更新されるときです
Sebastien Lorber、2015

はい、単一ページのアプリケーションで使用しています。
トロイ

16

JS、CSSクラス、ビューポートチェックなしのより良いソリューション:インタラクションメディア機能(メディアクエリレベル4)を使用できます

このような:

@media (hover) {
  // properties
  my:hover {
    color: red;
  }
}

iOS Safariがサポートしています

詳細:https : //www.jonathanfielding.com/an-introduction-to-interaction-media-features/


ただし、Firefoxではサポートされていません(もちろんこのコメントの時点では)
Frank

これはFirefoxでもサポートされるようになりました(FF 64 +、2018年12月リリース)。
wunch

4

基本的に3つのシナリオがあります。

  1. ユーザーはマウス/ポインターデバイスのみを持ち、アクティブ化できます:hover
  2. ユーザーはタッチスクリーンしか持っておらず、:hover要素をアクティブにすることはできません
  3. ユーザーはタッチスクリーンとポインターデバイスの両方を持っています

ユーザーが持っているところだけ最初の2つのシナリオは、可能であれば本来は受け入れ答えは素晴らしい作品のいずれかのポインタまたはタッチスクリーンを。OPが4年前に質問したとき、これは一般的でした。Windows 8とSurfaceデバイスが3番目のシナリオの可能性を高めていると、いくつかのユーザーが指摘しています。

(@Zenexerで詳しく説明されているように)タッチスクリーンデバイス上でホバーできないという問題のiOSソリューションは賢いですが、(OPで指摘されているように)単純なコードが誤動作する可能性があります。タッチスクリーンデバイスでのみホバーを無効にすると、タッチスクリーンフレンドリーな代替をコーディングする必要があります。ユーザーがポインターとタッチスクリーンの両方を持っていることを検出すると、さらに水が濁ります(@Simon_Weaverで説明)。

この時点で、最も安全な解決策は:hover、ユーザーがWebサイトとやり取りできる唯一の方法として使用することを避けることです。ホバー効果は、リンクまたはボタンがアクション可能であることを示す良い方法ですが、ユーザーがWebサイトでアクションを実行するために要素にホバーする必要はありません。

タッチスクリーンを念頭に置い「ホバー」機能を再考することで、代替のUXアプローチについて十分に議論できます。そこでの回答によって提供されるソリューションは次のとおりです。

  • ホバーメニューを直接アクションに置き換える(常に表示されるリンク)
  • ホバーメニューをオンタップメニューに置き換える
  • ホバーコンテンツを大量に別のページに移動する

今後、これはおそらくすべての新しいプロジェクトに最適なソリューションになるでしょう。受け入れられた答えはおそらく2番目に良い解決策ですが、ポインタデバイスも備えているデバイスを考慮に入れてください。iOSの:hoverハックを回避するためだけにデバイスにタッチスクリーンがある場合は、機能を削除しないように注意してください。


1

.cssのJQueryバージョンでは、すべてのホバールールにJQueryと次のスクリプトが含まれているため、.no-touch .my-element:hoverを使用します。

function removeHoverState(){
    $("body").removeClass("no-touch");
}

次に、bodyタグにclass = "no-touch" ontouchstart = "removeHoverState()"を追加します

ontouchstartがクラスを起動するとすぐに、すべてのホバー状態が削除されます


0

タッチが利用できないときにホバー効果のみを使用する代わりに、タッチイベントを処理するシステムを作成しました。これで問題が解決しました。最初に、「タップ」(「クリック」に相当)イベントをテストするためのオブジェクトを定義しました。

touchTester = 
{
    touchStarted: false
   ,moveLimit:    5
   ,moveCount:    null
   ,isSupported:  'ontouchend' in document

   ,isTap: function(event)
   {
      if (!this.isSupported) {
         return true;
      }

      switch (event.originalEvent.type) {
         case 'touchstart':
            this.touchStarted = true;
            this.moveCount    = 0;
            return false;
         case 'touchmove':
            this.moveCount++;
            this.touchStarted = (this.moveCount <= this.moveLimit);
            return false;
         case 'touchend':
            var isTap         = this.touchStarted;
            this.touchStarted = false;
            return isTap;
         default:
            return true;
      }
   }
};

次に、私のイベントハンドラーで次のようなことを行います。

$('#nav').on('click touchstart touchmove touchend', 'ul > li > a'
            ,function handleClick(event) {
               if (!touchTester.isTap(event)) {
                  return true;
               }

               // touch was click or touch equivalent
               // nromal handling goes here.
            });

0

答えを@Morgan Chengに感謝しますが、 " touchstart "(@Timothy Perezの答えから取得したコード)を取得するためにJS関数を少し変更しましたが、これにはjQuery 1.7以降が必要です

  $(document).on({ 'touchstart' : function(){
      //do whatever you want here
    } });

0

Zenexerによって提供される応答を考えると、追加のHTMLタグを必要としないパターンは次のとおりです。

jQuery('a').on('mouseover', function(event) {
    event.preventDefault();
    // Show and hide your drop down nav or other elem
});
jQuery('a').on('click', function(event) {
    if (jQuery(event.target).children('.dropdown').is(':visible') {
        // Hide your dropdown nav here to unstick
    }
});

このメソッドは、最初にマウスオーバーを発生させ、次にクリックをクリックします。


0

私はタッチのホバーを無効にすることは行く方法に同意します。

ただし、CSSを書き直す手間を省くには、:hoverアイテムを @supports not (-webkit-overflow-scrolling: touch) {}

.hover, .hover-iOS {
  display:inline-block;
  font-family:arial;
  background:red;
  color:white;
  padding:5px;
}
.hover:hover {
  cursor:pointer;
  background:green;
}

.hover-iOS {
  background:grey;
}

@supports not (-webkit-overflow-scrolling: touch) {
  .hover-iOS:hover {
    cursor:pointer;
    background:blue;
  }

}
<input type="text" class="hover" placeholder="Hover over me" />

<input type="text" class="hover-iOS" placeholder="Hover over me (iOS)" />


0

:hoveriOS Safariでイベントを無効にするという一般的な使用例がある場合、最も簡単な方法は、:hover回避するデバイスの画面幅より上に留まるイベントの最小幅メディアクエリを使用することです。例:

@media only screen and (min-width: 1024px) {
  .my-div:hover { // will only work on devices larger than iOS touch-enabled devices. Will still work on touch-enabled PCs etc.
    background-color: red;
  }
}

-6

画面サイズを見てください...

@media (min-width: 550px) {
    .menu ul li:hover > ul {
    display: block;
}
}

-12

配置したいコードをここに

// a function to parse the user agent string; useful for 
// detecting lots of browsers, not just the iPad.
function checkUserAgent(vs) {
    var pattern = new RegExp(vs, 'i');
    return !!pattern.test(navigator.userAgent);
}
if ( checkUserAgent('iPad') ) {
    // iPad specific stuff here
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.