Un completo curso de diseño gráfico, ilustración, diseño web y tipografía.

Espectros de CSS: El beso de la muerte del troceado de imágenes

por Dave Shea

Cuando los videojuegos todavía eran divertidos (estoy hablando de los días de gloria de los 8-bits), los gráficos eran mucho más simples de necesidad. Los datos bidimensionales y decorados en blanco y negro se dibujaban individualmente, muy en la línea del arte pixelado de hoy en día. Cientos y más tarde miles de pequeños gráficos, llamados “sprites” (espectros) eran los bloques de construcción de todos los aspectos visuales de un juego.

ejemplo de espectros de CSS

A medida que creció la complejidad de los juegos, se desarrollaron técnicas para controlar la multitud de espectros al tiempo que transcurría el juego. Una variación consistía en que los espectros se conectaban a una retícula maestra, y se quitaban cuando era necesario por parte de un código que indicaba las posiciones de cada gráfico individual, y los representaba selectivamente en la pantalla.

¿Qué tiene esto que ver con la web?

Todo lo viejo es nuevo otra vez, y si bien la aparición de los juegos en 3D ha hecho los mapas de espectros obsoletos, al mismo tiempo, el aumento de los móviles con capacidades para jugar en 2D los ha llevado otra vez a la palestra. Y ahora, con un poco de cálculo y mucho de CSS, vamos a retomar el concepto básico y aplicarlo al ámbito del diseño web.

Concretamente, vamos a reemplazar el troceado de imágenes de la vieja escuela (con el Javascript que necesitaba) con una solución en CSS. Dada la manera en que funciona CSS, vamos a llevarlo más lejos: al construir una retícula de imágenes y diseñar un sistema para conseguir cada celda individual de la red, podemos almacenar todos los botones/elementos de navegación/lo que sea que queramos en una sola imagen maestra, junto con los estados de los enlaces de “antes” y “después”.

¿Cómo funcionan los espectros de CSS?

Resulta que las herramientas básicas para esta técnica ya están presentes en CSS, si aplicamos un poco de pensamiento creativo.

Empecemos con la imagen maestra. Dividiendo un rectángulo en cuatro ítems, como puedes observar en esta imagen maestra nuestros estados de los enlaces de “antes” están en la fila superior, y los de “después” (:hover), en la fila inferior. NO hay una división clara entre los cuatro enlaces en este momento, así que imagina que cada parte del texto es un enlace. (Para simplificar, nos referiremos a las imágenes enlazadas como imágenes de “antes” y a las del estado :hover como “después” en el resto del artículo. Es posible extender este método a los otros estados, :active, :focus,y :visited pero no lo haremos para mantener las cosas más simples.

Los que están familiarizados con los rollovers rápidos de Petr Stanicek (Pixy) puede que ya vislumbren dónde vamos a parar. Este artículo debe agradecer el ejemplo de Pixy por la función básica de la que dependeremos. Pero no nos adelantemos.

Sigamos con el HTML. Cada truco de CSS intenta superponer una capa de elementos visuales sobre un código limpio, y esta técnica no es una excepción:

  <ul id="skyline">

    <li id="panel1b"><a href="#1"></a></li>
    <li id="panel2b"><a href="#2"></a></li>
    <li id="panel3b"><a href="#3"></a></li>

    <li id="panel4b"><a href="#4"></a></li>
  </ul>

Este código será la base de nuestro ejemplo. Ligero, simple y que degrada bien en los navegadores viejos o si está deshabilitado el CSS. Esta tendencia es buena para la industria. Es el gran ideal al que debemos aspirar. (Ignoraremos el texto dentro de los enlaces por ahora. Aplica tu técnica de reemplazo de imagen favorita más tarde para ocultar el texto que estás añadiendo.)

Aplicar el CSS

Con estos elementos básicos, es la hora de construir el CSS. Una nota rápida antes de empezar, debido a un fallo en IE glitch, colocaremos la imagen de después sobre la imagen de antes cuando la necesitemos, en lugar de reemplazar una con la otra. El resultado no presenta diferencias visuales si los alineamos con precisión, pero este método evita lo que sería un efecto de parpadeo que no deseamos.

  #skyline {
    width: 400px; height: 200px;
    background: url(test-3.jpg);
    margin: 10px auto; padding: 0;
    position: relative;}
  #skyline li {
    margin: 0; padding: 0; list-style: none;
    position: absolute; top: 0;}
  #skyline li, #skyline a {
    height: 200px; display: block;}

Contraintuitivamente, no estamos asignando la imagen de antes a los enlaces, está aplicada en el código, en <ul>. Verás por qué en un instante.

El resto del CSS en el ejemplo establece las dimensiones del bloque #skyline y los elementos de lista, las posiciones iniciales para los ítems de lista, y elimina los marcadores de la lista.

Dejaremos los enlaces vacíos, como elementos transparentes (si bien con unas dimensiones específicas) para disparar la actividad de los enlaces, y colocarlos utilizando los <li>s. Si quisiéramos colocar los enlaces e ignorar los <li>s, empezaríamos a tener errores en los navegadores más antiguos, de modo que evitémoslo.

Colocar los enlaces

Los <li>s están colocados (posicionados) de forma absoluta, de manera que ¿por qué no están encima de la ventana del navegador? Una propiedad extraña pero útil de los elementos posiconados es que todos los elementos descendientes que contienen basan su posición absoluta no a partir de la ventana del navegador, sino a partir de las esquinas del elemento posicionado antecesor más próximo. El resultado de esto es que, ya que aplicamos position: relative; a #skyline, somos capaces de posicionar de forma absoulta los <li>s a partir de la esquina superior izquierda del propio bloque #skyline.

  #panel1b {left: 0; width: 95px;}
  #panel2b {left: 96px; width: 75px;}
  #panel3b {left: 172px; width: 110px;}
  #panel4b {left: 283px; width: 117px;}

De este modo #panel1 no está posicionado horizontalmente, #panel2b está 96px a la izquierda del borde izquierdo de #skyline, y así sucesivamente. Hemos asignado un valor a los enlaces de display: block; y la misma altura que los <li>s en la lista, de modo que acabarán rellenado todo su <li> contenedor, que es exactamente lo que pretendemos.

En este momento tenemos un mapa de imagen básico con enlaces, pero sin estados :hover . Ver el ejemplo. Es más fácil entender qué ocurre con los bordes remarcados.

Hovers

Antes hubiéramos aplicado Javascript para cambiar el enlace y ofrecer una nueva imagen en el estado de después. En cambio, todos nuestros imágenes de después están en una única imagen, y todo lo que necesitamos es mover cada estado para que se muestre en el enlace adecuado.

Si aplicamos la imagen maestra al estado :hover sin valores adicionales, sólo haremos visible la esquina superior izquierda — no es lo que pretendemos, aunque sí se muestre recortado por el área de los enlaces, que sí es lo que queremos. Necesitamos mover la posición de la imagen de algún modo.

Tenemos valores conocidos de los píxeles; un poco de cálculo nos permitirá desplazar esa imagen de fondo tanto vertical como horizontalmente, de manera que sólo la parte que contiene el estado de después sea visible.

Aquí tenemos exactamente cómo lo haremos:

  #panel1b a:hover {
    background: transparent url(test-3.jpg)
    0 -200px no-repeat;}
  #panel2b a:hover {
    background: transparent url(test-3.jpg)
    -96px -200px no-repeat;}
  #panel3b a:hover {
    background: transparent url(test-3.jpg)
    -172px -200px no-repeat;}
  #panel4b a:hover {
    background: transparent url(test-3.jpg)
    -283px -200px no-repeat;}

¿De dónde salen estos valores de píxeles? Vayamos parte a parte: el primer valor es por supuesto el desplazamiento horizontal (a partir del borde izquierdo), y el segundo es el vertical.

Cada valor vertical es igual; puesto que la imagen maestra tiene 400 píxeles de alto y los estados de después están en la mitad inferior, simplemente dividimos la altura. Cambiar la imagen de fondo completa para que se desplace 200px hacia arriba requiere que apliquemos los valores como un número negativo. Piensa que el borde superior del enlace es el origen, o 0. Para colocar la imagen de fondo 200 px por encima de este punto debe hacerse moviendo el punto de partida -200px.

Del mismo modo, si la esquina izquierda de cada enlace es el valor 0, deberemos desplazar el fondo horizontalmente por un valor igual al ancho de todos los <li>s precedentes a aquel con el que estaremos trabajando. Así el primer enlace no requiere desplazamiento, ya que no hay píxeles antes de su punto de partida horizontal. El segundo enlace requiere un desplazamiento con un valor igula al ancho del primero, el tercero requiere un desplazamiento equivalente a la suma del ancho de los dos primeros enlaces, y el último necesita un desplazamiento equivalente al ancho combinado de los tres precedentes.

Es un poco difícil explicar el proceso, pero jugando con los valores pronto se vé como funcionan los desplazamientos, y una vez te has familiarizado con ello, no es tan difícil de hacer.

Así que aquí está. Efectos de cambio de imagen con una sóla imagen y basado en CSS, degradable a una simple lista no numerada.

Botones

No hay motivo por el cual los enlaces deban tocarse unos a otros, tal como están en nuestro ejemplo anterior. Los mapas de imagen pueden ser convenientes en algunos lugares, pero qué pasa si separamos cada enlace en su propio botón individual? De esta manera podemos añadir bordes y márgenes, dejar que el fondo se vea a través y tratarlos tan individualmente como necesitemos.

Es más, los bloques de construcción ya están en su lugar. Realmente no necesitamos modificar nuestro código de forma muy radical; el principal cambio es crear una nueva imagen de fondo que no tenga continuidad de enlace a enlace como en el ejemplo anterior. Puesto que no podemos depender de <ul> para colocar la imagen de fondo original, en lugar de eso acabaremos aplicándola a todos los <li>s y desplazándola cada vez de la misma manera que lo hacíamos en el ejemplo anterior.

Con una imagen adecuada y algo de espacio entre cada <li>, conseguiremos botones..

Fijáos que en este ejemplo hemos añadido bordes de 1px que, por supuesto, contan para el ancho final de los enlaces. Esto afecta nuestro valor de desplazamiento; lo hemos compensado añadiendo 2px a los desplazamientos donde hace falta.

Formas irregulares

Hasta ahora nos hemos concentrado en formas rectangulares y sin superposición. ¿Qué pasa con mapas de imagen complejos que los programas que recortan imágenes, como Fireworks e ImageReady exportan tan fácilmente? Relájate, también tenemos una solución para ello.

Empezaremos como en el primer ejemplo, aplicando la imagen de fondo a la lista <ul> quitando los marcadores de la lista y especificando anchos, etc. La principal diferencia está en la forma en que posicionamos los <li>s; el objetivo es rodear cada elemento gráfico con una caja que se adapta estrechamente a los bordes..

De nuevo, aprovechando la posibilidad de usar posicionamiento absoluto relativo al borde suprior izquierdo de la lista <ul>, seremos capaces de colocar los enlaces con precisión, exactamente dónde los queremos. Todo lo que queda es preparar los estados de hover.

Vale la pena indicar que en este caso, un juego simple de imágenes para entes y después no fue suficiente. Debido a los objetos superpuestos, depender de sólo un estado mostraría trozos de los objetos vecinos en su estado de después- Así, se mostrarían los fragmentos incluídos dentro de los bordes del enlace. (Lo más fácil es verlo en acción.)

¿Cómo evitarlo? Añadiendo un segundo estado de después, y seleccionando cuidadosamente qué objetos van en cada lugar. La imagen maestra en este caso ha dividido los objetos azul y púrpura en el primer estado de después, y los objetos verde, naranja y amarillo en el segundo estado. Este orden permite que las cajas se muestren alrededor de cada estado de despu`´es sin incluir trozos de los objetos que lo rodean. Y la ilusión es completa.

Beneficios y limitaciones

Un par de reflexiones finales. Nuestro nuevo método de espectros de CSS funciona bien en la mayoría de navegadores modernos. La excepción más notable es Opera 6, que no aplica imagen de fondo a los estados de hover. Por qué, no estamos seguro, pero esto significa que nuestros hovers no funcionan. Los enlaces sí lo hacen, y si han sido etiquetados correctamente, el resultado neto será un mapa de imagen estático pero usable en Opera 6. Se puede perdonar, ya que hace rato que Opera ha dejado atrás esa versión.

Otra preocupación será familiar a cualquiera que haya pasado algo de tiempo con el método de FIR. En el caso (raro) de que el usuario haya optado por no cargar imágenes pero sí tener activado CSS, aparederá un gran vacío en la página donde deberían ir las imágenes. Los enlaces están aún ahí y se pueden pulsar, pero visualmente no aparece nada. A la hora de publicar este artículo, no se ha encontrado una solución a este problema.

Además está el problema del tamaño de los ficheros. La tendencia natural es asumir que una imagen de tamaño doble sólo será algo más pesada que un conjunto de imágenes recortadas, ya que el área total de la imagen apenas será algo mayor que los trozos. Todos los formatos, sin embargo, añaden un poco de peso extra (por eso un GIF en blanco de 1px por 1px ahorra unos 50 bytes), y cuantas más imágenes hay, más rápidamente se añade el sobrepeso. Además, la imagen maestra requiere sólo una tabla de color cuando se utiliza un GIF, mientras que cada pieza recortada exigiría la suya propia. Las pruebas preliminares sugieren que todo esto indica que los espectros de CSS tienen un tamaño de fichero ligeramente inferior, o al menos no superior a las imágenes por separado.

Finalmente, no olvidemos que nuestro código es limpio y claro, con todas las ventajas que supone. Las listas en HTML degradan muy bien, y una técnica de reemplazo de imagen apropiada hará que los textos de las listas sean accesibles a todos los lectores de pantalla. Reemplazar las imágenes del espectro es facilísimo, ya que todas las dimensiones y desplazamientos están controlados en un solo fichero CSS, y todas las imágenes están contenidas en una sola.

Creador del popular css Zen Garden, Dave Shea es un diseñador gráfico que piensa que los CSS están empezando a llevarnos a alguna parte. Dave escribe diariamente en mezzoblue, y ha empezado con su propio estudio Bright Creative.

[ Este artículo ha sido traducido con permiso de A List Apart y su autor.]