touchend javascript css hover touch

touchend - mobile touch events javascript



Cómo evitar efectos de desplazamiento estables para botones en dispositivos táctiles (19)

Podría agregar una clase no-hover ontouchend para cada botón, y hacer mi CSS como> this: button: not (.no-hover): hover {background-color: blue; } pero probablemente sea bastante malo para el rendimiento, y no maneja> dispositivos como el Chromebook Pixel (que tiene una pantalla táctil y un mouse)> correctamente.

Este es el punto de partida correcto. Siguiente paso: aplicar / eliminar la clase nohover en los siguientes eventos (demostración con jQuery)

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

Aviso: Si desea aplicar otras clases al elemento buttone, el: no (.nohover) en el CSS ya no funcionará como se esperaba. De lo que debe agregar en su lugar una definición separada con el valor predeterminado y una etiqueta importante para sobrescribir el estilo de desplazamiento: .nohover {background-color: white! Important}

¡Esto incluso debería manejar dispositivos como el Chromebook Pixel (que tiene una pantalla táctil y un mouse) correctamente! Y no creo que sea un gran asesino de rendimiento ...

He creado un carrusel con un botón anterior y uno siguiente que siempre están visibles. Estos botones tienen un estado de desplazamiento, se vuelven azules. En los dispositivos táctiles, como iPad, el estado de desplazamiento es adhesivo, por lo que el botón permanece en azul después de tocarlo. No quiero eso.

  • Podría agregar una clase no-hover ontouchend para cada botón y hacer mi CSS así: button:not(.no-hover):hover { background-color: blue; } button:not(.no-hover):hover { background-color: blue; } pero probablemente sea bastante malo para el rendimiento, y no maneja correctamente dispositivos como el Chromebook Pixel (que tiene una pantalla táctil y un mouse).

  • Podría agregar una clase touch a documentElement y hacer mi CSS así: html:not(.touch) button:hover { background-color: blue; } html:not(.touch) button:hover { background-color: blue; } Pero eso tampoco funciona en dispositivos con toque y mouse.

Lo que preferiría es eliminar el estado de vuelo ontouchend . Pero no parece que eso sea posible. Centrar otro elemento no elimina el estado de desplazamiento. Tocar otro elemento manualmente sí lo hace, pero parece que no puedo activar eso en JavaScript.

Todas las soluciones que he encontrado parecen imperfectas. ¿Hay una solución perfecta?


Agregue este código JS a su página:

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

ahora en tu CSS antes de cada hover agrega la clase hover como esta:

.hover .foo:hover {}

Si el dispositivo es táctil, la clase del cuerpo estará vacía; de lo contrario, su clase se desplazará y las reglas se aplicarán.


Basado en la respuesta de Darren Cooks, que también funciona si mueves tu dedo sobre otro elemento.

Ver Find element finger on on durante un evento touchend

jQuery(function() { FastClick.attach(document.body); }); // Prevent sticky hover effects for buttons on touch devices // From https://.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); } });

Demo Codepen


Con Modernizr puede orientar sus objetos emergentes específicamente para dispositivos sin contacto:

(Nota: esto no se ejecuta en el sistema de fragmentos de , consulte el jsfiddle en jsfiddle lugar)

/* 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; }

Tenga en cuenta que :active no necesita ser apuntado con .no-touch porque funciona como se espera tanto en el móvil como en el escritorio.


Creo que encontré una solución elegante (mínimo js) para un problema similar:

Usando jQuery, puedes disparar el mouse sobre el cuerpo (o cualquier otro elemento), usando .mouseover()

Así que simplemente adjuntaré este controlador al evento ontouchend del elemento así:

var unhover = function() { $("body").mousover(); };

.hoverable { width: 100px; height: 100px; background: teal; cursor: pointer; } .hoverable:hover { background: pink; }

<div class="hoverable" ontouchend={unhover}></div>

Sin embargo, esto solo elimina: pseudoclases del elemento después de activarse otro evento táctil, como deslizar u otro toque.


De 4 maneras de lidiar con el vuelo estacionario fijo en el móvil : Aquí hay una forma de agregar o quitar dinámicamente una clase " can touch " al documento según el tipo de entrada actual del usuario. Funciona también con dispositivos híbridos en los que el usuario puede cambiar entre touch y mouse / trackpad:

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


Este es un problema común sin una solución perfecta. El comportamiento de desplazamiento es útil con un mouse y mayormente perjudicial con el tacto. El problema se agrava con los dispositivos que admiten el tacto y el mouse (¡al mismo tiempo, nada menos!) Como Chromebook Pixel y Surface.

La solución más limpia que he encontrado es solo habilitar el comportamiento de vuelo estacionario si el dispositivo no es compatible con la entrada táctil.

var isTouch = !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0; if( !isTouch ){ // add class which defines hover behavior }

Por supuesto, pierdes el control sobre dispositivos que puedan soportarlo. Sin embargo, a veces el desplazamiento sobre la superficie afecta más que el enlace en sí, por ejemplo, quizás desee mostrar un menú cuando un elemento está suspendido. Este enfoque le permite probar la existencia del toque y quizás adjunte un evento diferente de manera condicional.

He probado esto en el iPhone, iPad, Chromebook Pixel, Surface y en una variedad de dispositivos Android. No puedo garantizar que funcione cuando se agregue una entrada táctil USB genérica (como un lápiz) a la mezcla.


Esto es lo que he encontrado hasta ahora después de estudiar el resto de las respuestas. Debería ser compatible con usuarios solo con toque, solo con mouse o híbridos.

Crea una clase de vuelo flotante diferente para el efecto de desplazamiento. De forma predeterminada, agregue esta clase de desplazamiento a nuestro botón.

No queremos detectar la presencia de soporte táctil y desactivar todos los efectos de desplazamiento desde el principio. Como lo mencionaron otros, los dispositivos híbridos están ganando popularidad; las personas pueden tener soporte táctil pero quieren usar un mouse y viceversa. Por lo tanto, solo elimine la clase de vuelo estacionario cuando el usuario toque realmente el botón.

El siguiente problema es, ¿qué sucede si el usuario desea volver a usar un mouse después de tocar el botón? Para resolver eso, necesitamos encontrar un momento oportuno para volver a agregar la clase hover que hemos eliminado.

Sin embargo, no podemos volver a agregarlo inmediatamente después de eliminarlo, ya que el estado de desplazamiento permanece activo. Es posible que no deseemos destruir y recrear todo el botón también.

Entonces, pensé en usar un algoritmo de espera ocupado (usando setInterval) para verificar el estado de vuelo estacionario. Una vez que se desactiva el estado de desplazamiento, podemos volver a agregar la clase de vuelo estacionario y detener el tiempo de espera ocupado, volviendo al estado original donde el usuario puede usar el mouse o el tacto.

Sé que estar ocupado, esperar no es tan bueno, pero no estoy seguro de si hay un evento apropiado. He considerado agregarlo nuevamente en el evento mouseleave, pero no fue muy robusto. Por ejemplo, cuando aparece una alerta después de tocar el botón, la posición del mouse se desplaza pero el evento mouseleave no se activa.

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

Editar: Otro enfoque que probé es llamar a e.preventDefault() dentro de ontouchstart o ontouchend. Parece detener el efecto de desplazamiento cuando se toca el botón, pero también detiene la animación de clic de botón y evita que se invoque la función onclick cuando se toca el botón, por lo que debe llamarlos manualmente en el controlador ontouchstart o ontouchend. No es una solución muy limpia.


Esto funcionó para mí: poner el estilo hover en una nueva clase

.fakehover {background: red}

A continuación, agregue / elimine la clase como y cuando sea necesario

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

Repita para los eventos touchstart y touchend. O cualquiera que sea el evento que desee para obtener el resultado deseado, por ejemplo, quería que el efecto de desplazamiento se alternara en una pantalla táctil.


Esto funciona perfectamente en 2 pasos.

  1. Establezca su etiqueta de cuerpo para que sea así <body ontouchstart=""> . No soy fanático de este "truco", pero permite que Safari en iOS reaccione a los toques instantáneamente. No estoy seguro de cómo, pero funciona.

  2. Configura tu clase tangible de esta manera:

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

Es posible que desee eliminar cualquier animación en su clase tangible también. Android Chrome parece ser un poco más lento que iOS.

Esto también dará como resultado que se aplique el estado activo si el usuario se desplaza por la página mientras toca su clase.


Fue útil para mí: 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"); } } } } } }


Iba a publicar mi propia solución, pero al comprobar si alguien ya la publicó, descubrí que @Rodney casi lo hizo. Sin embargo, se perdió una última crucial que lo hizo uniseful, al menos en mi caso. Quiero decir, yo también tomé la misma adición / eliminación de la clase .fakeHover través de mouseenter y mouseleave detección de eventos, pero eso solo, per se , actúa casi exactamente como "genuino" :hover . Quiero decir: cuando tocas un elemento en tu tabla, no detectará que lo has "cortado", manteniendo así el estado de "falsa protección".

Lo que hice fue simplemente escuchar al click , también, así que cuando "toco" el botón, disparo manualmente un mouseleave .

Si este es mi código final:

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

De esta forma, mantendrá su funcionalidad de hover habitual cuando use un mouse cuando simplemente esté "pasando el mouse" por sus botones. Bueno, casi todo: el único inconveniente de alguna manera es que, después de hacer clic en el botón con el mouse, no estará en el estado de hover . Al igual que si hizo clic y rápidamente sacó el puntero del botón. Pero en mi caso puedo vivir con eso.


Lo que hice hasta ahora en mis proyectos fue revertir los cambios de :hover en dispositivos táctiles:

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

Todos los nombres de clase y colores con nombre solo para fines de demostración ;-)


Puede eliminar el estado de desplazamiento eliminando temporalmente el enlace del DOM. Ver http://testbug.handcraft.com/ipad.html

En el CSS tienes:

:hover {background:red;}

En el JS tienes:

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

Y luego en tu HTML tienes:

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


Puede establecer el color de fondo encendido :active estado :active y dar :focus el fondo predeterminado.

si configura el color de fondo mediante el onfocus/ontouch , el estilo de color permanece una vez :focus estado del :focus desapareció.
También necesita restablecer onblur para restaurar el valor predeterminado de fd cuando se pierde el foco.


Puedes intentarlo de esta manera.

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


Una solución que me ha funcionado:

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

Agregue este código a su hoja de estilo.

Quería deshacerme del fondo gris que aparece en iOS Safari cuando se hace clic en un enlace. Pero parece hacer más. Ahora, al hacer clic en un botón (con un :hover pseudoclases!) Se abre de inmediato. Solo lo probé en un iPad, no sé si funcionará en otros dispositivos.


Una vez implementado CSS Media Queries Level 4 , podrá hacer esto:

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

O en inglés: "Si el navegador admite un vuelo estacionario verdadero / verdadero / real / no emulado (p. Ej., Tiene un dispositivo de entrada principal parecido al ratón), aplique este estilo cuando los button s estén sobre ellos".

Como esta parte de Media Queries Level 4 hasta ahora solo se ha implementado en Chrome, he escrito un polyfill para tratar con esto. Utilizándolo, puedes transformar el CSS futurista anterior en:

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

(Una variación de la técnica .no-touch ) Y luego, usando algún JavaScript del lado del cliente del mismo polyfill que detecta la compatibilidad con el my-true-hover estacionario, puede alternar la presencia de la clase my-true-hover consecuencia:

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


$("#elementwithhover").click(function() { // code that makes element or parent slide or otherwise move out from under mouse. $(this).clone(true).insertAfter($(this)); $(this).remove(); });