Hover Intent moderno en menues dropdown

7/may/2015 0

La utilidad (y poca accesibilidad) de los menúes dropdown son conocidos e incuestionables. Pero existe un pequeño problema cuando el usuario navega sobre ellos, el cual se puede apreciar a continuación:

Ejemplo 1 Hover Intent moderno en menues dropdown | CSSLab.cl

El Problema

Vemos que cuando se pasa el mouse sobre los elementos que gatillan los paneles se sobreponen a lo que está debajo de ellos si el movimiento es lo suficientemente rápido. No es un comportamiento crítico pero la solución es tan simple que mejor es tenerla siempre presente.

Como sabemos la construcción de un menú dropdown (un elemento que contiene sub-elementos que son desplegados sólo cuando el usuario pasa el mouse sobre el elemento padre) no es más que un cambio en el pseudo-estado :hover. Si está sobre el elemento muestra los sub-elementos, si no, vuelve a esconderlos.

El HTML base:

<ul class="nav">
  <li>
    <a href="#">Element</a>
    <ul>
      <li><a href="#">Sub-Element</a></li>
      <li><a href="#">Sub-Element</a></li>
    </ul>
  </li>
  <li>
    <a href="#">Element</a>
    <ul>
      <li><a href="#">Sub-Element</a></li>
      <li><a href="#">Sub-Element</a></li>
    </ul>
  </li>
  ...
</ul>

Y el CSS base:

.nav {
  position: relative;
}
	.nav ul {
	  position: absolute;
	}
	.nav li {
	  list-style: none;
	}
	.nav a {
	  display: block;
	  width: 90px;
	}
	.nav > li {
	  float: left;
	}
		.nav > li > a + ul {
		  visibility: hidden;
		}
			.nav > li:hover > a + ul {
			  visibility: visible;
			}

JS Bin

La Solución

Ejemplo 2 Hover Intent moderno en menues dropdown | CSSLab.cl

Lo que se propone es atrasar el comportamiento del :hover a los sub-elementos, con unos pocos milisegundos (ms) de delay (en mis ejemplos, 0.3ms). Con esto haremos que el usuario cuando esté pasando sobre los elementos no los despliegue al instante sino que espere esos milisegundos antes de gatillarlos, denotando la verdadera intención del usuario: mostrar los sub-elementos o sólo pasar sobre el elemento. Este comportamiento se denomina hover intent y se puede realizar de 2 maneras: mediante la propiedad CSS3 transition-delay y con fallback con JS para los browsers que no soportan esta propiedad (IE9 e inferiores):

Utilzando CSS3:

/* 
  la declaración resumida es: 
  transition: propiedad duración tipo delay;
*/
.nav > li > a + ul {
  visibility: hidden;
  /* al salir el mouse del menu desplegado no debe haber delay
     por eso está en 0s */
  transition: visibility 0s linear 0s;
}
  .nav > li:hover > a + ul {
    visibility: visible;
    /* al entrar el mouse al elemento hay un delay de 300ms
       para desplegar el menu */
    transition: visibility 0s linear 0.3s;
  }

JS Bin

Utilzando JS/jQuery:

(function () { 
  var menuDropdown = $('.nav'),
      delay = 300; // retardo dropdown (ms)

  // esconde los submenues por defecto
  $('a + ul', menuDropdown).hide();

  $("li", menuDropdown).hover(function() { // mousein
    var elem = $(this);

  // indicador que el mouse ha entrado al elemento padre
  elem.attr('mIn', 'true');

  setTimeout(function () {
    // mostramos submenu
    if (elem.attr('mIn') == 'true') {
      $('a + ul', elem).show();
    }
    }, delay);
    
  }, function() { // mouseout

    // indicador que el mouse ha salido del submenu desplegado
    $(this).attr('mIn', 'false');
    // escondemos submenu
    $('a + ul', $(this)).hide();
    
  });
}());

JS Bin

Deja tu Comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

CSSLab