ipad mobile-safari iphone pseudo-class

¿Es posible forzar a ignorar el: seudoclases hover para usuarios de iPhone/iPad?



mobile-safari pseudo-class (13)

Agregar la biblioteca de FastClick a su página hará que todas las pulsaciones en un dispositivo móvil se conviertan en eventos de clic (independientemente de dónde haga clic el usuario), por lo que también debería solucionar el problema de desplazamiento en dispositivos móviles. Edité tu violín como ejemplo: http://jsfiddle.net/FvACN/8/ .

Simplemente incluya la lib de fastclick.min.js en su página y actívela a través de:

FastClick.attach(document.body);

Como beneficio adicional, también eliminará la molesta demo de 300ms onClick que sufren los dispositivos móviles.


Hay un par de consecuencias menores al usar FastClick que pueden o no ser importantes para su sitio:

  1. Si toca en algún lugar de la página, desplácese hacia arriba, desplácese hacia abajo y luego suelta el dedo en la misma posición exacta en la que lo colocó inicialmente, FastClick lo interpretará como un "clic", aunque obviamente no lo es. Al menos así es como funciona en la versión de FastClick que estoy usando actualmente (1.0.0). Alguien puede haber solucionado el problema desde esa versión.
  2. FastClick elimina la posibilidad de que alguien haga "doble clic".

Tengo algunos menús css en mi sitio que se expanden con :hover (sin js)

Esto funciona de manera semi-rota en iDevices, por ejemplo, un toque activará la regla :hover y expandirá el menú, pero al tocar en otro lugar no se eliminará el :hover . Además, si hay un enlace dentro del elemento que está :hover , tiene que tocar dos veces para activar el enlace (primero toque los activadores :hover , pulse el segundo enlace de activadores).

He podido hacer que las cosas funcionen bien en el iPhone vinculando el evento de touchstart .

El problema es que a veces el safari móvil aún elige activar la regla :hover desde el CSS en lugar de mis eventos de touchstart .

Sé que este es el problema porque cuando desactivo todas las reglas :hover manualmente en el CSS, Safari móvil funciona bien (pero los navegadores comunes obviamente ya no).

¿Hay alguna manera de "cancelar" dinámicamente las reglas de :hover de ciertos elementos cuando el usuario está en safari móvil?

Vea y compare el comportamiento de iOS aquí: http://jsfiddle.net/74s35/3/ Nota: que solo algunas propiedades de css activan el comportamiento de dos clics, por ej. Display: none; pero no fondo: rojo; o texto-decoración: subrayado;


Algunos dispositivos (como han dicho otros) tienen eventos táctiles y de mouse. La superficie de Microsoft, por ejemplo, tiene una pantalla táctil, un panel táctil Y un lápiz óptico que en realidad plantea eventos al pasar el mouse sobre la pantalla.

Cualquier solución que deshabilite :hover función de la presencia de eventos "táctiles" también afectará a los usuarios de Surface (y a muchos otros dispositivos similares). Muchas computadoras portátiles nuevas son táctiles y responderán a eventos táctiles, por lo que deshabilitar el vuelo estacionario es una práctica realmente mala.

Este es un error en Safari, no hay absolutamente ninguna justificación para este comportamiento terrible. Me niego a sabotear navegadores que no sean iOS debido a un error en iOS Safari que aparentemente ha estado ahí durante años. Realmente espero que arreglen esto para iOS8 la próxima semana, pero mientras tanto ...

Mi solución :

Algunos han sugerido usar Modernizr ya, así Modernizr le permite crear sus propias pruebas. Lo que básicamente estoy haciendo aquí es ''abstraer'' la idea de un navegador que admite :hover sobre una prueba de Modernizr que puedo usar en todo mi código sin hardcoding if (iOS) todo momento.

Modernizr.addTest(''workinghover'', function () { // Safari doesn''t ''announce'' to the world that it behaves badly with :hover // so we have to check the userAgent return navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? false : true; });

Entonces el CSS se convierte en algo como esto

html.workinghover .rollover:hover { // rollover css }

Solo en iOS fallará esta prueba e inhabilitará la renovación.

La mejor parte de tal abstracción es que si encuentro que se rompe en un determinado Android o si está arreglado en iOS9, entonces puedo modificar la prueba.


Básicamente hay tres escenarios:

  1. El usuario solo tiene un mouse / puntero y puede activar :hover
  2. El usuario solo tiene una pantalla táctil y no puede activar :hover elementos de :hover
  3. El usuario tiene una pantalla táctil y un dispositivo puntero

La respuesta originalmente aceptada funciona muy bien si solo son posibles los dos primeros escenarios, donde un usuario tiene puntero o pantalla táctil. Esto era común cuando OP hizo la pregunta hace 4 años. Varios usuarios han señalado que los dispositivos con Windows 8 y Surface están haciendo que el tercer escenario sea más probable.

La solución de iOS para el problema de no poder pasar el ratón por los dispositivos con pantalla táctil (como detalla @Zenexer) es ingeniosa, pero puede hacer que el código directo se comporte mal (como lo señala el OP). Deshabilitar el vuelo estacionario solo para dispositivos con pantalla táctil significa que aún necesitará codificar una alternativa amigable con la pantalla táctil. Detectar cuándo un usuario tiene tanto el puntero como la pantalla táctil enturbia las aguas (como explica @Simon_Weaver).

En este punto, la solución más segura es evitar el uso :hover el :hover sobre la única forma en que un usuario puede interactuar con su sitio web. Los efectos de desplazamiento son una buena forma de indicar que un enlace o botón es accionable, pero no se debe exigir a un usuario que desplace el cursor sobre un elemento para realizar una acción en su sitio web.

Repensar la funcionalidad de "vuelo estacionario" con pantallas táctiles en mente tiene una buena discusión sobre los enfoques UX alternativos. Las soluciones proporcionadas por la respuesta allí incluyen:

  • Reemplazar menús desplegables con acciones directas (enlaces siempre visibles)
  • Reemplazar menús on-hover con menús directos
  • Mover grandes cantidades de contenido en vuelo en una página separada

En el futuro, esta será probablemente la mejor solución para todos los proyectos nuevos. La respuesta aceptada es probablemente la segunda mejor solución, pero asegúrese de tener en cuenta los dispositivos que también tienen dispositivos de puntero. Tenga cuidado de no eliminar la funcionalidad cuando un dispositivo tiene una pantalla táctil solo para trabajar con iOS :hover hack.


Dada la respuesta proporcionada por Zenexer, un patrón que no requiere etiquetas HTML adicionales es:

jQuery(''a'').on(''mouseover'', function(event) { event.preventDefault(); // Show and hide your drop down nav or other elem }); jQuery(''a'').on(''click'', function(event) { if (jQuery(event.target).children(''.dropdown'').is('':visible'') { // Hide your dropdown nav here to unstick } });

Este método dispara el mouseover primero, el clic segundo.


Descubrí que ": hover" es impredecible en iPhone / iPad Safari. A veces, toca el elemento que hace que ese elemento ": hover", mientras que a veces se desplaza a otros elementos.

Por el momento, solo tengo una clase de "no tocar" en el cuerpo.

<body class="yui3-skin-sam no-touch"> ... </body>

Y tenga todas las reglas de CSS con ": hover" debajo de ".no-touch":

.no-touch my:hover{ color: red; }

En algún lugar de la página, tengo javascript para eliminar la clase sin contacto del cuerpo.

if (''ontouchstart'' in document) { Y.one(''body'').removeClass(''no-touch''); }

Esto no se ve perfecto, pero funciona de todos modos.


En lugar de solo tener efectos de desplazamiento cuando el toque no está disponible, creé un sistema para manejar los eventos táctiles y eso me solucionó el problema. Primero, definí un objeto para probar eventos "tap" (equivalentes a "hacer clic").

touchTester = { touchStarted: false ,moveLimit: 5 ,moveCount: null ,isSupported: ''ontouchend'' in document ,isTap: function(event) { if (!this.isSupported) { return true; } switch (event.originalEvent.type) { case ''touchstart'': this.touchStarted = true; this.moveCount = 0; return false; case ''touchmove'': this.moveCount++; this.touchStarted = (this.moveCount <= this.moveLimit); return false; case ''touchend'': var isTap = this.touchStarted; this.touchStarted = false; return isTap; default: return true; } } };

Luego, en mi controlador de eventos, hago algo como lo siguiente:

$(''#nav'').on(''click touchstart touchmove touchend'', ''ul > li > a'' ,function handleClick(event) { if (!touchTester.isTap(event)) { return true; } // touch was click or touch equivalent // nromal handling goes here. });


Gracias a @Morgan Cheng por la respuesta, sin embargo, modifiqué ligeramente la función JS para obtener el " touchstart " (código tomado de la answer de @Timothy Perez). Sin embargo, necesita jQuery 1.7+ para esto.

$(document).on({ ''touchstart'' : function(){ //do whatever you want here } });


La biblioteca de detección de características del navegador Modernizer incluye una verificación de eventos táctiles.

Su comportamiento predeterminado es aplicar clases a su elemento html para cada característica que se detecta. A continuación, puede utilizar estas clases para diseñar su documento.

Si los eventos táctiles no están habilitados, Modernizr puede agregar una clase de no-touch :

<html class="no-touch">

Y luego amplíe sus estilos de vuelo esta clase:

.no-touch a:hover { /* hover styles here */ }

Puede descargar una compilación Modernizr personalizada para incluir la cantidad de detecciones de funciones que necesite.

Aquí hay un ejemplo de algunas clases que se pueden aplicar:

<html class="js no-touch postmessage history multiplebgs boxshadow opacity cssanimations csscolumns cssgradients csstransforms csstransitions fontface localstorage sessionstorage svg inlinesvg no-blobbuilder blob bloburls download formdata">


La versión de JQuery en su uso de .css .no-touch .my-element: hover para todas sus reglas de desplazamiento incluyen JQuery y la siguiente secuencia de comandos

function removeHoverState(){ $("body").removeClass("no-touch"); }

Luego, en la etiqueta del cuerpo, agregue class = "no-touch" ontouchstart = "removeHoverState ()"

tan pronto como el OnTouchstart dispara la clase para todos los estados de vuelo estacionario se elimina


Solo mira el tamaño de la pantalla ...

@media (min-width: 550px) { .menu ul li:hover > ul { display: block; } }



aquí está el código en el que querrá colocarlo

// a function to parse the user agent string; useful for // detecting lots of browsers, not just the iPad. function checkUserAgent(vs) { var pattern = new RegExp(vs, ''i''); return !!pattern.test(navigator.userAgent); } if ( checkUserAgent(''iPad'') ) { // iPad specific stuff here }


:hover no es el problema aquí. Safari para iOS sigue una regla muy extraña. Dispara mouseover y mousemove primero; si se cambia algo durante estos eventos, ''clic'' y los eventos relacionados no se disparan:

mouseenter y mouseleave parecen estar incluidos, aunque no están especificados en el gráfico.

Si modificas algo como resultado de estos eventos, los eventos de clic no se activarán. Eso incluye algo más arriba en el árbol DOM. Por ejemplo, esto evitará que los clics individuales funcionen en su sitio web con jQuery:

$(window).on(''mousemove'', function() { $(''body'').attr(''rel'', Math.random()); });

Editar: para aclarar, el evento de mouseenter jQuery incluye mouseenter y mouseleave . Ambos evitarán el click si se cambia el contenido.