Wie simuliere ich einen Hover mit einem Touch-in-Touch-fähigen Browser?

120

Mit etwas HTML wie diesem:

<p>Some Text</p>

Dann einige CSS wie folgt:

p {
  color:black;
}

p:hover {
  color:red;
}

Wie kann ich zulassen, dass eine lange Berührung eines berührungsfähigen Geräts den Schwebeflug repliziert? Ich kann Markup ändern / JS usw. verwenden, kann mir aber keinen einfachen Weg vorstellen, dies zu tun.

Rich Bradshaw
quelle
Ich denke speziell an das iPhone-Betriebssystem - es ist eine Demo der CSS-Animation, bei der es für viele einfach ist, den Mauszeiger zu verwenden, anstatt zu klicken.
Rich Bradshaw

Antworten:

172

OK, ich habe es geschafft! Dazu muss das CSS leicht geändert und JS hinzugefügt werden.

Verwenden Sie jQuery, um es einfach zu machen:

$(document).ready(function() {
    $('.hover').on('touchstart touchend', function(e) {
        e.preventDefault();
        $(this).toggleClass('hover_effect');
    });
});

Auf Englisch: Wenn Sie eine Berührung beginnen oder beenden, schalten Sie die Klasse hover_effectein oder aus.

Fügen Sie dann in Ihrem HTML-Code einen Klassen-Hover zu allem hinzu, mit dem dies funktionieren soll. Ersetzen Sie in Ihrem CSS eine beliebige Instanz von:

element:hover {
    rule:properties;
}

mit

element:hover, element.hover_effect {
    rule:properties;
}

Und nur für zusätzlichen Nutzen, fügen Sie dies auch Ihrem CSS hinzu:

.hover {
-webkit-user-select: none;
-webkit-touch-callout: none;        
}

Um den Browser zu stoppen, werden Sie aufgefordert, das Bild oder was auch immer zu kopieren / speichern / auswählen.

Einfach!

Rich Bradshaw
quelle
Das ist toll. Ich habe die Domready-Funktion jedoch aufgeteilt, da sie toggledie Dinge durcheinander bringt, wenn der Benutzer ein Element berührt und zu einem anderen zieht (z. B. wenn er das falsche Element berührt und versucht, die Berührung abzubrechen)
Jacksonkr
Ich habe touchendund preventDefault()in meiner Website entfernt und es funktioniert gut, aber jetzt werden Menüs nicht automatisch durch Tippen außerhalb des Ziels geschlossen.
26аниил Пронин
Ich hätte auch gerne einen Rat, wie man ein solches Menü schließt, wenn der Benutzer eine andere Stelle berührt oder mit dem Scrollen beginnt. Ich denke, es könnte einen anderen touchstartZuhörer am Körper geben (oder ähnliches), aber ich fragte mich, ob es einen besseren Weg gibt. Vielen Dank!
Darryl Young
2
Gibt es überhaupt eine Scroll-Geste zu ignorieren? Dies macht genau das, was ich brauche, aber jetzt kann ich den Inhalt, der diesen Effekt hat, nicht mehr auf und ab scrollen.
Alsobubbly
1
Ich habe den PreventDefault entfernt, da das Scrollen verfügbar sein soll, aber danke für die Tipps zu Touchstart und Touchend! Gott schicke dies ist die einzige Antwort, die in allen Browsern zuverlässig funktioniert.
Petraeus
54

Alles, was Sie tun müssen, ist Touchstart an ein Elternteil zu binden. So etwas wird funktionieren:

$('body').on('touchstart', function() {});

Sie müssen nichts in der Funktion tun, lassen Sie es leer. Dies reicht aus, um den Schwebeflug in Berührung zu bringen, sodass sich eine Berührung eher wie Schwebeflug und weniger wie Aktiv verhält. iOS Magie.

Razvan Cercelaru
quelle
2
Ermöglicht diese Lösung, dass der Link beim zweiten Tippen ausgeführt wird?
Samuelkobe
1
Nein, es wird immer noch der Klick auf die erste Berührung ausgelöst. Ich habe es gerade getestet.
Jack
Tolle Lösung! Schnell und einfach.
Hunter Turner
41

Versuche dies:

<script>
document.addEventListener("touchstart", function(){}, true);
</script>

Und in Ihrem CSS:

element:hover, element:active {
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-user-select: none;
-webkit-touch-callout: none /*only to disable context menu on long press*/
}

Mit diesem Code benötigen Sie keine zusätzliche .hover-Klasse!

Anselm
quelle
1
Dies funktioniert für mich. Einige andere Dinge, die noch mehr helfen könnten, sind, anstatt Javascript hinzuzufügen. Gehen Sie folgendermaßen vor: <body ontouchstart = ""> Fügen Sie dann einen kleinen Timer in das Ereignis css: active ein: tr: active {Hintergrundfarbe : # 118aab; Übergang: alle .2s linear; -Webkit-Tap-Highlight-Farbe: rgba (0,0,0,0); -webkit-user-select: keine; -webkit-touch-callout: keine}
Kozy
Hat für mich gearbeitet. Danke ... Das einzige - es bleibt ein bisschen zurück ... ich meine - nachdem Sie gedrückt haben, wird es nicht sofort geladen.
Roman Losev
Verwenden Sie fastclick.js, um die Verzögerung zu entfernen
Anselm
25

Um Ihre Hauptfrage zu beantworten: "Wie simuliere ich einen Schwebeflug mit einem Touch-in-Touch-fähigen Browser?"

Erlauben Sie einfach das Klicken auf das Element (durch Tippen auf den Bildschirm) und lösen Sie das hoverEreignis dann mit JavaScript aus.

var p = document.getElementsByTagName('p')[0];
p.onclick = function() {
 // Trigger the `hover` event on the paragraph
 p.onhover.call(p);
};

Dies sollte funktionieren, solange sich hoverauf Ihrem Gerät ein Ereignis befindet (obwohl es normalerweise nicht verwendet wird).

Update: Ich habe diese Technik gerade auf meinem iPhone getestet und sie scheint gut zu funktionieren. Probieren Sie es hier aus: http://jsfiddle.net/mathias/YS7ft/show/light/

Wenn Sie stattdessen eine 'lange Berührung' verwenden möchten, um den Schwebeflug auszulösen, können Sie das obige Code-Snippet als Ausgangspunkt verwenden und Spaß mit Timern und anderen Dingen haben;)

Mathias Bynens
quelle
Ich wusste nichts über dieses onhover.call (p) -Bit, das ist ziemlich cool. Es gibt jedoch keinen Schwebeflug ...
Rich Bradshaw
Haben Sie dies mit mehreren Elementen und langer Berührung getestet? Bedeutet das, dass der Benutzer seinen Finger über den Bildschirm bewegt und für jedes Element einen Schwebestil anzeigt?
Marcus
Wenn Sie jQuery bereits verwenden, können Sie das Hover-Ereignis möglicherweise einfach mit jQuery selbst aufrufen, z. B.: JQuery.hover (); Ich bin mir jedoch nicht sicher, ob die API dies unterstützt.
Kzqai
Hoppla, das war ein Kommentar, der eher für den obigen Beitrag gilt, der tatsächlich jQuery verwendet, sorry.
Kzqai
Benötigen Sie spezielle Skripte oder rufen Sie die Funktion auf? Es funktioniert für mich aber nur auf einer Seite und ich weiß nicht, was der Unterschied ist.
Richard Young
13

Weitere verbesserte Lösung

Zuerst habe ich mich für den Ansatz von Rich Bradshaw entschieden , aber dann traten Probleme auf. Durch Ausführen von e.preventDefault () beim 'Touchstart'- Ereignis wird die Seite nicht mehr gescrollt, und weder das lange Drücken des Optionsmenüs noch das Doppelklicken des Zooms können die Ausführung beenden.

Eine Lösung könnte darin bestehen, herauszufinden, welches Ereignis aufgerufen wird, und nur e.preventDefault () im späteren 'touchend' . Da der 'touchmove' von scroll vor 'touchend' steht , bleibt er standardmäßig erhalten, und 'click' wird ebenfalls verhindert, da es sich um Nachwörter in der Ereigniskette handelt, die auf Mobilgeräte angewendet werden, wie folgt:

// Binding to the '.static_parent' ensuring dynamic ajaxified content
$('.static_parent').on('touchstart touchend', '.link', function (e) {

    // If event is 'touchend' then...
    if (e.type == 'touchend') {
        // Ensuring we event prevent default in all major browsers
        e.preventDefault ? e.preventDefault() : e.returnValue = false;
    }

    // Add class responsible for :hover effect
    $(this).toggleClass('hover_effect');
});

Wenn dann das Optionsmenü angezeigt wird, wird kein "Touchend" mehr ausgelöst, das für das Ausschalten der Klasse verantwortlich ist, und beim nächsten Mal ist das Schwebeverhalten umgekehrt, völlig durcheinander.

Eine Lösung wäre dann wiederum, unter bestimmten Bedingungen herauszufinden, in welchem ​​Ereignis wir uns befinden, oder nur separate Ereignisse durchzuführen und addClass () bzw. removeClass () für 'touchstart' und 'touchend' zu verwenden , um sicherzustellen, dass es immer beginnt und endet jeweils hinzufügen und entfernen, anstatt sich bedingt dafür zu entscheiden. Zum Abschluss binden wir den Rückruf zum Entfernen auch an den Ereignistyp "focusout" und bleiben dafür verantwortlich , die Schwebeklasse eines Links zu löschen, die möglicherweise aktiviert bleibt und nie wieder besucht wird, wie folgt :

$('.static_parent').on('touchstart', '.link', function (e) {
    $(this).addClass('hover_effect');
});

$('.static_parent').on('touchend focusout', '.link', function (e) {
    // Think double click zoom still fails here
    e.preventDefault ? e.preventDefault() : e.returnValue = false;
    $(this).removeClass('hover_effect');
});

Achtung: Einige Fehler treten immer noch in den beiden vorherigen Lösungen auf, und denken Sie (nicht getestet), dass der Doppelklick-Zoom auch immer noch fehlschlägt.

Ordentliche und hoffentlich fehlerfreie (nicht :)) Javascript-Lösung

Nun , für eine zweite, sauberer, aufgeräumter und reaktions Ansatz nur mit Hilfe von Javascript (kein zwischen .hover Klasse und Pseudo mischen: Hover) und von wo aus Sie direkt Ihr Ajax - Verhalten auf der universellen nennen könnte (mobile und Desktop) ‚Klick‘ Event Ich habe eine ziemlich gut beantwortete Frage gefunden, anhand derer ich endlich verstanden habe, wie ich Berührungs- und Mausereignisse miteinander mischen kann, ohne dass mehrere Ereignisrückrufe zwangsläufig die Ereignisse in der Ereigniskette ändern. Hier ist wie:

$('.static_parent').on('touchstart mouseenter', '.link', function (e) {
    $(this).addClass('hover_effect');
});

$('.static_parent').on('mouseleave touchmove click', '.link', function (e) {
    $(this).removeClass('hover_effect');

    // As it's the chain's last event we only prevent it from making HTTP request
    if (e.type == 'click') {
        e.preventDefault ? e.preventDefault() : e.returnValue = false;

        // Ajax behavior here!
    }
});
Alexandre Rosário
quelle
3

Der Mauseffekt hoverkann nicht in Touch-Geräten implementiert werden. Wenn ich mit der gleichen Situation in erschienen safari iosbin, habe ich verwendet:active in CSS verwendet, um Wirkung zu erzielen.

dh.

p:active {
  color:red;
}

In meinem Fall funktioniert es. Möglicherweise ist dies auch der Fall, der ohne Verwendung von Javascript verwendet werden kann. Probieren Sie es einfach aus.

sijo vijayan
quelle
2

Fügen Sie diesen Code hinzu und setzen Sie die Klasse "tapHover" auf Elemente, die Sie auf diese Weise arbeiten möchten. Wenn Sie zum ersten Mal auf ein Element tippen, erhält es die Pseudoklasse ": hover" und die Klasse "tapped". Klickereignis wird verhindert. Wenn Sie zum zweiten Mal auf dasselbe Element tippen, wird ein Klickereignis ausgelöst.

// Activate only in devices with touch screen
if('ontouchstart' in window)
{
    // this will make touch event add hover pseudoclass
    document.addEventListener('touchstart', function(e) {}, true);

    // modify click event
    document.addEventListener('click', function(e) {
        // get .tapHover element under cursor
        var el = jQuery(e.target).hasClass('tapHover')
            ? jQuery(e.target)
            : jQuery(e.target).closest('.tapHover');

        if(!el.length)
            return;

        // remove tapped class from old ones
        jQuery('.tapHover.tapped').each(function() {
            if(this != el.get(0))
                jQuery(this).removeClass('tapped');
        });

        if(!el.hasClass('tapped'))
        {
            // this is the first tap
            el.addClass('tapped');
            e.preventDefault();
            return false;
        }
        else
        {
            // second tap
            return true;
        }
    }, true);
}
.box {
	float:		left;
	
	display:	inline-block;
	margin:		50px 0 0 50px;
	width:		100px;
	height:		100px;
	overflow:	hidden;
	
	font-size:	20px;
	
	border:		solid 1px black;
}
.box.tapHover {
	background:	yellow;
}
.box.tapped {
	border:		solid 3px red;
}
.box:hover {
	background:	red;
}
<div class="box" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
<div class="box tapHover" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
<div class="box tapHover" onclick="this.innerHTML = Math.random().toFixed(5)"></div>

100k
quelle
1

Ohne gerätespezifisches (oder besser Browser) JS bin ich mir ziemlich sicher, dass Sie kein Glück haben.

Bearbeiten: dachte, Sie wollten das vermeiden, bis ich Ihre Frage erneut las. Im Falle von Mobile Safari können Sie sich registrieren, um alle Berührungsereignisse zu erhalten, die denen mit nativen UIView-s ähneln. Ich kann die Dokumentation momentan nicht finden, werde es aber versuchen.

Joonas Trussmann
quelle
1

Eine Möglichkeit besteht darin, den Hover-Effekt zu starten, wenn die Berührung beginnt, und dann den Hover-Effekt zu entfernen, wenn sich die Berührung bewegt oder endet.

Dies ist, was Apple über das Touch-Handling im Allgemeinen zu sagen hat , da Sie das iPhone erwähnen.

nach vorne gezogen
quelle
Ist der Linkinhalt jetzt noch relevant?
Flavien Volken
1

Mein persönlicher Geschmack ist es, die :hoverStile auch dem :focusStaat zuzuschreiben , wie:

p {
    color: red;
}

p:hover, p:focus {
    color: blue;
}

Dann mit folgendem HTML:

<p id="some-p-tag" tabindex="-1">WOOOO</p>

Und das folgende JavaScript:

$("#some-p-tag").on("touchstart", function(e){
    e.preventDefault();
    var $elem = $(this);

    if($elem.is(":focus")) {
        //this can be registered as a "click" on a mobile device, as it's a double tap
        $elem.blur()
    }
    else {
        $elem.focus();
    }
});
Zuhälter
quelle
1

Gelöst 2019 - Hover on Touch

Es scheint jetzt am besten zu sein, Hover nicht ganz mit ios oder touch im Allgemeinen zu verwenden. Der folgende Code wendet Ihr CSS an, solange die Berührung beibehalten wird, und ohne andere ios-Flyouts. Mach das;

  1. Jquery add: $ ("p"). On ("touchstart", Funktion (e) {$ (this) .focus (); e.preventDefault ();});

  2. CSS: Ersetzen Sie p: hover durch p: focus und fügen Sie p: active hinzu

Optionen;

  • Ersetzen Sie den jquery p-Selektor durch eine beliebige Klasse usw.

  • Um den Effekt beizubehalten, halten Sie auch p: hover und fügen Sie body {cursor: ponter;} hinzu, sodass ein Tippen irgendwo darauf endet

  • Versuchen Sie Click & Mouseover-Ereignisse sowie Touchstart im selben Code (aber nicht getestet).

  • entferne e.preventDefault (); um Benutzern die Verwendung von ios-Flyouts zu ermöglichen, z. B. Kopieren

Anmerkungen

  • Nur auf Textelemente getestet, kann ios Eingaben usw. unterschiedlich behandeln

  • Nur auf dem iPhone XR ios 12.1.12 und dem ipad 3 ios 9.3.5 mit Safari oder Chrome getestet.

Darren
quelle
0

Eine Mischung aus nativem Javascript und jQuery:

var gFireEvent = function (oElem,sEvent) 
{
 try {
 if( typeof sEvent == 'string' && o.isDOM( oElem ))
 {
  var b = !!(document.createEvent),
     evt = b?document.createEvent("HTMLEvents"):document.createEventObject();
  if( b )    
  {  evt.initEvent(sEvent, true, true ); 
    return !oElem.dispatchEvent(evt);
  }
  return oElem.fireEvent('on'+sEvent,evt);
 }
 } catch(e) {}
 return false;
};


// Next you can do is (bIsMob etc you have to determine yourself):

   if( <<< bIsMob || bIsTab || bisTouch >>> )
   {
     $(document).on('mousedown', function(e)
     {
       gFireEvent(e.target,'mouseover' );
     }).on('mouseup', function(e)
     {
       gFireEvent(e.target,'mouseout' );
     });
   }
Codebeat
quelle
1
Es tut mir leid, pedantisch zu sein, aber jquery ist javacript
matpol
2
@matpol: jQuery ist Javascript, aber Javascript ist nicht jQuery. Speziell für Sie füge ich das Wort "reines", reines Javascript hinzu. Zufriedener Herr?
Codebeat
Sie können jquery nicht verwenden, ohne 'reines' Javascript zu verwenden. Ich mache nur den Punkt, weil einige Leute, die SO häufig sind, dies nicht zu wissen scheinen.
Matpol
5
Eine Mischung aus nativem Javascript und jQuery, zufrieden?
Codebeat
0

Die einfachste Lösung, die ich gefunden habe: Ich hatte einige <span> -Tags mit: hover css-Regeln. Ich wechselte zu <a href = "javascript: void (0 )"> und voilà. Die Schwebestile in iOS begannen zu funktionieren.

Becario Senior
quelle
0

Die Verwendung kann auch CSS verwenden, dem versteckten Link Fokus und Aktiv (für IE7 und darunter) hinzufügen. Beispiel eines ul-Menüs in einem div mit Klassenmenü:

.menu ul ul {display:none; position:absolute; left:100%; top:0; padding:0;}
.menu ul ul ul {display:none; position:absolute; top:0; left:100%;}
.menu ul ul a, .menu ul ul a:focus, .menu ul ul a:active { width:170px; padding:4px 4%; background:#e77776; color:#fff; margin-left:-15px; }
.menu ul li:hover > ul { display:block; }
.menu ul li ul li {margin:0;}

Es ist spät und ungetestet, sollte funktionieren ;-)

Mark Groen
quelle