[CSS3|JS] Menú dropdown

Iniciado por Gus Garsaky, Junio 25, 2015, 04:36:31 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

En éste post, vamos a crear un menú dropdown, lo que en HTML se llama select, y aplicarle los estilos que deseemos, lo que no podemos hacer con select (puedes customizarlo, pero de forma bastante limitada).


Marcado HTML

Código: html5

<section class="dropdown" tabindex="1">
<span>Choose one skill</span>
<ul>
<li><a href="#">Fullstack developer</a></li>
<li><a href="#">Frontend developer</a></li>
<li><a href="#">Backend developer</a></li>
</ul>
</section>


CSS

El dropdown será un section, y las opciones una lista. El primer hijo, el elemento span, será el texto que se le muestre al usuario antes de que éste escoja un valor. Ahora, veamos que estilos le damos.

Código: css

.dropdown {
    background-color: #fff;
    align-items: center;
    border: 1px solid #c5c5c5;
    border-radius: 3px;
    box-shadow: 0 2px 4px rgba(0,0,0,.15);
    display: flex;
    height: 35px;
    margin: 0;
    outline: none;
    position: relative;
}


El fondo será blanco, tendrá un borde color gris y un redondeado de 3 px. También tiene un alto de 35 px y una sobra ligera inclinada un poco hacia abajo. Tiene una posición relative que nos permitirá ubicar la lista de opciones de acuerdo a él; tiene además un display: inline-flex que hace que los elementos se muestren en forma horizontal y un align-items, que hará que los hijos se centren de acuerdo a su eje vertical.

Por el momento tenemos un rectángulo nada más, no hay indicios que ésto sea un dropdown, así que será necesario ponerle una flecha para que el usuario lo identifique. Para esto usaremos la pseudo clase :after.

Código: css

.dropdown:after {
    align-items: center;
    border-left: 1px solid #d8d8d8;
    color: #555;
    content: "▼";
    display: flex;
    font-family: 'segoe ui';
    font-size: .8rem;
    height: 100%;
    justify-content: center;
    width: 30px;
}


Crearemos un elemento en :after, de tipo flex con un alto de 100% y un ancho de 35px, además un borde izquierdo gris. Como contenido, tendrá una flecha mirando hacia abajo. Ahora, para centrar esa flecha, tendremos que usar align-items y justify-content con el valor center, logrando así un centrado perfecto.

Citar
El mismo centrado lo podemos lograr con las propiedades: line-height, que debe tener el mismo valor que el height y con text-align para centrar el texto en el eje horizontal.

Para el texto por defecto, será muy simple la cosa:

Código: css

.dropdown > span {
color: #777;
       display: block;
font-family: 'segoe ui';
margin: 0;
       padding: 0 .7rem;
}


Un color gris oscuro y un padding horizontal de .7rem.

LA LISTA

La lista es también sencilla. Veamos:

Código: css

.dropdown > ul {
        background-color: #fff;
border: 1px solid #c5c5c5;
border-radius: 3px;
box-shadow: 0 2px 4px rgba(0,0,0,.15);
        display: block;
left: 0;
list-style: none;
margin: 0;
        opacity: 0;
        padding: .45rem 0;
position: absolute;
top: 140%;
        transition: all .2s linear;
        visibility: hidden;
        z-index: 1;
}


Solo algunas pequeñas cosas que rescatar. Tiene un position absolute y un top de 140%, lo que hace que la lista se ubique un poco hacia bajo. También tiene una sombra y una opacidad 0 y visibility hidden, lo que hace que no esté visible la lista. Por último, tiene un z-index de 1, lo que hace que la lista esté sobre el resto de elementos en caso 'detrás' de la lista haya algún otro elemento.

Por cuestiones de estética, le creamos una flecha que indique que el pertenece al dropdown:

Código: css

.dropdown > ul:after {
    background-color: #fff;
    border: 1px solid #c5c5c5;
    border-right-width: 0;
    border-bottom-width: 0;
    content: "";
    display: block;
    height: 10px;
    position: absolute;
    top: -6px;
    right: 10px;
    transform: rotate(45deg) skew(5deg, 5deg);
    width: 10px;
}


Lo hacemos gracias a transform. Simplemente lo rotamos 45 grados y nos da la forma de un rombo, le borramos el borde derecho e inferior y ya tenemos nuestro triángulo. ¿fácil no?

Ahora simplemente vamos a estilizar los list items y los elementos a:

Código: css

.dropdown > ul > li, .dropdown > ul > li > a {
    display: block;
}
.dropdown > ul > li:not(:last-of-type) {
    border-bottom: 1px dashed #ddd;
}
.dropdown > ul > li:hover {
    background-color: #f5f5f5;
}
.dropdown > ul > li > a {
color: #777;
font-family: 'segoe ui';
padding: .5rem .8rem;
        text-align: center;
text-decoration: none;
}


La instrucción .dropdown > ul > li:not(:last-of-type) se traduce a: afecta a todos los elementos li hijos de ul menos el último hijo. Es decir, el borde inferior se lo daremos al primero y al rango entre él y el último (excluido).

Por último, haremos la lista visible cuando se haga click en el menú (y se añadirá la clase active mediante JavaScript):

Código: css

.dropdown.active > ul {
    opacity: 1;
    visibility: visible;
}


JAVASCRIPT

Ya tenemos la parte visual, ahora nos queda darle funcionalidad. Veamos el código JavaScript:

Código: javascript

'use strict';
class Dropdown {
constructor(el) {
this.dropdown = el;
this.display = el.querySelector('span');
this.list = el.querySelector('ul');
this.opts = this.list.querySelectorAll('li');
this.index = -1;
this.value = '';
this.initEvents();
}
initEvents() {
let self = this;
this.dropdown.addEventListener('click', function() {
self.dropdown.classList.toggle('active');
});
[].forEach.call(self.opts, function(cur) {
cur.addEventListener('click', function(e) {
e.preventDefault();
self.value = cur.textContent;
self.display.innerText = self.value;
self.index = Array.prototype.indexOf.call(self.list, cur);
});
});
},
       getValue() {
           return this.value;
       }
       getIndex() {
          return this.index;
       }
}


Primero le pasamos por el constructor nuestro dropdown. En el constructor, guarda el span, la lista y las opciones (li) como variables. También crea dos variables: value e index, las cuales contendrán el texto del valor escogido y el índice del mismo respectivamente. Cuando se escoja una opción, se guarda el texto de la opción escogida y el índice del mismo y se actualiza el texto del span con el texto de la opción que se ha escogido.

Tan solo basta con:

Código: javascript

document.addEventListener('DOMContentLoaded', function() {
let dropdown = new Dropdown(document.querySelector('.dropdown'));
});


Y ya tendremos nuestro dropdown funcional. Si quieremos saber en algún momento en valor o el índice actual, basa con:

Código: javascript
var value = dropdown.getValue();
var index = dropdown.getIndex();



No tienes permitido ver los links. Registrarse o Entrar a mi cuenta


Saludos.