it-swarm.com.de

So vermeiden Sie Sticky-Hover-Effekte für Tasten auf Touch-Geräten

Ich habe ein Karussell mit einem vorherigen und einem nächsten Button erstellt, die immer sichtbar sind. Diese Schaltflächen haben einen Schwebeflug, sie werden blau dargestellt. Bei Touch-Geräten wie dem iPad ist der Hover-Status klebrig, sodass die Schaltfläche nach dem Antippen blau bleibt. Das will ich nicht.

  • Ich könnte eine no-hover-Klasse ontouchend für jede Schaltfläche hinzufügen und makemy CSS wie folgt hinzufügen: button:not(.no-hover):hover { background-color: blue; }, aber das ist wahrscheinlich ziemlich schlecht für die Leistung, und __. Behandelt Geräte wie den Chromebook-Pixel (der sowohl eine touchscreen und eine Maus) korrekt.

  • Ich könnte eine touch-Klasse zur documentElement hinzufügen und mein CSS wie folgt erstellen: html:not(.touch) button:hover { background-color: blue; } Das funktioniert jedoch auch nicht auf Geräten, die sowohl eine Touch-Maus als auch eine -Maus haben.

Ich würde es vorziehen, den Schwebezustand ontouchend zu entfernen. Aber es scheint nicht möglich zu sein. Wenn Sie ein anderes Element fokussieren, wird der Hover-Status nicht entfernt. Manuelles Tippen auf ein anderes Element tut dies, aber ich kann das in JavaScript nicht auslösen.

Alle Lösungen, die ich gefunden habe, scheinen unvollständig zu sein. Gibt es eine perfekte Lösung?

116
Chris

Sie können den Hover-Status entfernen, indem Sie die Verknüpfung vorübergehend aus dem DOM entfernen. Siehe http://testbug.handcraft.com/ipad.html


In der CSS haben Sie:

:hover {background:red;}

In der JS haben Sie:

function fix()
{
    var el = this;
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    setTimeout(function() {par.insertBefore(el, next);}, 0)
}

Und dann hast du in deinem HTML:

<a href="#" ontouchend="this.onclick=fix">test</a>
49
Sjoerd Visscher

Sobald CSS Media Queries Level 4 implementiert ist, können Sie Folgendes tun:

@media (hover: hover) {
    button:hover {
        background-color: blue;
    }
}

Oder in englischer Sprache: "Wenn der Browser das richtige/echte/echte/nicht emulierte Schweben unterstützt (z. B. ein mausähnliches primäres Eingabegerät), dann wenden Sie diesen Stil an, wenn buttons über dem Hover-Modus liegt."

Da dieser Teil von Media Queries Level 4 bisher nur in Bleeding-Edge Chrome implementiert wurde, schrieb I ein Polyfill , um dies zu behandeln. Damit können Sie das obige futuristische CSS in Folgendes umwandeln:

html.my-true-hover button:hover {
    background-color: blue;
}

(Eine Variation der .no-touch-Technik.) Wenn Sie dann clientseitiges JavaScript aus derselben Polyfill verwenden, die Unterstützung für Schwebeflug erkennt, können Sie das Vorhandensein der my-true-hover-Klasse entsprechend umschalten:

$(document).on('mq4hsChange', function (e) {
    $(document.documentElement).toggleClass('my-true-hover', e.trueHover);
});
49
cvrebert

Dies ist ein häufiges Problem ohne perfekte Lösung. Hover-Verhalten ist bei einer Maus nützlich und bei Berührung meist schädlich. Das Problem wird durch Geräte verstärkt, die Berührung und Maus (gleichzeitig und nicht weniger!) Wie das Chromebook Pixel und die Oberfläche unterstützen.

Die sauberste Lösung, die ich gefunden habe, ist das Aktivieren des Hover-Verhaltens nur dann, wenn das Gerät keine Berührungseingabe unterstützt.

var isTouch =  !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;

if( !isTouch ){
    // add class which defines hover behavior
}

Zugegeben, Sie verlieren den Schwebeflug auf Geräten, die dies unterstützen könnten. Manchmal wirkt sich der Schwebeflug jedoch stärker auf die Verbindung selbst aus, z. Vielleicht möchten Sie ein Menü anzeigen, wenn ein Element im Schwebeflug ist. Dieser Ansatz ermöglicht es Ihnen, die Existenz einer Berührung zu testen und möglicherweise ein anderes Ereignis bedingt zu verknüpfen.

Ich habe dies auf iPhone, iPad, Chromebook Pixel, Surface und verschiedenen Android-Geräten getestet. Ich kann nicht garantieren, dass dies funktioniert, wenn ein generischer USB-Touch-Eingang (z. B. ein Stift) zum Mix hinzugefügt wird.

24
Tim Medora

Mit Modernizr können Sie Ihre Hover gezielt für No-Touch-Geräte ausrichten:

(Hinweis: Dies kann nicht auf dem StackOverflow-Snippet-System ausgeführt werden. Überprüfen Sie stattdessen die Option jsfiddle .)

/* this one is sticky */
#regular:hover, #regular:active {
  opacity: 0.5;
}

/* this one isn't */
html.no-touch #no-touch:hover, #no-touch:active {
  opacity: 0.5;
}

Beachten Sie, dass :active nicht mit .no-touch anvisiert werden muss, da es auf Mobilgeräten und auf dem Desktop wie erwartet funktioniert.

10
rachel

Von 4 Möglichkeiten, mit Sticky Hover auf Mobilgeräten umzugehen : Hier können Sie dem Dokument basierend auf dem aktuellen Eingabetyp des Benutzers dynamisch eine "can touch" - Klasse hinzufügen oder entfernen. Es funktioniert auch mit Hybridgeräten, bei denen der Benutzer zwischen Berührung und Maus/Trackpad wechseln kann:

<script>

;(function(){
    var isTouch = false //var to indicate current input type (is touch versus no touch) 
    var isTouchTimer 
    var curRootClass = '' //var indicating current document root class ("can-touch" or "")

    function addtouchclass(e){
        clearTimeout(isTouchTimer)
        isTouch = true
        if (curRootClass != 'can-touch'){ //add "can-touch' class if it's not already present
            curRootClass = 'can-touch'
            document.documentElement.classList.add(curRootClass)
        }
        isTouchTimer = setTimeout(function(){isTouch = false}, 500) //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event
    }

    function removetouchclass(e){
        if (!isTouch && curRootClass == 'can-touch'){ //remove 'can-touch' class if not triggered by a touch event and class is present
            isTouch = false
            curRootClass = ''
            document.documentElement.classList.remove('can-touch')
        }
    }

    document.addEventListener('touchstart', addtouchclass, false) //this event only gets called when input type is touch
    document.addEventListener('mouseover', removetouchclass, false) //this event gets called when input type is everything from touch to mouse/ trackpad
})();

</script>
6
coco puffs
$("#elementwithhover").click(function() { 
  // code that makes element or parent slide or otherwise move out from under mouse. 

  $(this).clone(true).insertAfter($(this));
  $(this).remove();
});
5
Verard Sloggett

Ich wollte meine eigene Lösung posten, aber wenn ich bereits nachgefragt habe, ob jemand sie bereits veröffentlicht hat, habe ich festgestellt, dass @Rodney es fast geschafft hat. Er vermisste es jedoch ein letztes Mal, was es zumindest in meinem Fall unansehnlich machte. Ich meine, auch ich habe die gleiche .fakeHover-Klasse hinzugefügt/über mouseenter und mouseleave Ereigniserkennung entfernt/entfernt, aber das allein wirkt per se fast genauso wie "echter" :hover. Ich meine: Wenn Sie auf ein Element in Ihrer Tabelle tippen, erkennt es nicht, dass Sie es "verlassen" haben - und behält den Status "fakehover" bei.

Was ich getan habe, war einfach auf click zu hören. Wenn ich also auf die Schaltfläche "tippe", feuere ich manuell eine mouseleave ab.

Das ist mein endgültiger Code:

.fakeHover {
    background-color: blue;
}


$(document).on('mouseenter', 'button.myButton',function(){
    $(this).addClass('fakeHover');
});

$(document).on('mouseleave', 'button.myButton',function(){
    $(this).removeClass('fakeHover');
});

$(document).on('button.myButton, 'click', function(){
    $(this).mouseleave();
});

Auf diese Weise behalten Sie die übliche hover-Funktionalität bei, wenn Sie eine Maus verwenden, wenn Sie einfach auf Ihren Tasten "schweben". Nun, fast alles: Der einzige Nachteil ist, dass der Button nach dem Klicken mit der Maus nicht im hover-Zustand ist. Ähnlich wie wenn Sie auf den Button geklickt und den Zeiger schnell genommen hätten. Aber in meinem Fall kann ich damit leben.

2
Pere

Fügen Sie diesen JS-Code zu Ihrer Seite hinzu:

document.body.className = 'ontouchstart' in document.documentElement ? '' : 'hover';

fügen Sie nun in Ihrem CSS vor jedem Hover die Hover-Klasse folgendermaßen hinzu:

.hover .foo:hover {}

Wenn es sich bei dem Gerät um Berührung handelt, ist die Body-Klasse leer. Andernfalls wird die Klasse als Schwebeflug angezeigt und die Regeln werden angewendet!

1
Ali

Eine Lösung, die für mich funktioniert hat:

html {
   -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

Fügen Sie diesen Code Ihrem Stylesheet hinzu.

Ich wollte den grauen Hintergrund entfernen, der in iOS Safari angezeigt wird, wenn auf einen Link geklickt wird. Aber es scheint mehr zu tun. Jetzt wird ein Klick auf eine Schaltfläche (mit einer :hover Pseudoklasse!) Sofort geöffnet! Ich habe es nur auf einem iPad getestet, ich weiß nicht, ob es auf anderen Geräten funktioniert. 

1
Leon Vogler

Ich glaube, ich habe eine elegante (minimale js) Lösung für ein ähnliches Problem gefunden:

Mit jQuery können Sie mit .mouseover() einen Schwebeflug am Körper (oder einem anderen Element) auslösen.

Also füge ich einfach einen this-Handler an das ontouchend -Ereignis des Elements an:

var unhover = function() {
  $("body").mousover();  
};
.hoverable {
  width: 100px;
  height: 100px;
  background: teal;
  cursor: pointer;
}

.hoverable:hover {
  background: pink;
}
<div class="hoverable" ontouchend={unhover}></div>

Dies entfernt jedoch nur: hover-Pseudoklasse aus dem Element, nachdem ein anderes Berührungsereignis ausgelöst wurde, wie Wischen oder eine andere Berührung 

1
Ian Averno

Sie können den Hover-Effekt für Geräte außer Kraft setzen, die Hover nicht unterstützen. Mögen:

.my-thing {
    color: #BADA55;
}

.my-thing:hover {
    color: hotpink;
}

@media (hover: none) {
    .my-thing {
        color: #BADA55;
    }
}

Getestet und überprüft unter iOS 12

Hat Tipp an https://stackoverflow.com/a/50285058/178959 für diesen Hinweis.

1
OrganicPanda

Dies ist, worauf ich bisher gekommen bin, nachdem ich die restlichen Antworten studiert hatte. Es sollte in der Lage sein, Touch-Only-, Mouse-Only- oder Hybrid-Benutzer zu unterstützen.

Erstellen Sie eine separate Hover-Klasse für den Hover-Effekt. Fügen Sie diese Schaltfläche standardmäßig unserer Schaltfläche hinzu.

Wir möchten die Touch-Unterstützung nicht erkennen und alle Hover-Effekte von Anfang an deaktivieren. Wie bereits erwähnt, gewinnen Hybridgeräte an Beliebtheit; Menschen können Berührungsunterstützung haben, möchten aber eine Maus verwenden und umgekehrt. Entfernen Sie daher die Hover-Klasse nur dann, wenn der Benutzer die Schaltfläche tatsächlich berührt.

Das nächste Problem ist, was ist, wenn der Benutzer nach dem Berühren der Schaltfläche wieder mit der Maus arbeiten möchte? Um das zu lösen, müssen wir einen günstigen Zeitpunkt finden, um die entfernte Hover-Klasse wieder hinzuzufügen.

Es kann jedoch nicht sofort nach dem Entfernen wieder hinzugefügt werden, da der Hover-Status noch aktiv ist. Möglicherweise möchten wir auch nicht die gesamte Schaltfläche zerstören und neu erstellen.

Also dachte ich daran, einen Algorithmus mit beschäftigtem Warten (mit setInterval) zu verwenden, um den Hover-Status zu überprüfen. Sobald der Hover-Status deaktiviert ist, können wir die Hover-Klasse wieder hinzufügen und das Warten auf lange Wartezeiten beenden, wodurch wir in den ursprünglichen Zustand zurückkehren, in dem der Benutzer entweder Maus oder Berührung verwenden kann.

Ich weiß, dass das Warten mit Wartenden nicht so toll ist, aber ich bin mir nicht sicher, ob es ein passendes Ereignis gibt. Ich habe mir überlegt, es im Mouseleave-Event wieder hinzuzufügen, aber es war nicht sehr robust. Wenn beispielsweise nach dem Berühren der Schaltfläche eine Warnmeldung angezeigt wird, verschiebt sich die Mausposition, das Mauseleave-Ereignis wird jedoch nicht ausgelöst.

var button = document.getElementById('myButton');

button.ontouchstart = function(e) {
  console.log('ontouchstart');
  $('.button').removeClass('button-hover');
  startIntervalToResetHover();
};

button.onclick = function(e) {
  console.log('onclick');
}

var intervalId;

function startIntervalToResetHover() {
  // Clear the previous one, if any.
  if (intervalId) {
    clearInterval(intervalId);
  }
  
  intervalId = setInterval(function() {
    // Stop if the hover class already exists.
    if ($('.button').hasClass('button-hover')) {
      clearInterval(intervalId);
      intervalId = null;
      return;
    }
    
    // Checking of hover state from 
    // http://stackoverflow.com/a/8981521/2669960.
    var isHovered = !!$('.button').filter(function() {
      return $(this).is(":hover");
    }).length;
    
    if (isHovered) {
      console.log('Hover state is active');
    } else {
      console.log('Hover state is inactive');
      $('.button').addClass('button-hover');
      console.log('Added back the button-hover class');
      
      clearInterval(intervalId);
      intervalId = null;
    }
  }, 1000);
}
.button {
  color: green;
  border: none;
}

.button-hover:hover {
  background: yellow;
  border: none;
}

.button:active {
  border: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='myButton' class='button button-hover'>Hello</button>

Edit: Ein anderer Ansatz, den ich ausprobiert habe, ist, e.preventDefault() innerhalb von onuchstart oder onuchend aufzurufen. Es scheint den Hover-Effekt anzuhalten, wenn die Schaltfläche berührt wird. Sie stoppt jedoch auch die Animation der Schaltflächenklicks und verhindert, dass die Onclick-Funktion aufgerufen wird, wenn die Schaltfläche berührt wird. Sie müssen diese also manuell im Handler onuchstart oder onuchend aufrufen. Keine sehr saubere Lösung.

1
Kevin Lee

Ich könnte eine No-Hover-Klasse für jeden Button hinzufügen und mein CSS folgendermaßen machen: button: not (.no-hover): hover {Hintergrundfarbe: Blau; } Aber das ist wahrscheinlich ziemlich schlecht für die Leistung und behandelt> Geräte wie das Chromebook Pixel (das sowohl einen Touchscreen als auch eine Maus hat)> nicht richtig.

Dies ist der richtige Ausgangspunkt. Nächster Schritt: Nohover-Klasse für folgende Ereignisse anwenden/entfernen (Demo mit jQuery)

buttonelement
 .on("touchend touchcancel",function(){$(this).addClass("nohover")})
 .on("touchstart mouseover",function({$(this).removeClass("nohover")});   

Hinweis: Wenn Sie andere Klassen auf das buttonelement anwenden möchten, funktionieren die:: (.nohover) im CSS nicht mehr wie erwartet. Dann müssen Sie stattdessen eine separate Definition mit dem Standardwert und! Wichtigen Tag hinzufügen, um den Hover-Stil zu überschreiben: .nohover {Hintergrundfarbe: weiß! wichtig} 

Dies sollte sogar mit Geräten wie dem Chromebook Pixel (das sowohl einen Touchscreen als auch eine Maus besitzt) korrekt umgehen! Und ich denke nicht, dass dies ein großer Performancekiller ist ...

1
Sascha Hendel

Es war hilfreich für mich: 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");
                    }
                }
            }
        }
    }
}
1
mineroot

Sie können diesen Weg versuchen.

javascript:

var isEventSupported = function (eventName, elementName) {
    var el = elementName ? document.createElement(elementName) : window;
    eventName = 'on' + eventName;
    var isSupported = (eventName in el);
    if (!isSupported && el.setAttribute) {
        el.setAttribute(eventName, 'return;');
        isSupported = typeof el[eventName] == 'function';
    }
    el = null;
    return isSupported;
};

if (!isEventSupported('touchstart')) {
    $('a').addClass('with-hover');
}

css:

a.with-hover:hover {
  color: #fafafa;
}
0

Sie können die Hintergrundfarbe für den :active-Status festlegen und :focus den defauten Hintergrund zuweisen.

wenn Sie die Hintergrundfarbe über onfocus/ontouch einstellen, bleibt der Farbstil erhalten, sobald der :focus-Status verschwunden ist.
Sie müssen auch auf onblur zurücksetzen, um defeg bg wiederherzustellen, wenn der Fokus verloren geht.

0
G-Cyr

Basierend auf der Antwort von Darren Cooks, die auch funktioniert, wenn Sie Ihren Finger über ein anderes Element bewegen.

Siehe Finger des Elements suchen ist während eines Touchend-Ereignisses aktiviert

jQuery(function() {
    FastClick.attach(document.body);
});
// Prevent sticky hover effects for buttons on touch devices
// From https://stackoverflow.com/a/17234319
//
//
// Usage:
// <a href="..." touch-focus-fix>..</a>
//
// Refactored from a directive for better performance and compability
jQuery(document.documentElement).on('touchend', function(event) {
  'use strict';

  function fix(sourceElement) {
    var el = $(sourceElement).closest('[touch-focus-fix]')[0];
    if (!el) {
      return;
    }
    var par = el.parentNode;
    var next = el.nextSibling;
    par.removeChild(el);
    par.insertBefore(el, next);
  }

  fix(event.target);
  var changedTouch = event.originalEvent.changedTouches[0];
  // http://www.w3.org/TR/2011/WD-touch-events-20110505/#the-touchend-event
  if (!changedTouch) {
    return;
  }
  var touchTarget = document.elementFromPoint(changedTouch.clientX, changedTouch.clientY);
  if (touchTarget && touchTarget !== event.target) {
    fix(touchTarget);
  }
});

Codepen Demo

0
jantimon

Ich habe eine Nice-Lösung, die ich gerne weitergeben möchte. Zuerst müssen Sie feststellen, ob der Benutzer wie folgt auf dem Handy ist:

var touchDevice = /ipad|iphone|Android|windows phone|blackberry/i.test(navigator.userAgent.toLowerCase());

Dann füge einfach hinzu:

if (!touchDevice) {
    $(".navbar-ul").addClass("hoverable");
}

Und in CSS:

.navbar-ul.hoverable li a:hover {
    color: #fff;
}
0
Michał Reszka

Was ich bisher in meinen Projekten getan habe war, die :hover-Änderungen auf Touch-Geräten rückgängig zu machen:

.myhoveredclass {
    background-color:green;
}
.myhoveredclass:hover {
    background-color:red;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
    .myhoveredclass:hover, .myhoveredclass:active, .myhoveredclass:focus {
        background-color:green;
    }
}

Alle Klassennamen und genannten Farben nur zu Demonstrationszwecken ;-)

0
z00l

Dies funktioniert perfekt in 2 Schritten.

  1. Stellen Sie Ihr Körper-Tag so ein, dass es <body ontouchstart=""> ist. Ich bin kein Fan dieses "Hacks", aber Safari auf iOS kann sofort auf Berührungen reagieren. Nicht sicher wie, aber es funktioniert.

  2. Richten Sie Ihre berührbare Klasse folgendermaßen ein:

    // I did this in SASS, but this should work with normal CSS as well
    
    // Touchable class
    .example {
    
        // Default styles
        background: green;
    
        // Default hover styles 
        // (Think of this as Desktop and larger)
        &:hover {
            background: yellow;
        }
    
        // Default active styles
        &:active {
            background: red;
        }
    
        // Setup breakpoint for smaller device widths
        @media only screen and (max-width: 1048px) {
    
            // Important!
            // Reset touchable hover styles
            // You may want to use the same exact styles as the Default styles
            &:hover {
                background: green;
            }
    
            // Important!
            // Touchable active styles
            &:active {
                background: red;
            }
        }
    }
    

Sie können auch alle Animationen aus Ihrer berührbaren Klasse entfernen. Android Chrome scheint etwas langsamer als iOS zu sein.

Dies führt auch dazu, dass der aktive Status angewendet wird, wenn der Benutzer die Seite scrollt, während Sie Ihre Klasse berühren.

0
Michael

Einige der Probleme mit :hover:focus:active auf mobilen Geräten können durch den fehlenden <meta name="viewport" content="width=device-width"> verursacht werden, wenn die Browser versuchen, den Bildschirm zu manipulieren.

0
GEkk

Ich ging durch das ähnliche Problem, meine Anwendung war für alle Bildschirmgrößen kompatibel und hatte eine Menge Hover-Effekte auf Desktop-Bildschirmgröße/mausbasierten Geräten verursachten einen Zustand, der als "Sticky-Hover" bezeichnet wurde, und es war eine Hürde, dass die App für Benutzer von Touch-basierten Geräten ordnungsgemäß funktionierte.

Wir haben SCSS in unserer App verwendet. und ich habe ein mixin definiert, um auf berührungsbasierte Geräte aufzupassen.

@mixin hover-support {
  @media not all and (pointer: coarse) {
    &:hover {
      @content;
    }
  }
}

und dann habe ich alle meine CSS-Klassen unter das unten genannte Snippet gestellt.

   @include hover-support() {
    // Your css-classes or css that you want to apply on those devices that support hover.
   }

Zum Beispiel hatten wir eine Klasse zum Animieren eines Symbols, die ausgelöst wurde, sobald wir über das Symbol gefahren sind, wie Sie es in CSS sehen können, aber auf einem berührungsbasierten Gerät wurde es durch einen Sticky-Hover-Effekt beeinflusst und dann habe ich es hineingestellt. @ include hover-support () um sicherzustellen, dass der Schwebeflug nur für Geräte gilt, die den Schwebeflug unterstützen.

@include hover-support() {
  .animate-icon {
    -webkit-transition: all 0.2s;
    transition: all 0.2s;
    &:hover {
      transform: scale(1.3);
      filter: brightness(85%);
      cursor: pointer;
    }
  }
}
0
Divyanshu Rawat

Das funktionierte für mich: das Schwebeflug-Styling in eine neue Klasse zu bringen

.fakehover {background: red}

Fügen Sie dann die Klasse nach Bedarf hinzu bzw. entfernen Sie sie

$(".someclass > li").on("mouseenter", function(e) {
  $(this).addClass("fakehover");
});
$(".someclass > li").on("mouseleave", function(e) {
  $(this).removeClass("fakehover");
});

Wiederholen Sie diesen Vorgang für Touchstart- und Touchend-Ereignisse. Oder welche Ereignisse auch immer Sie wünschen, um das gewünschte Ergebnis zu erzielen, z. B. sollte der Hover-Effekt auf einem Touchscreen aktiviert werden.

0
Rodney