web-dev-qa-db-fra.com

Comment simuler un survol avec un navigateur activé au toucher?

Avec du HTML comme celui-ci:

<p>Some Text</p>

Puis quelques CSS comme ceci:

p {
  color:black;
}

p:hover {
  color:red;
}

Comment puis-je autoriser un contact prolongé sur un périphérique tactile avec la réplication en vol stationnaire? Je peux changer le balisage/utiliser JS, etc., mais je ne peux pas penser à un moyen facile de le faire.

112
Rich Bradshaw

OK, j'ai réussi! Cela implique de modifier légèrement le CSS et d’ajouter du JS.

Utiliser jQuery pour simplifier les choses:

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

En anglais: lorsque vous commencez ou mettez un terme au toucher, activez ou désactivez la classe hover_effect.

Ensuite, dans votre code HTML, ajoutez un survol de classe à tout ce avec quoi vous souhaitez que cela fonctionne. Dans votre CSS, remplacez toute instance de:

element:hover {
    rule:properties;
}

avec

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

Et juste pour plus d’utilité, ajoutez ceci à votre CSS:

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

Pour arrêter le navigateur vous demandant de copier/enregistrer/sélectionner l'image ou quoi que ce soit.

Facile!

164
Rich Bradshaw

Tout ce que vous avez à faire est de lier Touchstart à un parent. Quelque chose comme ça va marcher:

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

Vous n'avez rien à faire dans la fonction, laissez-la vide. Cela sera suffisant pour obtenir des survols au toucher, de sorte qu'un contact se comporte davantage comme: survol et moins comme: actif. Magie iOS.

50
Razvan Cercelaru

Essaye ça:

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

Et dans votre 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*/
}

Avec ce code, vous n'avez pas besoin d'un cours supplémentaire .hover!

39
Anselm

Pour répondre à votre question principale: "Comment simuler un survol avec un navigateur tactile?"

Permettez simplement de "cliquer" sur l’élément (en touchant l’écran), puis de déclencher l’événement hover à l’aide de JavaScript.

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

Cela devrait fonctionner tant qu’il existe un événement hover sur votre périphérique (même s’il n’est normalement pas utilisé).

Mise à jour: Je viens de tester cette technique sur mon iPhone et cela semble bien fonctionner. Essayez-le ici: http://jsfiddle.net/mathias/YS7ft/show/light/

Si vous souhaitez utiliser une "longue touche" pour déclencher le survol, vous pouvez utiliser le fragment de code ci-dessus comme point de départ et vous amuser avec les minuteries et d'autres choses;)

25
Mathias Bynens

Solution améliorée

J'ai d'abord suivi l'approche de Rich Bradshaw, mais des problèmes ont commencé à apparaître. En exécutant l'événement e.preventDefault () sur 'touchstart', la page ne défile plus et aucun appui long ne permet d'activer le menu d'options ni de double-cliquer sur le zoom pour terminer l'exécution. 

Une solution pourrait être de trouver quel événement est appelé et juste e.preventDefault () dans le dernier, 'touchend'. Comme le 'touchmove' de scroll vient avant 'le touchend', il reste comme par défaut et le 'clic' est également empêché car il vient après les mots de la chaîne d'événements appliquée au mobile, comme suit:

// 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');
});

Mais ensuite, lorsque le menu des options apparaît, il ne déclenche plus le 'touchend' responsable de basculer hors de la classe, et la prochaine fois que le comportement de survol sera inversé, totalement mélangé. 

Une solution serait alors, encore une fois, de trouver conditionnellement quel événement nous sommes, ou juste de faire des événements séparés, et d'utiliser addClass () et removeClass () respectivement sur 'touchstart' et 'touchend', en s'assurant qu'il commence et finit toujours par l'ajout et la suppression au lieu de le décider conditionnellement. Pour finir, nous allons également lier la suppression du rappel au type d'événement 'focusout', en restant responsables de la suppression de la classe de survol de tout lien pouvant rester activé et ne jamais être revisité, comme suit:

$('.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');
});

Attention: Certains bugs surviennent encore dans les deux solutions précédentes et, pensez aussi (non testé), le zoom double-clic échoue également.

Bien rangé et si tout va bien sans bug (pas :)) Solution Javascript

Now, pour une seconde approche, plus propre, plus ordonnée et réactive, utilisant seulement du javascript (pas de mix entre la classe .hover et le pseudo: hover) et d'où vous pouvez appeler directement votre comportement ajax sur l'universel (mobile et desktop) 'click' event, j'ai trouvé une question plutôt bien résolue à partir de laquelle j'ai enfin compris comment je pouvais mélanger des événements tactiles et de la souris sans plusieurs rappels d'événement, changeant inévitablement les uns des autres dans la chaîne d'événements. Voici comment:

$('.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!
    }
});
13
Alexandre Rosário

L'effet de la souris hover ne peut pas être implémenté dans un périphérique tactile. Quand je suis apparu avec la même situation dans safariios j'ai utilisé :active en css pour faire effet.

c'est à dire.

p:active {
  color:red;
}

Dans mon cas, cela fonctionne. Peut-être est-ce également le cas qui peut être utilisé sans utiliser javascript. Juste essayer.

3
sijo vijayan

Ajoutez ce code, puis définissez la classe "tapHover" sur les éléments sur lesquels vous souhaitez travailler de la sorte . La première fois que vous tapez sur un élément, il gagne la pseudo-classe ": hover" et la classe "tapée". L'événement de clic sera empêché . La deuxième fois que vous appuyez sur le même élément, l'événement de clic sera déclenché.

// 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>

2
l00k

Une façon de le faire serait de faire l'effet de survol lorsque le contact commence, puis de supprimer l'effet de survol lorsque le contact se déplace ou se termine.

C’est ce que Apple a à dire à propos de la manipulation tactile en général, puisque vous parlez de l’iPhone.

1
drawnonward

Sans JS spécifique à un appareil (ou plutôt à un navigateur), je suis sûr que vous n'avez pas de chance.

Edit: pensais que vous vouliez éviter cela jusqu'à ce que je relise votre question. Dans le cas de Mobile Safari, vous pouvez vous inscrire pour obtenir tous les événements tactiles similaires à ce que vous pouvez faire avec UIView-s natif. Vous ne trouvez pas la documentation pour le moment, tenterez de le faire.

1
Joonas Trussmann

Mon goût personnel est d'attribuer les styles :hover à l'état :focus, comme suit:

p {
    color: red;
}

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

Puis avec le code HTML suivant:

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

Et le JavaScript suivant:

$("#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();
    }
});
1
pimbrouwers

Un mélange de Javascript et de 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' );
     });
   }
0
Codebeat

La solution la plus simple que j'ai trouvée: j'avais quelques balises <span> avec les règles: hover css J'ai changé pour <a href = "javascript: void (0)"> et voilà. Les styles de survol dans iOS ont commencé à fonctionner.

0
Becario Senior

Résolu 2019 - Survolez le toucher

Il semble maintenant préférable d'éviter d'utiliser le survol avec iOS ou le toucher en général. Le code ci-dessous applique votre css tant que le contact est maintenu et sans autres flyouts ios. Faire ceci;

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

  2. CSS: remplacez p: hover par p: focus et ajoutez p: actif 

Les options;

  • remplace le sélecteur jquery p par n'importe quelle classe, etc.

  • pour que l'effet reste, gardez p: hover également, et ajoutez body {cursor: ponter;} pour qu'un tap n'importe où le termine

  • essayez les événements click & mouseover ainsi que touchstart dans le même code (mais non testé)

  • supprimer e.preventDefault (); pour permettre aux utilisateurs d’utiliser les flyouts ios, par exemple copie

Remarques 

  • testé uniquement pour les éléments de texte, ios peut traiter les entrées, etc. différemment

  • testé uniquement sur iphone XR ios 12.1.12 et ipad 3 ios 9.3.5, avec Safari ou Chrome.

0
darren

Use peut aussi utiliser CSS, ajouter le focus et active (pour IE7 et inférieur) au lien caché. Exemple de menu ul dans un menu div avec classe:

.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;}

Il est tard et n'a pas été testé, ça devrait marcher ;-)

0
Mark Groen