¿Es posible forzar ignorar la pseudoclase: hover para usuarios de iPhone/iPad?


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

Esto funciona de una manera semi-rota en iDevices, por ejemplo, un toque activará la regla :hover y expandirá el menú, pero luego tocar en otro lugar no elimina el :hover. Además, si hay un enlace dentro del elemento que es :hover'ed, debe tocar dos veces para activar el enlace (primero toque activa :hover, segundo toque activa enlace).

He sido capaz de hacer que las cosas funcionen bien en el iphone mediante la unión de la touchstart evento.

El problema es que a veces mobile safari todavía elige activar la regla :hover desde el css en lugar de mis eventos touchstart!

Sé que este es el problema porque cuando deshabilito todas las reglas :hover manualmente en el css, mobile safari funciona muy bien (pero los navegadores regulares obviamente ya no lo hacen).

¿Hay alguna forma de "cancelar" dinámicamente :hover reglas para ciertos elementos cuando el usuario está en mobile safari?

Ver y comparar iOS comportamiento aquí: http://jsfiddle.net/74s35/3 / Nota: solo algunas propiedades css activan el comportamiento de dos clics, por ejemplo, display:none; pero no background: red; o text-decoration: underline;

Author: Christopher Camps, 2010-04-30

13 answers

Encontré que ":hover" es impredecible en iPhone/iPad Safari. A veces toque en elemento hacer que el elemento": hover", mientras que a veces se desplaza a otros elementos.

Por el momento, solo tengo una clase "no-touch" en body.

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

Y tener todas las reglas 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 no-touch del cuerpo.

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

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

 74
Author: Morgan Cheng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-19 10:22:22

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

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

Si modifica algo como resultado de estos eventos, haga clic en eventos no se activarán. Eso incluye algo más alto en el árbol DOM. Por ejemplo, esto evitará clics individuales de trabajar en su sitio web con jQuery:

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

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

 38
Author: Zenexer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-29 12:34:32

La biblioteca de detección de características del navegadorModernizador incluye una comprobació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 dar estilo a 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 alcance sus estilos de hover con esta clase:

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

Puede descargar una compilación personalizada de Modernizr para incluya tan pocas o tantas detecciones de características como 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">
 18
Author: Beau Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-29 23:54:35

Algunos dispositivos (como otros han dicho) tienen eventos táctiles y de ratón. Microsoft Surface, por ejemplo, tiene una pantalla táctil, un trackpad Y un stylus que en realidad plantea eventos de hover cuando se cierne sobre la pantalla.

Cualquier solución que desactive :hover basado en la presencia de eventos 'touch' también afectará a los usuarios de Surface (y muchos otros dispositivos similares). Muchas computadoras portátiles nuevas son táctiles y responderán a los eventos táctiles , por lo que deshabilitar el flotador es una muy mala practicar.

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

Mi solución:

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

 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 esta prueba fallará y deshabilitará el rollover.

La mejor parte de tal abstracción es que si encuentro que se rompe en un determinado android o si se fija en iOS9, entonces solo puedo modificar la prueba.

 17
Author: Simon_Weaver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-01 22:23:55

Agregar la biblioteca FastClick a su página hará que todos los toques 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 hover en dispositivos móviles. Edité tu violín como ejemplo: http://jsfiddle.net/FvACN/8/.

Solo incluye el fastclick.min.js lib en su página, y activar a través de:

FastClick.attach(document.body);

Como beneficio secundario, también eliminará el molesto retraso de 300 ms onClick que los dispositivos móviles sufrir de.


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

  1. Si toca en algún lugar de la página, desplácese hacia arriba, desplácese hacia abajo y luego suelte el dedo en la misma posición exacta en la que lo colocó inicialmente, FastClick interpretará eso 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 pudo haber arreglado el problema desde esa versión.
  2. FastClick elimina la posibilidad de que alguien haga "doble clic".
 15
Author: Troy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-18 18:43:01

Una mejor solución, sin ninguna clase JS, css y verificación de viewport: puede usar las características de Medios de interacción (Nivel de Consultas de medios 4)

Así:

@media (hover) {
  // properties
  my:hover {
    color: red;
  }
}

IOS Safari lo soporta

Más sobre: https://www.jonathanfielding.com/an-introduction-to-interaction-media-features /

 9
Author: Estevão Lucas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-14 00:06:53

Básicamente, Hay tres escenarios:

  1. El usuario solo tiene un dispositivo de ratón / puntero y puede activar :hover
  2. El usuario solo tiene una pantalla táctil, y no puede activar :hover elementos
  3. El usuario tiene tanto una pantalla táctil como un dispositivo puntero

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

La solución de iOS para el problema de no ser capaz de flotar en dispositivos de pantalla táctil (como se detalla por @Zenexer) es inteligente, pero puede causar código directo a portarse mal (como se señala por el OP). Deshabilitar el hover solo para dispositivos con pantalla táctil significa que aún tendrá que codificar una alternativa amigable con la pantalla táctil. Detectar cuando un usuario tiene tanto puntero y la pantalla táctil enturbia aún más las aguas (como explica @Simon_Weaver).

En este punto, la solución más segura es evitar usar :hover como la única forma en que un usuario puede interactuar con su sitio web. Los efectos de hover son una buena manera de indicar que un enlace o botón es procesable, pero no se debe requerir que un usuario pase un elemento para realizar una acción en su sitio web.

Repensar la funcionalidad "hover" con pantallas táctiles en mente tiene una buena discusión sobre la UX alternativa enfoque. Las soluciones proporcionadas por la respuesta allí incluyen:

  • Reemplazar los menús flotantes con acciones directas (enlaces siempre visibles)
  • Sustitución de menús al pasar por menús al toque
  • Mover grandes cantidades de contenido al pasar a una página separada

En el futuro, esta será probablemente la mejor solución para todos los nuevos proyectos. 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. Ser tenga cuidado de no eliminar la funcionalidad cuando un dispositivo tiene una pantalla táctil solo para evitar el hack de iOS :hover.

 4
Author: thirdender,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-13 12:32:14

La versión de jQuery en tu .uso de css .no-touch. my-element: hover para todas tus reglas de hover incluir jQuery y el siguiente script

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

Luego en la etiqueta body añadir class= "no-touch" ontouchstart = "removeHoverState ()"

Tan pronto como el ontouchstart dispara la clase para todos los estados hover se elimina

 1
Author: Greg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-08 18:57:53

En lugar de tener solo efectos de hover cuando touch no está disponible, creé un sistema para manejar eventos táctiles y eso me ha resuelto el problema. Primero, definí un objeto para probar los eventos" tap "(equivalente a" click").

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

Entonces, 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.
            });
 1
Author: donut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-21 01:50:14

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

  $(document).on({ 'touchstart' : function(){
      //do whatever you want here
    } });
 0
Author: 3Gee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:36

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.

 0
Author: veryphatic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-02 14:05:46

Basta con mirar el tamaño de la pantalla....

@media (min-width: 550px) {
    .menu ul li:hover > ul {
    display: block;
}
}
 -6
Author: oeliewoep,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-19 08:49:00

Aquí está el código en el que querrás 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
}
 -12
Author: Luke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-09 08:38:07