Crear una Estupenda Navegación Animada con CSS y jQuery
() translation by (you can also view the original English article)
La animación y las respuestas visuales son magníficas formas de asistir a un usuario en la navegación e interacción con un sitio web. Si bien, tradicionalmente Adobe Flash fue la función 'goto' para cualquier animación, estos días con la magia de javascript podemos librarnos de Flash. Hoy vamos a construir una animación de un menú de navegación, verdaderamente, estupenda; usando sólo CSS y jQuery.
Demo y Recursos de Códigos
Resumen
El menú que vamos a construir puede verse en la siguiente captura de pantalla. Además, usted puede ver el trabajo final haciendo clic aquí.



Voy a dividir este curso en cinco secciones que son las siguientes:
- Borrador de boceto
- Creando los Recursos
- Escribiendo el HTML
- Escribiendo el CSS
- Creando la animación usando jQuery
Paso 1: Borrador de Boceto
En primer lugar, veamos que es lo que necesitamos hacer aquí.



Así que acá está una idea aproximada de lo que debería hacer:
- Dividiremos la página en 4 partes; encabezado, navegación y encabezado del contenido y el resto del contenido.
- El área del encabezado será una sencilla etiqueta contenedor <div>.
- La navegación será dividida en varias <div> contenedores complementando los ítem del menú.
- El contenido será un simple <div> contenedor.
Ahora, la mayor parte del tiempo usaremos las etiquetas html; <ul> y <li> como contenedores, pero ya que cada ítem del menú es único,
no veo las ventajas de usar las etiquetas <ul> y <li>, así que voy a usar un <div> contenedor en lugar de ellas.
Así que para resumirlo.
1 |
|
2 |
<!-- header section-->
|
3 |
<div id="header"></div> |
4 |
|
5 |
<!-- navigation section-->
|
6 |
<div id="navigation" class="container"> |
7 |
<div><a href="#">home</a></div> |
8 |
<div><a href="#">about</a></div> |
9 |
<div><a href="#">services</a></div> |
10 |
<div><a href="#">solutions</a></div> |
11 |
<div><a href="#">contact</a></div> |
12 |
</div>
|
13 |
|
14 |
<!-- container section-->
|
15 |
<div class="container"> |
16 |
<div id="content-title"></div> |
17 |
<!-- rest of the content -->
|
18 |
</div>
|
Podría ayudar el mostrar la estructura del directorio. La estructura del directorio es la siguiente:



Paso 2: Recursos
Supongo que usted tiene un conocimiento básico usando Photoshop, por lo tanto, no voy a dar demasiadas instrucciones detalladas en crear los recursos.
Hay varias cosas que necesitamos crear.
- Fondo del Encabezado
- Título del Contenido
- Navegación
- Franja del fondo
Note que si usted desea omitir este paso, entonces usted puede descargar los archivos zip que están al final de éste curso y ¡extraer mis copias!
De acuerdo, vamos a crear el fondo para el encabezado. Abra Photoshop y cree un lienzo de 1 x 181 px o usted puede crear uno más largo y luego recortar la imagen.
Cree una capa y aplique un degradado linea con un color preestablecido Frontal a Fondo para 171px, éste será el degradado principal.
Cree otra capa y aplique un degradado linea con un color preestablecido Frontal a Fondo para 10px al fondo de la primer capa para algunos efectos de sombras.
Aquí esta como es que debería lucir, éste tiene 100x181px que después podemos recortar a 1 x 181px.



Guarde este archivo como 'hdr_bkg.png' en nuestra carpeta 'img'.
A continuación crearemos el título del contenido. Nuevamente, abra Photoshop y cree un documento de 934x284 px.
Cree una Rectángulo Redondeado usando la herramienta adecuada, seleccione la forma creada, cree una capa nueva, añada un degradado y dele algún efecto de sombra.
Luego, tendremos algo como esto:



Guarde este archivo como 'content-title.png' en la carpeta 'img'.
Ahora vamos a crear los recursos que necesitamos para la navegación. Necesitamos dos conjuntos de navegación y una caja blanca.
La caja blanca es sencilla. Solamente cree un rectángulo redondeado de 98 x 58 pixeles y píntelo con color blanco. Asegúrese que el fondo es transparente.

Guarde este archivo como 'white.jpg' en la carpeta 'img'.
Para el ítem de la navegación, abra Photoshop y cree un documento de 490 x 58 pixeles.
Cree un rectángulo redondeado con un tamaño aproximado de 98px x 58px y ponga alto de texto en él. Necesitaremos dos copias de cada texto.
Yo aplique un poco de sombra paralela a cada texto, aunque esto por supuesto, es opcional. Usted puede escoger sus propios colores.



Ahora, simplemente duplique esta capa junto a la línea horizontal. Aplique diferentes colores y textos.



Guarde este archivo como 'nav.jpg' en la carpeta 'img'.
Finalmente, para la franja del fondo, simplemente he usado una herramienta que encuentra en línea llamada Stripe Generator. El resultado tiene una aspecto parecido a este:

Usted puede ver mi configuraciones aquí.
Por supuesto, usted podría crear la franja usted mismo en Photoshop, pero porque no usar una estupenda herramienta web :-)
Paso 3: Código HTML
Ahora vamos a anotar nuestro HTML.
1 |
|
2 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3 |
<html xmlns="http://www.w3.org/1999/xhtml"> |
4 |
<head>
|
5 |
<title>slick animated menu</title> |
6 |
<!--our CSS file-->
|
7 |
<link rel="stylesheet" href="css/main.css" type="text/css" /> |
8 |
<!--jQuery library-->
|
9 |
<script type="text/javascript" src="js/jquery.js" ></script> |
10 |
<!--jQuery plugin, we’ll get to this later-->
|
11 |
<script type="text/javascript" src="js/jquery-bp.js" ></script> |
12 |
<!--Our animation script-->
|
13 |
<script type="text/javascript" src="js/navigation.js" ></script> |
14 |
</head>
|
15 |
<body>
|
16 |
<div id="header"></div> |
17 |
<div id="navigation" class="container"> |
18 |
<div id="home"><a href="home">home</a></div> |
19 |
<div id="about"><a href="about">about</a></div> |
20 |
<div id="services"><a href="services">services</a></div> |
21 |
<div id="solutions"><a href="solutions">solutions</a></div> |
22 |
<div id="contact"><a href="contact">contact</a></div> |
23 |
</div>
|
24 |
<div class="container"> |
25 |
<div class="content"> |
26 |
<div id="content-title"></div> |
27 |
<!-- the rest of the content-->
|
28 |
</div>
|
29 |
</div>
|
30 |
</body>
|
Esto es de acuerdo a nuestro plan de juego explicado en el Paso 1.
He añadido un enlace hacia un archivo 'main.css' que ya está creado y
además, he añadido algunas referencias a algunos archivos javascript. Ya que cada ítem de la navegación es único, le he dado a cada ítem un ID.
Aún necesitaremos algunos estilos comunes para cada una de los ítem del menú, esto hará mucho más fácil para nosotros controlar los estilos en fases posteriores.
También tendremos una caja blanca en la parte superior de cada ítem de la navegación aparecer, cuando pasemos el mouse sobre el menú o cuando un ítem del menú esté siendo seleccionado, por lo que necesitaremos crear otro <div> contenedor para eso. El HTML final debería lucir como este:
1 |
|
2 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3 |
<html xmlns="http://www.w3.org/1999/xhtml"> |
4 |
<head>
|
5 |
<title>slick animated menu</title> |
6 |
|
7 |
<link rel="stylesheet" href="css/main.css" type="text/css" /> |
8 |
|
9 |
<script type="text/javascript" src="js/jquery.js" ></script> |
10 |
<script type="text/javascript" src="js/jquery-bp.js" ></script> |
11 |
<script type="text/javascript" src="js/navigation.js" ></script> |
12 |
</head>
|
13 |
<body>
|
14 |
<div id="header"></div> |
15 |
<div id="navigation" class="container"> |
16 |
<div id="home" class="pri-nav"><div><a href="home">home</a></div></div> |
17 |
<div id="about" class="pri-nav"><div><a href="about">about</a></div></div> |
18 |
<div id="services" class="pri-nav"><div><a href="services">services</a></div></div> |
19 |
<div id="solutions" class="pri-nav"><div><a href="solutions">solutions</a></div></div> |
20 |
<div id="contact" class="pri-nav"><div><a href="contact">contact</a></div></div> |
21 |
</div>
|
22 |
<div class="container"> |
23 |
<div class="content"> |
24 |
<div id="content-title"></div> |
25 |
<!-- the rest of the content-->
|
26 |
</div>
|
27 |
</div>
|
28 |
</body>
|
Guarde este archivo como 'index.html'. Hasta este punto tenemos esto como nuestra página HTML:



Paso 4: CSS
Déjenos aplicar algunos estilos básicos de la página web. Empezaremos definiendo el fondo y añadiendo un área para un encabezado.
1 |
|
2 |
body { |
3 |
background: url(../img/body-bkg.jpg) repeat scroll; |
4 |
margin: 0; |
5 |
padding: 0; |
6 |
}
|
7 |
|
8 |
.containe r{ |
9 |
margin: 0pt auto; |
10 |
width:950px; |
11 |
}
|
12 |
#header { |
13 |
background: url(../img/hdr-bkg.jpg) repeat-x scroll; |
14 |
height:181px; |
15 |
}
|
Guarde este archivo como 'main.css' en la carpeta 'css'.
Ahora tenemos algo que luce así:



Ahora vamos a añadir estilos a cada uno de los ítem del menú. Recuerde que queremos la caja blanca en la parte superior de cada ítem,
así que el valor para la propiedad, posición deberá ser; absolute. Agregue los siguientes estilos en nuestro archivo 'main.css'.
1 |
|
2 |
#navigation{ |
3 |
height:60px; |
4 |
}
|
5 |
|
6 |
#home, #home div, |
7 |
#about, #about div, |
8 |
#services , #services div, |
9 |
#solutions, #solutions div, |
10 |
#contact, #contact div { |
11 |
height:80px; |
12 |
position:absolute; |
13 |
width:97px; |
14 |
float:left; |
15 |
}
|
16 |
|
17 |
#home, #about, #services, #solutions, #contact{ |
18 |
background-image: url(../img/nav.jpg); |
19 |
background-attachment: scroll; |
20 |
background-repeat: no-repeat; |
21 |
top:171px; |
22 |
}
|
23 |
|
24 |
#home{ |
25 |
background-position: 0px -25px; |
26 |
margin-left:6px; |
27 |
}
|
28 |
|
29 |
#about{ |
30 |
background-position: -98px -25px; |
31 |
margin-left:105px; |
32 |
}
|
33 |
|
34 |
#services{ |
35 |
background-position: -196px -25px; |
36 |
margin-left:204px; |
37 |
}
|
38 |
|
39 |
#solutions{ |
40 |
background-position: -294px -25px; |
41 |
margin-left:303px; |
42 |
}
|
43 |
|
44 |
#contact{ |
45 |
background-position: -392px -25px; |
46 |
margin-left:402px; |
47 |
}
|
48 |
|
49 |
#home div, #about div, #services div, #solutions div, #contact div { |
50 |
background-image: url(../img/white.jpg); |
51 |
background-attachment: scroll; |
52 |
background-repeat: no-repeat; |
53 |
background-position: 0px -60px; |
54 |
}
|
Ahora tenemos:



Un problema, la etiqueta <a href> aparece arriba de los ítems del menú, vamos a quitar eso con un número enorme en la propiedad; text indent, que efectivamente lo sacará de la pantalla.
Añada esto a nuestra hoja de estilos.
1 |
|
2 |
.pri-nav a{ |
3 |
display:block; |
4 |
text-decoration:none; |
5 |
text-indent:-30000px; |
6 |
}
|
Ahora debería lucir como este:



Sin embargo, aún tenemos un problema, nos gustaría que el menú de la navegación apareciera debajo de la sombra del encabezado. Podemos lograr eso modificando el estilo de nuestro encabezado.
1 |
|
2 |
#header{ |
3 |
background: url(../img/hdr-bkg.jpg) repeat-x scroll; |
4 |
height:181px; |
5 |
position:absolute; |
6 |
z-index :100; /* ensure the header is on top of navigation area */ |
7 |
top: 0px; |
8 |
left:0px; |
9 |
width:100%; |
10 |
}
|
Ahora, debido a que usamos un archivo .png con transparencia, éste debería lucir así:



¡Perfecto! Vamos añadir el contenido para que podamos conseguir el script de nuestra animación.
1 |
|
2 |
.content{ |
3 |
margin-top:160px; |
4 |
}
|
5 |
|
6 |
#content-title{ |
7 |
background: url(../img/content.jpg) no-repeat scroll; |
8 |
height:323px; |
9 |
position:absolute; |
10 |
width:100%; |
11 |
}
|
Paso 5: Script de la animación
Primero, vamos a descargar el último script de jQuery y colocarlo en la carpeta 'js'.
La animación es básicamente una manipulación del estilo de la posición del fondo.
Desafortunadamente, jQuery tiene una error en la animación del estilo de la posición del fondo. ¡Pero, no se preocupe! Alexander Farkas ha creado un pluging que resuelve este problema.
Descargue el archivo y póngale el nombre jquery-bp.js y guardelo en la carpeta 'js'.
Hay algo que necesitamos entender antes de continuar. He citado desde la documentación del plugin:
Debido a errores en algunos de los navegadores (por ejemplo, Firefox, usted tiene que ajustar la propiedad (inicial) del background-position [posición del fondo] en 'inline':
<div style="background-posiciton: 10px 20px"</div>
- Por supuesto, usted puede lograr esto, también, con JavaScript (jQuery):
$('#background).css({backgroundPosition:'10px 20px'});
De acuerdo, ahora que entendemos eso, vamos a empezar. Ajustaremos el estilo de la posición del fondo para cada ítem en el principio de nuestro script.
1 |
|
2 |
// id for each of our menu items
|
3 |
var nav = [ '#home', '#about', '#services', '#solutions', '#contact' ]; |
4 |
$(document).ready(function(){ |
5 |
setBkgPos(); |
6 |
});
|
7 |
|
8 |
function setBkgPos() |
9 |
{
|
10 |
for ( i = 0; i < nav.length; i++ ){ |
11 |
$(nav[i]).css({backgroundPosition: i*(-98) + 'px -25px'}); |
12 |
$(nav[i] + ' div').css({ backgroundPosition: '0px -60px'}); |
13 |
}
|
14 |
}
|
Guarde este archivo como 'navigation.js' en la carpeta 'js'.
Ahora uniremos 3 eventos para cada uno de los ítem del menú. Podemos hacer esto invocando una función 'bind'.
1 |
|
2 |
$(document).ready(function(){ |
3 |
setBkgPos(); |
4 |
|
5 |
// bind the event to function here
|
6 |
for ( i = 0; i < nav.length; i++ ) { |
7 |
$(nav[i]).bind( 'mouseover', mMouseOver ); |
8 |
$(nav[i]).bind( 'mouseout', mMouseOut ); |
9 |
$(nav[i]).bind( 'click', mClick ); |
10 |
}
|
11 |
});
|
Siempre que un usuario pase el puntero sobre un ítem de la navegación, nuestro script llamará a la función 'mMouseOver'.
Cuando el usuario retire el puntero de un ítem de la navegación, entonces nuestro script llamará a la función 'mMouseOut'.
Y cuando el usuario haga clic sobre un ítem de la navegación, nuestro script llamará a la función 'mClick'.
Paso 5.1: Evento Mouse over
Vamos a crear un "guión gráfico" para nuestra animación cuando el puntero se desplaza sobre algún ítem.
En el evento 'Mouse Over':
- Cambie la imagen del menú de la navegación (brillo) y cambie el cursor a un puntero.
- La navegación se moverá un poco.
- La caja blanca se moverá hacia abajo.
- La caja blanca y el menú de la navegación descenderán.
- El menú de la navegación y la caja blanca se moverán hacia arriba a su final posición.
- Y cambie la imagen del menú de la navegación a su estado original.



De acuerdo, vamos a añadir éstas funciones debajo del script anterior:
1 |
|
2 |
function _getHPos( id ) |
3 |
{
|
4 |
for ( i = 0; i < nav.length; i++ ){ |
5 |
if ( '#' + id == nav[i] ){ |
6 |
return i*(-98); |
7 |
}
|
8 |
}
|
9 |
return 0; |
10 |
}
|
11 |
|
12 |
function mMouseOver(e) |
13 |
{
|
14 |
$(this) |
15 |
// stop any animation that took place before this
|
16 |
.stop() |
17 |
// step 1. change the image file and change the cursor
|
18 |
.css({backgroundImage: 'url('+site_url+'img/nav-over.jpg)',cursor: 'pointer'}) |
19 |
// step.2 move up the navigation item a bit
|
20 |
.animate({ backgroundPosition:'(' + _getHPos( this.id ) +'px -30px}'},"fast", |
21 |
// this section will be executed after the step.2 is done
|
22 |
function(){ |
23 |
$(this) |
24 |
.children() |
25 |
// step. 3 move the white box down
|
26 |
.animate({backgroundPosition:'(0px -40px)'},20) |
27 |
// step 4. move the white box down
|
28 |
.animate({backgroundPosition:'(0px -20px)'},"fast"); |
29 |
$(this) |
30 |
// step 4. move the navigation item down
|
31 |
.animate({backgroundPosition:'(' + _getHPos( this.id ) +'px 50px)'},"fast") |
32 |
// step 5. move the navigation item to its final position
|
33 |
.animate({backgroundPosition:'(' + _getHPos( this.id ) +'px 25px)'},"fast"); |
34 |
// store the parent element id for later usage
|
35 |
var parent = this; |
36 |
$(this) |
37 |
.children() |
38 |
// step 5. move the white box to its final position
|
39 |
.animate( {backgroundPosition:'(0px -45px)'},"fast", |
40 |
// this section will be executed after the step.2 is done
|
41 |
function(){ |
42 |
// step.6 change the image to its original image
|
43 |
$(parent).css({backgroundImage: 'url(img/nav.jpg)'}); |
44 |
});
|
45 |
});
|
46 |
}
|
Necesito explicar varias cosas aquí:
- El _getHPos es usado para ajustar la posición horizontal del fondo de la navegación para cada ítem.
Por ejemplo, el ítem 'Home' del fondo empieza desde 0, la posición horizontal para el fondo de 'About' empieza desde los -98px y así sucesivamente. - Además. note que anteriormente en la función, invocamos la función 'stop'. Hacemos esto para asegurar que todo lo que la animación está ejecutando antes del evento 'mouse over' está detenido.
¿Por qué? Añadiremos otra animación después para el evento 'mouse out'.
Ahora vamos a suponer que el usuario desplazo el puntero sobre un ítem y entonces rápidamente mueva el puntero en alguna parte y otra vez rápidamente pase el puntero encima del mismo ítem.
Si no detenemos la animación antes de cada evento, habrá un retraso porque algunas partes de la animación estarán en fila o incluso peor la animación se volverá inconsistente y molesta para el usuario.
Paso 5.2: Evento Mouse out
Ahora está hecho. Vamos a crear un "guión gráfico" para el evento 'mouse out'.
En el evento 'Mouse Out':
- Mueva hacia abajo el ítem de la navegación.
- Mueva la caja blanca hacia abajo.
- Mueva la navegación arriba.
- Mueva los ítem de la navegación arriba a su posición original.
- Mueva la caja blanca a su posición original (invisible).
- Regrese el cursor a normal.



El código:
1 |
|
2 |
function mMouseOut(e) |
3 |
{
|
4 |
$(this) |
5 |
// stop any animation that took place before this
|
6 |
.stop() |
7 |
// step.1 move down navigation item
|
8 |
.animate({backgroundPosition:'(' + _getHPos( this.id ) +'px 40px )'}, "fast", |
9 |
// this section will be executed after the step.1 is done
|
10 |
function(){ |
11 |
// step.2 white box move really fast
|
12 |
$(this).children().animate({backgroundPosition:'(0px 70px)'}, "fast"); |
13 |
// step 3. move navigation item up
|
14 |
$(this).animate( {backgroundPosition:'(' + _getHPos( this.id ) +'px -40px)'}, "fast", |
15 |
// this section will be executed after the step.3 is done
|
16 |
function(){ |
17 |
// step 4. move navigation item ot its original position
|
18 |
$(this).animate( {backgroundPosition:'(' + _getHPos( this.id ) +'px -25px)'}, "fast", |
19 |
// this section will be executed after the step.4 is done
|
20 |
function(){ |
21 |
// move white box to its original position, ready for next animation
|
22 |
$(this).children().css({ backgroundPosition:'0px -60px'}); |
23 |
})
|
24 |
})
|
25 |
})
|
26 |
.css({backgroundImage: 'url(img/nav.jpg)', cursor: ''}); |
27 |
}
|
Paso 5.3: Click
¡Casi terminamos! Ahora necesitamos necesitamos controlar cuan un usuario hace clic en el ítem de la navegación.
1 |
|
2 |
function mClick(e) |
3 |
{
|
4 |
location.href = this.id; |
5 |
}
|
Por supuesto, usted puede apuntar donde quiera ubicar su ubicación aquí. Esta función en particular dirige su navegador hacia [current_url]/[navigation_id] para que 'home' será '[current_url]/home', para 'about' será '[current_url]/about' y así sucesivamente.
Paso 5.4: Indicador de la página actual
Por supuesto, necesitamos un indicador cuando ya tenemos lista una página. Para eso necesitamos otra clase CSS.
Llamaremos esa clase 'active'. Por ejemplo si ahora estamos en 'home' el archivo HTML se convertirá:
1 |
|
2 |
<div id="home" class="pri-nav active"><div><a href="home">home</a></div></div> |
O si estamos en 'about' éste se convertirá:
1 |
|
2 |
<div id="about" class="pri-nav active"><div><a href="about">about</a></div></div> |
y así sucesivamente.
Así que ahora la idea es después que una página es cargada nuestro script verificará para ver que ítem de navegación tiene la clase 'active'.
Entonces podemos aplicar un efecto de animación. Y necesitamos asegurarnos que cualquier otro evento ('mouseover', 'mouseout', 'click') no causará cualquier efecto de animación en éste ítem 'active'.
Para eso necesitamos cambiar nuestro código un poco. Aquí esta completo el código después de los cambios:
1 |
|
2 |
var site_url = ''; |
3 |
var nav = [ '#home', '#about', '#services', '#solutions', '#contact' ]; |
4 |
|
5 |
$(document).ready(function(){ |
6 |
setBkgPos(); |
7 |
|
8 |
for ( i = 0; i < nav.length; i++ ) { |
9 |
$(nav[i]).bind( 'mouseover', mMouseOver ); |
10 |
$(nav[i]).bind( 'mouseout', mMouseOut ); |
11 |
$(nav[i]).bind( 'click', mClick ); |
12 |
}
|
13 |
|
14 |
for ( i = 0; i < nav.length; i++ ) { |
15 |
// element with ‘active’ class will start animation
|
16 |
if ( $(nav[i]).get(0).className.indexOf('active') >= 0 ){ |
17 |
$(nav[i]) |
18 |
.animate({ backgroundPosition:'(' + _getHPos( nav[i] ) +'px -30px}'},"fast", |
19 |
function(){ |
20 |
$(this) |
21 |
.children() |
22 |
.animate({backgroundPosition:'(0px -40px)'},20) |
23 |
.animate({backgroundPosition:'(0px -20px)'},"fast"); |
24 |
$(this) |
25 |
.animate({backgroundPosition:'(' + _getHPos( nav[i] ) +'px 50px)'},"fast") |
26 |
.animate({backgroundPosition:'(' + _getHPos( nav[i] ) +'px 25px)'},"fast"); |
27 |
var parent = this; |
28 |
$(this) |
29 |
.children() |
30 |
.animate( {backgroundPosition:'(0px -45px)'},"fast", |
31 |
function(){ |
32 |
$(parent).animate({backgroundPosition:'(' + _getHPos( parent.id ) +'px 25px)'},"fast"); |
33 |
$(parent).css({backgroundImage: 'url(img/nav.jpg)'}); |
34 |
});
|
35 |
});
|
36 |
break; |
37 |
}
|
38 |
}
|
39 |
});
|
¡Terminado!
Y con eso tenemos nuestro pequeño menú ingenioso.