Estoy escribiendo un sitio web destinado a ser utilizado tanto desde computadoras de escritorio como desde tabletas. Cuando se visita desde un escritorio, quiero que las áreas de la pantalla en las que se puede hacer clic se iluminen con :hover
efectos (color de fondo diferente, etc.) Con una tableta, no hay mouse, por lo que no quiero ningún efecto de desplazamiento.
El problema es que, cuando toco algo en la tableta, el navegador evidentemente tiene algún tipo de "cursor de mouse invisible" que se mueve a la ubicación que toqué y luego lo deja allí, por lo que lo que acabo de tocar se ilumina con un efecto de desplazamiento hasta que toque otra cosa.
¿Cómo puedo obtener los efectos de desplazamiento cuando estoy usando el mouse, pero suprimirlos cuando estoy usando la pantalla táctil?
En caso de que alguien estuviera pensando en sugerirlo, no quiero usar el rastreo de agentes de usuario. El mismo dispositivo podría tener una pantalla táctil y un mouse (tal vez no sea tan común hoy, pero mucho más en el futuro). No me interesa el dispositivo, me interesa cómo se utiliza actualmente: ratón o pantalla táctil.
Ya he intentado enganchar los touchstart
, touchmove
, y touchend
eventos y llamando preventDefault()
en todos ellos, lo que hace suprimir el "cursor del ratón invisible" una parte del tiempo; pero si toco rápidamente hacia adelante y hacia atrás entre dos elementos diferentes, después de algunos toques comenzará a mover el "cursor del mouse" e iluminará los efectos de desplazamiento de todos modos; es como si mi preventDefault
no siempre fuera un honor. No los aburriré con los detalles a menos que sea necesario; ni siquiera estoy seguro de que ese sea el enfoque correcto a seguir; si alguien tiene una solución más simple, soy todo oídos.
Editar: esto se puede reproducir con CSS estándar del pantano :hover
, pero aquí hay una reproducción rápida como referencia.
<style>
.box { border: 1px solid black; width: 150px; height: 150px; }
.box:hover { background: blue; }
</style>
<div class="box"></div>
<div class="box"></div>
Si pasa el mouse sobre cualquiera de los cuadros, obtendrá un fondo azul, que quiero. Pero si toca cualquiera de las casillas, también obtendrá un fondo azul, que es lo que estoy tratando de evitar.
También publiqué una muestra aquí que hace lo anterior y también engancha los eventos del mouse de jQuery. Se puede utilizar para ver que los eventos Tap también se disparará mouseenter
, mousemove
y mouseleave
.
fuente
Respuestas:
De tu pregunta deduzco que tu efecto de desplazamiento cambia el contenido de tu página. En ese caso, mi consejo es:
touchstart
ymouseenter
.mouseleave
,touchmove
yclick
.Alternativamente, puede editar su página para que no haya cambios de contenido.
Antecedentes
Para simular un mouse, los navegadores como Webkit mobile activan los siguientes eventos si un usuario toca y suelta un dedo en la pantalla táctil (como iPad) (fuente: Touch And Mouse en html5rocks.com):
touchstart
touchmove
touchend
mouseover
mouseenter
mouseover
,mouseenter
omousemove
cambia el contenido de la página, los siguientes eventos nunca se activan.mousemove
mousedown
mouseup
click
No parece posible simplemente decirle al navegador web que omita los eventos del mouse.
Lo que es peor, si un evento de mouseover cambia el contenido de la página, el evento de clic nunca se activa, como se explica en la Guía de contenido web de Safari - Manejo de eventos , en particular la figura 6.4 en Eventos de un dedo . Qué es exactamente un "cambio de contenido", dependerá del navegador y la versión. Descubrí que para iOS 7.0, un cambio en el color de fondo no es (¿o ya no?) Un cambio de contenido.
Solución explicada
Recordar:
touchstart
ymouseenter
.mouseleave
,touchmove
yclick
.¡Tenga en cuenta que no hay ninguna acción en
touchend
!Esto claramente funciona para eventos de mouse:
mouseenter
ymouseleave
(versiones ligeramente mejoradas demouseover
ymouseout
) se activan, y agregan y eliminan el desplazamiento.Si el usuario realmente
click
es un enlace, el efecto de desplazamiento también se elimina. Esto asegura que se elimine si el usuario presiona el botón Atrás en el navegador web.Esto también funciona para eventos táctiles: al inicio táctil, se agrega el efecto de desplazamiento. Se '' 'no' '' se quita al tocarlo. Se vuelve a agregar
mouseenter
y, dado que esto no provoca cambios de contenido (ya se agregó), elclick
evento también se dispara y el enlace se sigue sin necesidad de que el usuario vuelva a hacer clic.El retraso de 300 ms que tiene un navegador entre un
touchstart
evento y el queclick
se le da un buen uso porque el efecto de desplazamiento se mostrará durante este corto tiempo.Si el usuario decide cancelar el clic, un movimiento del dedo lo hará con normalidad. Normalmente, esto es un problema ya que no
mouseleave
se dispara ningún evento y el efecto de desplazamiento permanece en su lugar. Afortunadamente, esto se puede solucionar fácilmente eliminando el efecto de desplazamiento entouchmove
.¡Eso es!
Tenga en cuenta que es posible eliminar el retraso de 300 ms , por ejemplo, utilizando la biblioteca FastClick , pero esto está fuera del alcance de esta pregunta.
Soluciones alternativas
Encontré los siguientes problemas con las siguientes alternativas:
touchend
: Esto seguirá incorrectamente el enlace, incluso si el usuario solo quería desplazarse o hacer zoom, sin la intención de hacer clic en el enlace.touchend
que se usa como una condición if en eventos posteriores del mouse para evitar cambios de estado en ese momento. La variable se restablece en el evento de clic. Vea la respuesta de Walter Roman en esta página. Esta es una solución decente si realmente no desea un efecto de desplazamiento en las interfaces táctiles. Desafortunadamente, esto no funciona sitouchend
se dispara a por otro motivo y no se dispara ningún evento de clic (por ejemplo, el usuario se desplazó o hizo zoom), y posteriormente está tratando de seguir el enlace con un mouse (es decir, en un dispositivo con interfaz de mouse y táctil ).Otras lecturas
mouseover
omousemove
.fuente
touchend
lugar detouchstart
en la mayoría de los casos para evitar activar acciones inmediatamente cuando el usuario intenta deslizar el dedo hacia arriba o hacia abajo en una página. Se siguen sucediendo, pero es menos probable que distraer o confundir (asumiendo que es algo inofensivo como mostrar una etiqueta, no es algo que el usuario tiene que saber que pasó)Tal vez no piense en ello tanto como suprimir los efectos de desplazamiento para las pantallas táctiles, sino como añadir efectos de desplazamiento para los eventos del ratón.
Si desea mantener los
:hover
efectos en su CSS, puede especificar diferentes estilos para diferentes medios:Excepto que, desafortunadamente, hay muchos dispositivos móviles que ignoran esto y solo usan las reglas de la pantalla. Afortunadamente, muchos de los navegadores más nuevos para dispositivos móviles / tabletas admiten algunas consultas de medios más sofisticadas:
Entonces, incluso si se ignora la parte de "pantalla" o "computadora de mano", el "ancho máximo" funcionará por usted. Simplemente podría suponer que cualquier cosa con una pantalla de menos de 800 píxeles debe ser una tableta o teléfono, y no usar efectos de desplazamiento. Para los pocos usuarios que usan un mouse en un dispositivo de baja resolución, no verían los efectos de desplazamiento, pero su sitio estaría bien de lo contrario.
¿Más información sobre consultas de medios? Hay muchos artículos sobre esto en línea; aquí hay uno: http://www.alistapart.com/articles/return-of-the-mobile-stylesheet
Si desplaza los efectos de desplazamiento fuera de su CSS y los aplica con JavaScript, entonces podría vincularse específicamente a los eventos del mouse, y / o nuevamente podría hacer algunas suposiciones solo en función del tamaño de la pantalla, siendo el "problema" del peor de los casos que algunos el usuario que usa un mouse pierde los efectos de desplazamiento.
fuente
preventDefault()
, eso a veces suprime los eventos del mouse, pero como dije en mi pregunta, no es confiable.Escribí el siguiente JS para un proyecto reciente, que era un sitio de escritorio / móvil / tableta que tiene efectos de desplazamiento que no deberían aparecer al tacto.
El
mobileNoHoverState
módulo de abajo tiene una variablepreventMouseover
(declarado inicialmente comofalse
), que se establece paratrue
cuando un usuario dispara eltouchstart
evento en un elemento,$target
.preventMouseover
luego, se vuelve a configurarfalse
cada vez que se activa elmouseover
evento, lo que permite que el sitio funcione según lo previsto si un usuario utiliza tanto la pantalla táctil como el mouse.Sabemos que
mouseover
se activa despuéstouchstart
debido al orden en el que se declaraninit
.Luego, se crea una instancia del módulo más adelante en la línea:
fuente
Realmente quería una
css
solución pura para esto, ya que esparcir una solución javascript pesada alrededor de todas mis vistas parecía una opción desagradable. Finalmente encontré la consulta @ media.hover , que puede detectar "si el mecanismo de entrada principal permite al usuario desplazarse sobre los elementos". Esto evita dispositivos táctiles donde "flotar" es más una acción emulada que una capacidad directa del dispositivo de entrada.Entonces, por ejemplo, si tengo un enlace:
Entonces puedo diseñarlo con seguridad solo
:hover
cuando el dispositivo lo admita fácilmente con estocss
:Si bien la mayoría de los navegadores modernos admiten consultas de funciones de medios de interacción, algunos navegadores populares como IE y Firefox no lo hacen. En mi caso, esto funciona bien, ya que solo tenía la intención de admitir Chrome en el escritorio y Chrome y Safari en el móvil.
fuente
Mi solución es agregar la clase css activa de desplazamiento a la etiqueta HTML y usarla al comienzo de todos los selectores de CSS con: desplazar y eliminar esa clase en el primer evento touchstart.
http://codepen.io/Bnaya/pen/EoJlb
JS:
HTML:
CSS:
fuente
'ontouchstart' in window
. Ej .if ('ontouchstart' in window) document.querySelector('html').classList.remove('hover-active');
Lo que he hecho para resolver el mismo problema es tener una función de detección (uso algo como este código ), ver si onTouchMove está definido, y si es así agrego la clase css "touchMode" al cuerpo, de lo contrario agrego " desktopMode ".
Luego, cada vez que algún efecto de estilo solo se aplica a un dispositivo táctil, o solo a un escritorio, la regla css se antepone con la clase apropiada:
Editar : esta estrategia, por supuesto, agrega algunos caracteres adicionales a su css, por lo que si le preocupa el tamaño de css, puede buscar las definiciones touchMode y desktopMode y ponerlas en diferentes archivos, para que pueda servir css optimizado para cada dispositivo tipo; o puede cambiar los nombres de las clases a algo mucho más corto antes de ir a prod.
fuente
Bien, tuve un problema similar pero logré solucionarlo con consultas de medios y CSS simple. Estoy seguro de que estoy rompiendo algunas reglas aquí, pero me está funcionando.
Básicamente, tuve que tomar una aplicación masiva que alguien hizo y hacerla receptiva. Usaron jQueryUI y me pidieron que no manipulara ninguno de sus jQuery, por lo que estaba restringido a usar CSS solo.
Cuando presioné uno de sus botones en el modo de pantalla táctil, el efecto de desplazamiento se dispararía durante un segundo antes de que la acción del botón tuviera efecto. Así es como lo arreglé.
fuente
En mi proyecto, resolvimos este problema usando https://www.npmjs.com/package/postcss-hover-prefix y https://modernizr.com/ Primero, posprocesamos los archivos css de salida con
postcss-hover-prefix
. Agrega.no-touch
para todas lashover
reglas css .css
se convierte en
En tiempo de ejecución
Modernizr
agrega automáticamente clases css ahtml
etiquetas como estaDicho posprocesamiento de css más Modernizr deshabilita el desplazamiento para dispositivos táctiles y lo habilita para otros. De hecho, este enfoque se inspiró en Bootstrap 4, cómo resuelven el mismo problema: https://v4-alpha.getbootstrap.com/getting-started/browsers-devices/#sticky-hoverfocus-on-mobile
fuente
Puede activar el
mouseLeave
evento siempre que toque un elemento en la pantalla táctil. Aquí hay una solución para todas las<a>
etiquetas:fuente
Iv había encontrado 2 soluciones al problema, lo que implica que detecta el contacto con modernizr o algo más y establece una clase táctil en el elemento html.
Esto es bueno pero no se admite muy bien:
Pero esto tiene un muy buen soporte :
Funciona perfectamente para mí, hace que todos los efectos de desplazamiento sean como cuando tocas un botón, se iluminará pero no terminará con errores como el efecto de desplazamiento inicial para los eventos del mouse.
Detectando el toque de dispositivos no táctiles creo que modernizr ha hecho el mejor trabajo:https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.jsEDITAR
Encontré una solución mejor y más simple para este problema.
Cómo determinar si el cliente es un dispositivo táctil
fuente
Podría ser útil ver su CSS, ya que parece un problema bastante extraño. Pero de todos modos, si está sucediendo y todo lo demás está bien, puede intentar cambiar el efecto de desplazamiento a javascript (también puede usar jquery). Simplemente, conéctese al evento mouseover o mejor aún mouseenter e ilumine su elemento cuando se active el evento.
Vea el último ejemplo aquí: http://api.jquery.com/mouseover/ , ¡podría usar algo similar para registrar cuando se desencadena el evento y continuar desde allí!
fuente
mouseenter
; no dados. Al tocar, se mueve el "cursor del mouse invisible", por lo que se activamouseenter
ymousemove
(ymouseleave
cuando se toca en otro lugar).Si está contento de usar JavaScript, puede usar Modernizr en su página. Cuando se carga la página, un navegador de pantalla no táctil tendrá la clase '.no-touch' agregada a la etiqueta html, pero para un navegador de pantalla táctil, la etiqueta html tendrá la clase '.touch' agregada a la etiqueta html .
Entonces es simplemente un caso de verificar si la etiqueta html tiene la clase no-touch antes de decidir agregar sus oyentes mouseenter y mouseleave.
Para un dispositivo de pantalla táctil, los eventos no tendrán oyentes, por lo que no obtendrá ningún efecto de desplazamiento cuando toque.
fuente
.touch
y.no-touch
. Reescribir su respuesta en CSS junto con Modernizer,html.no-touch .box:hover {background-color: "#0000ff"}
y no definir nada parahtml.touch .box:hover
debería funcionar, ya que el OP solo está tratando de evitar los dispositivos móviles:hover
.En un proyecto que hice recientemente, resolví este problema con la función de eventos delegados de jQuery. Busca ciertos elementos usando un selector de jQuery y agrega / elimina una clase CSS a esos elementos cuando el mouse está sobre el elemento. Parece que funciona bien hasta donde he podido probarlo, que incluye IE10 en una computadora portátil con capacidad táctil que ejecuta Windows 8.
editar: esta solución, por supuesto, requiere que modifiques tu CSS para eliminar los selectores ": hover" y contemplar de antemano qué elementos quieres que sean "hoverables".
Sin embargo, si tiene muchos elementos en su página (como varios miles), es posible que se ralentice un poco, porque esta solución detecta eventos de tres tipos en todos los elementos de la página, y luego hace lo suyo si el selector coincide. Llamé a la clase CSS "mouseover" en lugar de "hover", porque no quería que ningún lector de CSS leyera ": hover" donde escribí ".hover".
fuente
Aquí está mi solución: http://jsfiddle.net/agamemnus/g56aw709/-- código a continuación.
Todo lo que hay que hacer es convertir su ": hover" en ".hover" ... ¡eso es todo! La gran diferencia entre esto y el resto es que esto también funcionará en selectores de elementos no singulares como
.my_class > *:hover {
.fuente
Incluya Modernizr en su página y configure sus estados de desplazamiento como este en su lugar:
fuente
Hola persona del futuro, probablemente quieras usar la consulta de medios
pointer
y / ohover
. Lahandheld
consulta de medios quedó obsoleta.fuente
Pruebe esta sencilla solución jquery 2019, aunque ha existido por un tiempo;
agregue este complemento al encabezado:
src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"
agregue esto a js:
$("*").on("touchend", function(e) { $(this).focus(); }); //applies to all elements
algunas variaciones sugeridas a esto son:
Notas
Referencias:
https://code.jquery.com/ui/
https://api.jquery.com/category/selectors/jquery-selector-extensions/
fuente