web-dev-qa-db-ja.com

タッチデバイスでホバーCSSスタイルを削除/無視する方法

ユーザーがタッチデバイス経由で当社のWebサイトにアクセスする場合、:hover CSS宣言をすべて無視したいと思います。 :hover CSSは意味をなさないため、タブレットがクリック/タップでトリガーすると、要素がフォーカスを失うまでスティックする可能性があるため、邪魔になることさえあります。正直なところ、なぜタッチデバイスが最初に:hoverをトリガーする必要があると感じるのかわかりませんが、これは現実であるため、この問題も現実です。

a:hover {
   color:blue;
   border-color:green;
   // etc. > ignore all at once for touch devices
}

だから、(どのように)タッチデバイスを宣言した後、CSSの:hover宣言を一度にすべて削除(無視)できますか?

96

この問題には複数の解決策があります。

Quick'n'dirty-J​​Sを使用して:hoverスタイルを削除

JavaScriptを使用して、:hoverを含むすべてのCSSルールを削除できます。これには、CSSに触れる必要がなく、古いブラウザーでも互換性があるという利点があります。

function hasTouch() {
    return 'ontouchstart' in document.documentElement
           || navigator.maxTouchPoints > 0
           || navigator.msMaxTouchPoints > 0;
}

if (hasTouch()) { // remove all :hover stylesheets
    try { // prevent exception on browsers not supporting DOM styleSheets properly
        for (var si in document.styleSheets) {
            var styleSheet = document.styleSheets[si];
            if (!styleSheet.rules) continue;

            for (var ri = styleSheet.rules.length - 1; ri >= 0; ri--) {
                if (!styleSheet.rules[ri].selectorText) continue;

                if (styleSheet.rules[ri].selectorText.match(':hover')) {
                    styleSheet.deleteRule(ri);
                }
            }
        }
    } catch (ex) {}
}

制限:スタイルシートは同じドメインでホストする必要があります(つまり、CDNがないことを意味します)。混合 マウスとタッチデバイス Surfaceのようなホバーを無効にします。これはUXを傷つけます。

CSSのみ-メディアクエリを使用

すべての:hoverルールを@mediaブロックに配置します。

@media (hover: hover) {
    a:hover { color: blue; }
}

または、すべてのホバールールを上書きします(古いブラウザーと互換性があります)。

a:hover { color: blue; }

@media (hover: none) {
    a:hover { color: inherit; }
}

制限:iOS 9.0以降、WebViewを使用する場合はChromeまたはAndroid 5.0以降のAndroidのみで動作します。 hover: hoverは、古いブラウザでのホバー効果を壊します。hover: noneは、以前に定義されたすべてのCSSルールをオーバーライドする必要があります。両方とも、マウスとタッチが混在するデバイスとは互換性がありません

最も堅牢-特別なCSSクラスを使用し、JSを介してタッチを検出します

この方法では、body.hasHoverをすべてのホバールールの先頭に追加する必要があります。 (または選択したクラス名)

body.hasHover a:hover { color: blue; }

hasHoverクラスは、最初の例のhasTouch()を使用して追加できます。

if (!hasTouch()) {
    document.body.className += ' hasHover';
}

ただし、これには、混合タッチデバイスの場合、前の例と同じ問題があり、究極のソリューションにつながります。マウスカーソルが移動するたびにホバー効果を有効にし、タッチが検出されるたびにホバー効果を無効にします。

function watchForHover() {
    var hasHoverClass = false;
    var container = document.body;
    var lastTouchTime = 0;

    function enableHover() {
        // filter emulated events coming from touch events
        if (new Date() - lastTouchTime < 500) return;
        if (hasHoverClass) return;

        container.className += ' hasHover';
        hasHoverClass = true;
    }

    function disableHover() {
        if (!hasHoverClass) return;

        container.className = container.className.replace(' hasHover', '');
        hasHoverClass = false;
    }

    function updateLastTouchTime() {
        lastTouchTime = new Date();
    }

    document.addEventListener('touchstart', updateLastTouchTime, true);
    document.addEventListener('touchstart', disableHover, true);
    document.addEventListener('mousemove', enableHover, true);

    enableHover();
}

watchForHover();

これは基本的にどのブラウザでも機能し、必要に応じてホバースタイルを有効または無効にします。ここで試してください: https://jsfiddle.net/dkz17jc5/19/

117
blade

ポインター適応 救助へ!

これはしばらく触れられていないので、次を使用できます。

a:link {
   color: red;
}

a:hover {
   color:blue;
}

@media (hover: none) {
   a:link {
      color: red;
   }
}

これを参照してください デスクトップブラウザと電話ブラウザの両方でデモモダンタッチデバイス でサポートされています。

:Surface PCの主要な入力(機能)はマウスであるため、たとえそれが青いリンクであっても、デタッチ(タブレット)画面。ブラウザは、常に最も正確な入力機能にデフォルト設定する必要があります。

32

現在、同様の問題に取り組んでいます。

すぐに発生する2つのmainオプションがあります。(1)ユーザー文字列チェック、または(2)別のURLを使用して個別のモバイルページを維持し、ユーザーに最適なものを選択させる。

  1. PHPやRubyなどのインターネットダクトテープ言語を使用できる場合は、ユーザー文字列を確認できますデバイスはページをリクエストし、同じコンテンツを提供しますが、通常のスタイルではなく<link rel="mobile.css" />を使用します。

ユーザー文字列には、ブラウザー、レンダラー、オペレーティングシステムなどに関する識別情報があります。「タッチ」デバイスと非タッチデバイスを決定するのはユーザー次第です。この情報はどこかで入手でき、システムにマッピングできる場合があります。

A. 古いブラウザを無視する が許可されている場合、単一のルールを通常の非モバイルCSSに追加するだけです。 EDIT:Erk。いくつかの実験を行った後、美的効果を無効にするだけでなく、以下のルールがwebkit-browsersのリンクをフォローする機能も無効にすることを発見しました- http://jsfiddle.net/3nkcdeao/ を参照してください
このように、モバイルケースのルールをどのように変更するかについては、ここに示すものよりも少し選択的にする必要がありますが、開始点として役立つ場合があります。

* { 
    pointer-events: none !important; /* only use !important if you have to */
}

補足として、親でポインターイベントを無効にしてから子で明示的に有効にすると、現在、子要素が:hoverに入ると、親でのホバー効果が再びアクティブになります。
を参照 http://jsfiddle.net/38Lookhp/5/

B.レガシーWebレンダラーをサポートしている場合、:hoverの間に特別なスタイルを設定するルールを削除するラインに沿って、もう少し作業を行う必要があります。全員の時間を節約するために、標準のスタイルシートで実行してモバイルバージョンを作成する自動コピー+ sed ingコマンドを作成するだけです。これにより、標準コードを記述/更新し、ページのモバイルバージョンに:hoverを使用するスタイルルールを削除することができます。

  1. (I)または、モバイルデバイス用にwebsite.comに加えてm.website.comがあることをユーザーに知らせるだけです。サブドメインは最も一般的な方法ですが、モバイルユーザーが変更されたページにアクセスできるように、特定のURLを予測可能な他の変更を加えることもできます。その段階では、サイトの別の部分に移動するたびにURLを変更する必要がないことを確認する必要があります。

この場合も、スタイルシートに1つまたは2つの余分なルールを追加するか、 sed または同様のユーティリティを使用して、少し複雑な操作を強制することができます。 CSSを変更するのではなく、jsまたはサーバー言語を使用してモバイルユーザーの面倒なことを行う要素にclass="disruptive"を追加するdiv:not(.disruptive):hover {...のようなスタイリングルールではなく、おそらく最も簡単に適用できます。

  1. (II)最初の2つを実際に組み合わせて、(ユーザーが間違ったバージョンのページに移動した疑いがある場合)モバイルタイプのディスプレイに切り替える、またはモバイルタイプのディスプレイに切り替えることを提案できます。ユーザーが前後にフロップできるようにします。すでに述べたように、@ mediaクエリは、訪問に使用されているものを判断する際に使用するものです。

  2. (III)「タッチ」デバイスと「タッチ」デバイスがわからない場合にjQueryソリューションを使用する場合は、 タッチスクリーンデバイスではCSSホバーが無視されない 役立つことがあります。

7
SeldomNeedy

私は同じ問題(私の場合はSamsungのモバイルブラウザー)に遭遇したので、この質問に出くわしました。

Calsal's answer のおかげで、試したモバイルブラウザで認識されているように見えるため、事実上すべてのデスクトップブラウザを除外すると思われる何かを見つけました(コンパイルされた表のスクリーンショットを参照してください: CSSポインター機能検出テーブル )。

MDN web docs 状態

ポインターCSS @media機能を使用して、ユーザーの主な入力メカニズムがポインティングデバイスであるかどうかに基づいてスタイルを適用できます。

私が発見したのは、pointer:コース(粗いは、添付されたテーブルのすべてのデスクトップブラウザには不明ですが、同じテーブルのすべてのモバイルブラウザには知られているものです。他のすべてのポインターキーワード値は一貫性のない結果をもたらすため、これが最も効果的な選択のようです。

したがって、 Calsal のようなメディアクエリを作成できますが、わずかに変更します。逆のロジックを使用して、すべてのタッチデバイスを除外します。

Sass mixin:

@mixin hover-supported {    
    /* 
     * https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer 
     * coarse: The primary input mechanism includes a pointing device of limited accuracy.
     */
    @media not all and (pointer: coarse) {
        &:hover {
            @content;
        }
    }
}

a {
    color:green;
    border-color:blue;

    @include hover-supported() {
        color:blue;
        border-color:green;
    }
}

コンパイルされたCSS:

a {
  color: green;
  border-color: blue;
}
@media not all and (pointer: coarse) {
  a:hover {
    color: blue;
    border-color: green;
  }
}

これについても説明します Gist 私は問題を調査した後に作成しました。 Codepen 実証研究用。

UPDATE:このアップデートを書いている時点で2018-08-23、@ DmitriPavlutinが指摘したように、この手法はFirefoxデスクトップでは動作しないようです。

6
ProgrammerPer

これを試して:

@media (hover:<s>on-demand</s>) {
    button:hover {
        background-color: #color-when-NOT-touch-device;
    }
}

更新:残念ながら、W3Cはこのプロパティを仕様から削除しました( https://github.com/w3c/csswg-drafts/commit/2078b46218f7462735bb0b5107c9a3e84fb4c4b1 )。

6
Marouen Mhiri

Modernizr JS(これも StackOverflow answer を参照)を使用するか、カスタムJS関数を作成できます。

function is_touch_device() {
 return 'ontouchstart' in window        // works on most browsers 
  || navigator.maxTouchPoints;       // works on IE10/11 and Surface
};

if ( is_touch_device() ) {
  $('html').addClass('touch');
} else {
  $('html').addClass('no-touch');
} 

ブラウザでtouchイベントのサポートを検出し、通常のCSSプロパティを割り当て、次のようにhtml.no-touchクラスで要素を走査します:

html.touch a {
    width: 480px;
}

/* FOR THE DESKTOP, SET THE HOVER STATE */
html.no-touch a:hover {
   width: auto;
   color:blue;
   border-color:green;
}
4
Giacomo Paita

Jason´s answer によると、純粋なCSSメディアクエリでホバーをサポートしていないデバイスのみに対処できます。また、@media not all and (hover: none)を使用して、同様の質問で moogal´s answer のような、ホバーをサポートするデバイスのみに対処することもできます。変に見えますが、動作します。

使いやすくするために、これからSassミックスインを作成しました。

@mixin hover-supported {
    @media not all and (hover: none) {
        &:hover {
            @content;
        }
    }
}

2019-05-15の更新この中程度の記事 CSSでターゲットにできるすべての異なるデバイスを通過することをお勧めします。基本的には、これらのメディアルールを組み合わせたもので、特定のターゲットに合わせて組み合わせます。

@media (hover: hover) {
    /* Device that can hover (desktops) */
}
@media (hover: none) {
    /* Device that can not hover with ease */
}
@media (pointer: coarse) {
    /* Device with limited pointing accuracy (touch) */
}
@media (pointer: fine) {
    /* Device with accurate pointing (desktop, stylus-based) */
}
@media (pointer: none) {
    /* Device with no pointing */
}

特定のターゲットの例:

@media (hover: none) and (pointer: coarse) {
    /* Smartphones and touchscreens */
}

@media (hover: hover) and (pointer: fine) {
    /* Desktops with mouse */
}

私はミックスインが大好きです、これは私がそれを使用する方法です:

@mixin is-touch {
    @media (hover: none) and (pointer: coarse) {
        @content;
    }
}
1
Calsal

これも回避策の可能性がありますが、ホバースタイルの前にcssを調べて.no-touchクラスを追加する必要があります。

Javascript:

if (!("ontouchstart" in document.documentElement)) {
document.documentElement.className += " no-touch";
}

CSSの例:

<style>
p span {
    display: none;
}

.no-touch p:hover span {
    display: inline;
}
</style>
<p><a href="/">Tap me</a><span>You tapped!</span></p>

ソース

追伸しかし、覚えておくべきは、市場にはますます多くのタッチデバイスが登場し、同時にマウス入力もサポートしているということです。

1
mr.mii

これはまだ完全なソリューションではないかもしれません(そしてjQueryを使用しています)が、それは取り組むべき方向性/概念かもしれません。つまり、デフォルトで:hover css状態を非アクティブ化し、ドキュメントのどこかでmousemoveイベントが検出された場合にアクティブ化します。もちろん、誰かがjsを無効にした場合、これは機能しません。この方法でそれを行うことに反対する他のことは何でしょうか?

たぶんこのように:

CSS:

/* will only work if html has class "mousedetected" */
html.mousedetected a:hover {
   color:blue;
   border-color:green;
}

jQuery:

/* adds "mousedetected" class to html element if mouse moves (which should never happen on touch-only devices shouldn’t it?) */
$("body").mousemove( function() {
    $("html").addClass("mousedetected");
});
1

汚い方法...エレガントではないが、あなたを救うことができる最も簡単な方法。

ホバーを特徴付けるものをすべて削除します。

.your-class:hover:before {
  color: blue;
  background: linear-gradient(to bottom, rgba(231,56,39,0) 0%, #aaaaaa 100%);
}

@media all and (min-width:320px) and (max-width: 960px) {
    .your-class:hover:before {
    color: black;
    background: transparent;
  }
}
0
Fellipe Sanches

役に立ちました: link

function hoverTouchUnstick() {
    // Check if the device supports touch events
    if('ontouchstart' in document.documentElement) {
        // Loop through each stylesheet
        for(var sheetI = document.styleSheets.length - 1; sheetI >= 0; sheetI--) {
            var sheet = document.styleSheets[sheetI];
            // Verify if cssRules exists in sheet
            if(sheet.cssRules) {
                // Loop through each rule in sheet
                for(var ruleI = sheet.cssRules.length - 1; ruleI >= 0; ruleI--) {
                    var rule = sheet.cssRules[ruleI];
                    // Verify rule has selector text
                    if(rule.selectorText) {
                        // Replace hover psuedo-class with active psuedo-class
                        rule.selectorText = rule.selectorText.replace(":hover", ":active");
                    }
                }
            }
        }
    }
}
0
mineroot

これを試してください(この例では背景と背景色を使用しています):

var ClickEventType = ((document.ontouchstart !== null) ? 'click' : 'touchstart');

if (ClickEventType == 'touchstart') {
            $('a').each(function() { // save original..
                var back_color = $(this).css('background-color');
                var background = $(this).css('background');
                $(this).attr('data-back_color', back_color);
                $(this).attr('data-background', background);
            });

            $('a').on('touchend', function(e) { // overwrite with original style..
                var background = $(this).attr('data-background');
                var back_color = $(this).attr('data-back_color');
                if (back_color != undefined) {
                    $(this).css({'background-color': back_color});
                }
                if (background != undefined) {
                    $(this).css({'background': background});
                }
            }).on('touchstart', function(e) { // clear added stlye="" elements..
                $(this).css({'background': '', 'background-color': ''});
            });
}

css:

a {
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
0
HU TanKy

この簡単な2019 jqueryソリューションを試してください。

  1. このプラグインをheadに追加します:

    src = "https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"

  2. これをjsに追加します:

    $( "*")。on( "touchend"、function(e){$(this).focus();}); //すべての要素に適用

  3. これに推奨されるバリエーションは次のとおりです。

    $( ":input、:checkbox、")。on( "touchend"、function(e){(this).focus);}); //要素を指定します

    $( "*")。on( "click、touchend"、function(e){$(this).focus();}); //クリックイベントを含める

    css:body {カーソル:ポインター; } //どこでもタッチしてフォーカスを終了

ノート

  • ツールチップに影響を与えることを避けるために、bootstrap.jsの前にプラグインを配置します
  • safariまたはChromeを使用して、iphone XR ios 12.1.12およびipad 3 ios 9.3.5でのみテストされています。

参照:

https://code.jquery.com/ui/

https://api.jquery.com/category/selectors/jquery-selector-extensions/

0
darren