Questo è quello che ho escogitato finora dopo aver studiato il resto delle risposte. Dovrebbe essere in grado di supportare utenti solo touch, solo mouse o ibridi.
Crea una classe hover separata per l'effetto hover. Per impostazione predefinita, aggiungi questa classe al passaggio del mouse sul nostro pulsante.
Non vogliamo rilevare la presenza del supporto touch e disabilitare tutti gli effetti hover fin dall'inizio. Come menzionato da altri, i dispositivi ibridi stanno guadagnando popolarità; le persone possono avere il supporto per il tocco ma vogliono usare un mouse e viceversa. Pertanto, rimuovere la classe al passaggio del mouse solo quando l'utente tocca effettivamente il pulsante.
Il prossimo problema è: cosa succede se l'utente desidera tornare a utilizzare un mouse dopo aver toccato il pulsante? Per risolverlo, dobbiamo trovare un momento opportuno per aggiungere nuovamente la classe hover che abbiamo rimosso.
Tuttavia, non è possibile aggiungerlo immediatamente dopo averlo rimosso, poiché lo stato al passaggio del mouse è ancora attivo. Potremmo non voler distruggere e ricreare anche l'intero pulsante.
Quindi, ho pensato di utilizzare un algoritmo di attesa (utilizzando setInterval) per verificare lo stato al passaggio del mouse. Una volta disattivato lo stato al passaggio del mouse, possiamo quindi aggiungere nuovamente la classe al passaggio del mouse e interrompere l'attesa di occupato, riportandoci allo stato originale in cui l'utente può utilizzare il mouse o il tocco.
So che l'attesa non è eccezionale, ma non sono sicuro che ci sia un evento appropriato. Ho preso in considerazione l'idea di aggiungerlo di nuovo nell'evento di mouseleave, ma non era molto robusto. Ad esempio, quando viene visualizzato un avviso dopo che è stato toccato il pulsante, la posizione del mouse si sposta ma l'evento di mouseleave non viene attivato.
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>
Modifica: un altro approccio che ho provato è quello di chiamare e.preventDefault()
intouchstart o ontouchend. Sembra fermare l'effetto hover quando si tocca il pulsante, ma arresta anche l'animazione del clic del pulsante e impedisce che la funzione onclick venga chiamata quando si tocca il pulsante, quindi è necessario chiamarli manualmente nel gestore intouchstart o intouchend. Non è una soluzione molto pulita.