En esta segunda y última parte profundizamos en la técnica de CSS “CSS Sprites” con un ejemplo práctico en el cual recrearemos el funcionamiento del menú superior horizontal de la web oficial de Apple. Todo ello paso a paso y de forma clara… ¡como siempre!

Autor:

Hola! Soy diseñador, programador web y cofundador de la startup Cokidoo, desarrollamos aplicaciones web a gran escala y comercio electrónico, aplicaciones para móviles y advertising. Puedes seguirme através de mi twitter y ver algunos de mis themes en Themeforest. También soy aficionado a la fotografía.
Descarga Demostración

Este tutorial forma parte de una serie

Introducción: ¿Qué vamos a hacer?

Continuamos con la segunda y última parte de esta serie de tutoriales. En la 1ª parte nos habíamos centrado en la teoría, recopilando un poco de historia acerca de los orígenes de los sprites y de las ventajas que nos aportaban en el diseño web.

Una vez conocida la teoría, sólo nos queda realizar pruebas y ejemplos prácticos que nos demuestren lo leído y aprendido hasta ahora. En esta ocasión el ejemplo escogido es la recreación del funcionamiento del menú horizontal de la web oficial de Apple todo ello usando CSS Sprites.

Recrearemos el menú horizontal de la web oficial de Apple mediante la técnica CSS Sprites que estamos analizando en esta serie de tutoriales.

Será interesante ver cómo con un poco de ingenio podemos llegar a recrear un menú funcional con hasta cuatro estados para cada botón además de evitar los tiempos de carga de imágenes secundarias. Os dejo con una imagen previa, seguro que a más de uno os suena :) :

Vista previa menú Apple

En realidad hemos acortado el número de secciones para la imagen previa para no tener que escalar y perder detalle de la imagen previa. Dicho esto… ¡Vamos a ello!

Paso 1: Identificando los 4 estados de los botones

Como hemos comentado en la introducción, cada botón / sección tendrá hasta cuatro estados distintos. Los siguientes descritos a continuación:

  • Normal: Sin seleccionar, ni estar activo… etc.
  • Hover: Cuando el usuario pasa el ratón por encima, pero no está activa.
  • Click: Cuando recibe un click por parte del usuario.
  • Activo: Sección en la que nos encontramos.

Para recrear estos cuatro estados, nos valdremos de la imagen / sprite que tienen en la web de Apple. Este sería el esquema de estados en nuestra imagen:

Estados del menú

Como veis, los cuatro estados del menú están incluídos en una única imagen, alterando el background-position conseguiremos mostrar los distintos estados según nuestras necesidades. Vayamos al siguiente paso, donde comenzaremos a organizar nuestra estrategia para el background-position en el CSS.

Paso 2: Organizando y dividiendo nuestro Sprite

Como hemos podido ver en la imagen previa anterior de los estados, vamos a necesitar organizar la imagen en “trozos” de forma que cada rectángulo recoja el botón a mostrar alterando la propiedad de CSS background-position.

Es importante recordar que la propiedad background-position está siempre referida al borde superior izquierdo, o lo que es lo mismo a las coordenadas o punto (0, 0).

Las secciones / botones del menú de Apple tienen el mismo ancho, concretamente un ancho de 177 pixels por 37 pixels de altura. Quizás quede poco claro hablando de cantidades, pero con esta imagen se verá mucho más clara la grid / red de sprites que llevaremos a cabo:

Imagen del menú con medidas

Una vez definido claramente cuál será nuestro esquema para abordar el Sprite / imagen, lo único que nos queda por hacer es ponernos manos a la obra, y comenzar a escribir primero el código HTML de nuestro menú, y segundo, aplicar el código CSS que emplearemos para recrear los distintos estados. ¡Vamos a ello!

Paso 3: La estructura HTML

El documento HTML será bastante simple, sólo necesitaremos crear una lista con la que recrear el menú, en este caso del tipo desordenada (<ul>) con elementos que contengan el enlace a cada sección de nuestra página web. Crearemos hasta 3 menús distintos cada uno con pequeños cambios para ver los diferentes estados posibles en las secciones.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="es-ES">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Introducción, Comprensión y Utilización de los CSS Sprites: Parte II</title>
    <link rel="stylesheet" href="main.css" type="text/css" media="screen" />
    < !--[if lte IE 6]><link rel="stylesheet" href="ie6.css" type="text/css"/><![endif]-->
</head>
<body>
    <div class="wrapper">
        <h1>Introducción, Comprensión y Utilización de los CSS Sprites: Parte II</h1>
        <h2>Sección Inicio activa</h2>
        <div class="clearfix">
            <ul class="menu">
                <li class="inicio activo inicio_ie6"><a href="#">Inicio</a></li>
                <li class="store"><a href="#">Store</a></li>
                <li class="mac"><a href="#">Mac</a></li>
                <li class="ipod"><a href="#">iPod+iTunes</a></li>
                <li class="iphone"><a href="#">iPhone</a></li>
                <li class="downloads"><a href="#">Downloads</a></li>
                <li class="support"><a href="#">Support</a></li>
            </ul>
            <div id="final"></div>
        </div>
        <h2>Sección Mac activa</h2>
        <div class="clearfix">
            <ul class="menu">
                <li class="inicio"><a href="#">Inicio</a></li>
                <li class="store"><a href="#">Store</a></li>
                <li class="mac activo mac_ie6"><a href="#">Mac</a></li>
                <li class="ipod"><a href="#">iPod+iTunes</a></li>
                <li class="iphone"><a href="#">iPhone</a></li>
                <li class="downloads"><a href="#">Downloads</a></li>
                <li class="support"><a href="#">Support</a></li>
            </ul>
            <div id="final"></div>
        </div>
        <h2>Sección iPhone activa y menor ancho en el borde final</h2>
        <div class="clearfix">
            <ul class="menu">
                <li class="inicio"><a href="#">Inicio</a></li>
                <li class="store"><a href="#">Store</a></li>
                <li class="mac"><a href="#">Mac</a></li>
                <li class="ipod"><a href="#">iPod+iTunes</a></li>
                <li class="iphone activo iphone_ie6"><a href="#">iPhone</a></li>
                <li class="downloads"><a href="#">Downloads</a></li>
                <li class="support"><a href="#">Support</a></li>
            </ul>
            <div id="final" class="alter"></div>
        </div>
    </div>
</body>
</html>

Así pues, los menús tendrán las siguientes peculiaridades (que se aplicaran posteriormente en el CSS):

  • Primer menú: La sección Inicio estará activa, por lo que no tendrá efecto hover ni click.
  • Segundo menú: La sección Mac estará activa, por lo que no tendrá efecto hover ni click.
  • Tercer menú: La sección iPhone estará activa, por lo que no tendrá efecto hover ni click y además el borde derecho tendrá menos longitud.

También estamos utilizando una división al lado de nuestro menú conocida con el identificador “final”, será el borde redondeado que aparecerá a la derecha. Es simplemente por tener un aspecto visual un poco más bonito, y para que quede exactamente igual al original (también nos servirá para explicar un truco de CSS más adelante).

A pesar de usar imágenes de fondo para el menú, no hay que olvidarse de añadir el texto de sección correspondiente a los enlaces. De esta forma tanto personas que no tengan CSS como los buscadores que indexen nuestra web, podrán leer perfectamente el menú.

Los más observadores habréis podido ver que estamos utilizando un código “extraño” en la línea 7 de nuestro código HTML. Lo que conseguimos con esto, llamado comentario condicional, es cargar un archivo de CSS a mayores del original para aplicar a un navegador en particular. Sólo funciona con Internet Explorer y en este caso, hemos especificado que los problemas se darán en la sección Internet Explorer 6.

¿Qué raro que falle el Internet Explorer 6, no? :) . Vamos a por la parte interesante del tutorial… ¡a por el CSS!

Paso 4: Maquetando el menú horizontal

Como en cada tutorial de maquetación, vamos a utilizar un CSS reset que nos facilitará la vida a la hora de maquetar y se vea prácticamente igual en todos los navegadores sin apenas esfuerzo. En esta ocasión vamos a omitir la copia del código en el tutorial, pero podréis encontrarlo en los archivos de descarga.

Recordado el CSS reset, nos toca analizar nuestro menú horizontal. Para ello haremos uso de la propiedad float, en este caso “float: left” lo cual nos permitirá variar el flujo de alineación de nuestro menú, y en lugar de mostrarse los elementos uno debajo de otro, se mostrarán en una misma línea horizontal. Como siempre, una imagen vale más que mil palabras:

Imagen previa del menú horizontal en estado prematuro

Para ello el código CSS que hemos aplicado es bastante más sencillo de lo que cabría esperar:

.menu li{
    float: left;
}
.menu li a{
    width: 117px;
    line-height: 37px;
    text-align: center;
    float: left;
}

Analizando el código que acabamos de añadir, podemos ver cómo se le ha aplicado el valor “float: left;” tanto al elemento de la lista, como al propio enlace contenido, esto no es necesario en todos los navegadores, pero en otros como por ejemplo el Internet Explorer 6 y 7 sí que es necesario.

Además hemos aplicado “width: 117px;” y “line-height: 37px”… ¿no os suenan de algo estas cantidades? Pues si no os suenan, deberían, son las dimensiones en anchura y altura para los botones de cada sección que analizábamos en pasos anteriores, cuando organizábamos la distribución de nuestro Sprite.

Para recrear un menú horizontal es necesario aplicar la propiedad CSS “float” (a los distintos elementos) la cual permite variar el flujo de alineación en la maquetación a nuestro antojo: izquierda (float: left;) y derecha (float: right;).

El menú horizontal estaría prácticamente listo, pero nos queda aplicarle la técnica de CSS Sprite para darle un toque visual mucho más vistoso.

Paso 5: Aplicando la técnica de CSS Sprites

Llegamos a la parte final de este tutorial, ya tenemos nuestro menú horizontal perfectamente alineado y funcional, por lo que nos queda darle el acabado visual que deseemos. Para ello utilizaremos distintas propiedades CSS como: background-color, background-image, background-position, background-repeat y text-indent.

Todas estas propiedades de CSS que comienzan por “background-” pueden ser resumidas en la propiedad “background” de forma que nos ahorraremos líneas de código CSS y se aplicarán como si las definiésemos una a una.

¿Para qué queremos la propiedad “text-indent” en nuestro CSS? Pues muy sencillo: necesitamos ocultar los textos (que no eliminar) para que sólo se vea nuestra imagen de fondo en cada botón / sección. De esta forma los buscadores y usuarios sin CSS nos indexarán / leerán perfectamente, y los usuarios con dispositivos que interpreten el CSS verán nuestro menú tal y como lo hemos diseñado.

Así pues el elemento “.menu li a” que teníamos anteriormente, pasará a tener una línea más entre sus propiedades:

.menu li a{
    width: 117px;
    line-height: 37px;
    text-align: center;
    float: left;
    text-indent: -99999px;
}

Ocultados los textos de nuestras secciones, ya sólo nos queda aplicar la famosa técnica de CSS Sprite para definir las distintas imágenes de fondo para nuestro menú, en cada uno de sus estados. Para ello utilizaremos una clase por cada sección, de forma que los distintos eventos que nos permite reconocer el CSS nos permitirá definir cada imagen fondo, para cada estado:

.menu li.inicio a{
    background: transparent url(img/menu.png) no-repeat scroll 0 0;
}
.menu li.inicio a:hover{
    background: transparent url(img/menu.png) no-repeat scroll 0 -38px;
}
.menu li.inicio a:active{
    background: transparent url(img/menu.png) no-repeat scroll 0 -76px;
}
.menu li.inicio.activo a{
    background: transparent url(img/menu.png) no-repeat scroll 0 -114px;
}
.menu li.store a{
    background: transparent url(img/menu.png) no-repeat scroll -117px 0;
}
.menu li.store a:hover{
    background: transparent url(img/menu.png) no-repeat scroll -117px -38px;
}
.menu li.store a:active{
    background: transparent url(img/menu.png) no-repeat scroll -117px -76px;
}
.menu li.store.activo a{
    background: transparent url(img/menu.png) no-repeat scroll -117px -114px;
}
.menu li.mac a{
    background: transparent url(img/menu.png) no-repeat scroll -234px 0;
}
.menu li.mac a:hover{
    background: transparent url(img/menu.png) no-repeat scroll -234px -38px;
}
.menu li.mac a:active{
    background: transparent url(img/menu.png) no-repeat scroll -234px -76px;
}
.menu li.mac.activo a{
    background: transparent url(img/menu.png) no-repeat scroll -234px -114px;
}
.menu li.ipod a{
    background: transparent url(img/menu.png) no-repeat scroll -351px 0;
}
.menu li.ipod a:hover{
    background: transparent url(img/menu.png) no-repeat scroll -351px -38px;
}
.menu li.ipod a:active{
    background: transparent url(img/menu.png) no-repeat scroll -351px -76px;
}
.menu li.ipod.activo a{
    background: transparent url(img/menu.png) no-repeat scroll -351px -114px;
}
.menu li.iphone a{
    background: transparent url(img/menu.png) no-repeat scroll -468px 0;
}
.menu li.iphone a:hover{
    background: transparent url(img/menu.png) no-repeat scroll -468px -38px;
}
.menu li.iphone a:active{
    background: transparent url(img/menu.png) no-repeat scroll -468px -114px;
}
.menu li.iphone.activo a{
    background: transparent url(img/menu.png) no-repeat scroll -468px -114px;
}
.menu li.downloads a{
    background: transparent url(img/menu.png) no-repeat scroll -585px 0;
}
.menu li.downloads a:hover{
    background: transparent url(img/menu.png) no-repeat scroll -585px -38px;
}
.menu li.downloads a:active{
    background: transparent url(img/menu.png) no-repeat scroll -585px -76px;
}
.menu li.downloads.activo a{
    background: transparent url(img/menu.png) no-repeat scroll -585px -114px;
}
.menu li.support a{
    background: transparent url(img/menu.png) no-repeat scroll -702px 0;
}
.menu li.support a:hover{
    background: transparent url(img/menu.png) no-repeat scroll -702px -38px;
}
.menu li.support a:active{
    background: transparent url(img/menu.png) no-repeat scroll -702px -114px;
}
.menu li.support.activo a{
    background: transparent url(img/menu.png) no-repeat scroll -702px -114px;
}

Para aquellos que no estéis familiarizados con la propiedad “background” contenedora de todas las propiedades “background-” el esquema es el siguiente:

elemento{
    background: [background-color] [background-image] [background-repeat] [background-position]
}

Recordad que el background-position se refiere siempre respecto a la esquina superior izquierda: distancia en horizontal y distancia en vertical (en este orden).

Hemos creado una clase de CSS llamada “activo” con la cual podemos definir la sección que está activa en nuestro menú. Es una segunda clase asignada al elemento del menú que lamentablemente el Internet Explorer 6 no reconoce, por lo que tenemos que asignar una tercera en los elementos que estén activos: “inicio_ie6″, “mac_ie6″ y “iphone_ie6″.

Esto lo hemos hecho gracias al comentario condicional, que comentábamos anteriormente, el cual nos permite cargar otra hoja de estilos CSS únicamente para el navegador Internet Explorer 6.

Para el borde derecho de nuestro menú hemos asignado el siguiente código:

/******* FINAL *******/
#final{
    width: 163px;
    height: 37px;
    line-height: 37px;
    text-align: center;
    background: transparent url(img/menu.png) no-repeat scroll -819px 0;
    float: left;
}
#final.alter{
    width: 50px;
    background-position: right 0;
}
/******* /FINAL *******/

Como os comentaba anteriormente, el truco que hemos añadido en el tercer menú al borde derecho con la clase “alter”. En lugar de especificar una cantidad en pixels en la distancia horizontal de la propiedad background-position hemos asignado el valor “right” por lo que la imagen comenzará a tenerse en cuenta horizontalmente de derecha a izquierda, y no al revés como suele ser por defecto.

Recordad, esquina superior izquierda “top, left” por defecto, pero de esta forma pasaría a ser “top, right” para la división con el id=”final”.

Dando como valor horizontal “right” a la propiedad CSS background-position conseguimos que el borde derecho de nuestro menú pueda variar en anchura partiendo siempre de la parte derecha, donde tiene el menú redondeado, de lo contrario no ocurriría hasta alcanzar la anchura mínima del borde.

Y con todo esto… ¡hemos terminado!

Factores que pueden afectar a nuestro Sprite

Ahora que sabemos cómo aplicar a nuestros diseños la técnica CSS Sprite, sólo nos queda seguir practicando, jugando e ingeniando nuevas formas de aplicarla.

Si bien en la mayoría de los casos la técnica es rentable y óptima, aveces no lo es, ya que entran en juego otros factores de la imagen final que obtengamos como sprite: el número de colores, el tamaño o peso de la imagen, etc.

Además de otras circunstancias como pueden ser las visitas que tendrán ciertas partes del sprite final, si por ejemplo la mayoría de los iconos que conforman nuestra imagen pertenecen a una sección a la que sólo accede el 1% de nuestros visitantes, es posible que necesitemos 2 sprites: uno para esa sección poco transitada y otra para el resto de nuestra web.

Reflexión final

Como siempre, la última decisión la tenéis vosotros, lo que realmente interesa en todos los tutoriales que publicamos en Web.Ontuts es entender lo que se está explicando, más allá de copiar y pegar el código que os ofrecemos. Sólo así podremos mejorar y aplicar todo lo aprendido, combinándolo con nuestras propias ideas y necesidades.

¡Un saludo y nos vemos en el próximo tutorial!

¿Necesitas desarrollar un proyecto web o para móviles? ¡Estamos disponibles!

Visitar Cokidoo

Cokidoo, los creadores de Ontuts, desarrollamos proyectos tecnológicos centrados en redes sociales y aplicaciones web, aplicaciones móviles y consultoría web y bases de datos.

Somos jóvenes, inquietos, versátiles, apasionados por la innovación y enfocados en las nuevas tecnologías. Con Ontuts tratamos de compartir nuestro conocimiento adquirido en los distintos proyectos, ayudando a la comunidad y mostrando nuestra capacidad tecnológica.

Si necesitas un presupuesto sin compromiso, estamos disponibles, no dudes en contactar con nosotros.

Comentarios en esta publicación (9 comentarios)

¿Te ha gustado esta publicación? ¡Puedes compartir tu opinión con todos nosotros! Simplemente pincha aquí mismo.

Bueno tuto! Aunque me he quedado con las ganas de probarlo… :(

Ostrás! He puesto mal el enlace de pruebas, perdonad!

Braulio Olan

Excelente!, y no solo por la muy detallada explicacion, nunca me puse a reflexionar las ventajas de cargar una imagen mayor a varias pequeñas, gracias!

iDexter

Wow genial! El post me ha aclarado varias dudas que tenía respecto a los menús y los sprites para una práctica de la facultad!

Antonio

Muy bueno el tutorial, me pondre a optimizar mis paginas en breve.
Como han dicho la explicación muy buena.
Seguid así!!!

Marcela

bueno! solo una duda respecto a la funcion de la clase “clearfix” que no esta especificada en el CSS.
gracias!

@Marcela gracias por tus comentarios!

La clase clearfix es una de ayuda que suelo usar con las propiedades: overflow:hidden; y en explorers: zoom: 1;

Una duda. Tu en cada elemento, le añades la propiedad “background” y con ella pues su url, la posición… etc todos los parametros para colocarla. Por ello, ¿el sprite se va a cargar una sola vez al entrar en la web con el menú diseñado o una vez para cada elemento? Creo haber entendido que una vez solo, pero no quiero quedarme con la duda.

Gracias, muy buen tutorial.

@Bernardo la propiedad background se la asigno a todos los elementos que a mí me interese en el CSS, luego en el navegador se renderiza el background en aquellos elementos que cumplan con el selector de CSS.

Cargar se carga una sóla vez la imagen, pero se le aplica como background a todos los elementos que lo requieran.