Sprites e imágenes embebidas usadas con CSS para la optimización de documentos HTML.
En el presente artículo trataremos:
- La optimización de documentos HTML mediante el uso de sprites
- La obtención de sprites
- La inclusión de sprites mediante CSS
- La obtención de sprites –imágenes en general- codificados en Base64
- La técnica de inclusión de sprites embebidos
¿Qué es un sprite?
Numerosas son las acepciones del término, inicialmente empleado para referirse a bitmaps independientes del cuerpo del escenario, que podrían ser animados sobre él de forma separada –nos referimos a la edición en inglés por ser mucho más amplia y precisa, a nuestro entender-. Para una discusión completa acúdase allí:http://en.wikipedia.org/wiki/Sprite_(computer_graphics)
En nuestro caso –en lo que se refiere a HTML y CSS- es un conjunto de imágenes agrupadas en una única imagen, a cada una de ellas se accede mediante un desplazamiento respecto del borde superior izquierdo, cota (0,0), y sus dimensiones absolutas. Es, por tanto un método de agrupación de imágenes que, posteriormente, pueden ser tratadas de forma independiente.
Sprite utilizado para diversas aplicaciones y logos de Google
Ilustración de un sprite de una animación con CSS –por ejemplo-
Por qué se optimiza el código HTML
Uno de los problemas de retardo más importantes en la carga de documentos desde Internet es el tráfico HTTP y las propias capacidades de los navegadores para gestionarlo. El punto crítico más importante suele ser el fraccionamiento de llamadas, consecuentemente, el número de archivos es determinante.Si se utilizan múltiples imágenes, se realizarán otras tantas llamadas al servidor y una sobrecarga directamente proporcional al acceso a la página, por el contrario, se reducirá sustancialmente esto con el uso de sprites, dado que cada uno de ellos –o uno único- descargará múltiples imágenes con una sola llamada –un único archivo-. Bien es cierto que el peso cuenta, pero en menor cantidad de lo que pesa el tráfico de llamadas en sí, dentro de los límites de la moderación y hablando proporcionalmente.
Fijémonos, por poner un caso, en las figuras que siguen, las tres primeras figuras de una supuesta barra de herramientas, se han agrupado en una única en formato sprite, que utilizaremos en nuestros ejemplos; ahora en la carga de la página ahorraremos dos accesos al servidor al tener que referenciar una única imagen.
Generación de sprites
Usualmente dispondremos de las imágenes por separado y desearemos generar el sprite correspondiente.Deberemos acudir a utilidades que automaticen la tarea y las hay, afortunadamente, abundantes y de calidad que, además de generar el sprite, nos dan información de cómo insertar las imágenes, sus cotas, dimensiones y código para utilizarlas en nuestra CSS.
Algunos de los lugares de Internet que nos proporcionan esas facilidades son:
En las figuras anteriores mostramos las vistas de dos de los lugares, el segundo de ellos –instantsprite.com-, que funciona con Firefox, Chrome y Opera , trabaja de la siguiente forma:
- Se comienza con una subida de las múltiples imágenes que constituirán el sprite
- Seleccionamos el desplazamiento que habrá entre cada una de ellas en el sprite
- El tipo de imagen final –png o gif-
- La orientación de las imágenes en el sprite –horizontal o vertical-
- Creado el sprite se guarda haciendo clic sobre él con el botón derecho del ratón y en el menú emergente seleccionando la opción de guardar imagen
Ejemplo de uso de sprites con CSS
En la figura adjunta se muestra una colección de seis figuras –un sprite- que muestra el estado de tres botones en forma normal y cuando se pasa el botón por encima de ellos –efecto hover-. No son más que las tres figuras inicialmente mostradas más otras tres que hemos construido pasándolas a vídeo inverso, su efecto es suficientemente ilustrativo para nuestro ejemplo. Las hemos expuesto en doble fila, como una opción adicional más y así poder ilustrar también cómo manejar ese tipo de sprites multilínea.
El ejemplo base lo hemos tomado de un editor de textos HTML 5, de tipo Rich-Text Editing, una simple área de edición con el atributo contenteditable, del que hemos hablado ya en nuestros anteriores artículos:
- http://www.desarrolloweb.com/articulos/html5-rich-text-editing.html
- http://www.desarrolloweb.com/articulos/html5-rich-text-editing-II.html
- De fondo de botón utilizamos el sprite, pero acotando el área visible a aquel la parte que deseamos sea visible en cada caso.
- Hay seis casos:
- Los tres botones en estado de reposo de negrilla, itálica y subrayado
- Los tres botones cuando se pasa por encima de ellos –hover-
- Disponemos de seis imágenes que, medidas desde el borde superior izquierdo, deberemos fijar su posición con unos desplazamientos de 0, 31px y 61px –por diseño- y las mismas pero 24px en vertical para las de la segunda línea –también por el propio diseño de la imagen del sprite-
- Nótese que la primera imagen y su correspondiente cuando se pasa sobre ella el ratón tendrán unas cotas (0, 0) y (0, -24)
- Para la segunda (-31, 0) y (-31, -24)
- Para la tercera (-61, 0) y (-61 -24)
- Su alto, en todos los casos es 24px –heigth-
- Obsérvense lo valores negativos de las cotas
- Obsérvese el posicionamiento left y width de cada botón, acorde a a su posición y el ancho que ocuparán (coincidente con el ancho de la imagen dentro del sprite)
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Sprite-1</title>
<style>
#opciones {
position: relative;
}
#opciones li {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
top: 0;
}
#opciones li, #opciones a {
height: 24px;
display: block;
}
#negrilla {
left: 0px;
width: 31px;
background: url('sprite-1.png') 0 0;
}
#negrilla a:hover {
background: url('sprite-1.png') 0 -24px;
}
#italica {
left: 31px;
width: 30px;
background: url('sprite-1.png') -31px 0;
}
#italica a:hover {
background: url('sprite-1.png') -31px -24px;
}
#subrayado {
left: 61px;
width: 30px;
background: url('sprite-1.png') -61px 0;
}
#subrayado a:hover {
background: url('sprite-1.png') -61px -24px;
}
#textBox {
position: absolute;
top: 40px;
width: 600px;
height: 300px;
border: 2px #000000 solid;
padding: 10px;
overflow: scroll;
background-color: yellow;
}
</style>
</head>
<body>
<ul id="opciones">
<li id="negrilla"><a href="#" onclick="document.execCommand('bold',false,'');"></a></li>
<li id="italica"><a href="#" onclick="document.execCommand('italic',false,'');"></a></li>
<li id="subrayado"><a href="#" onclick="document.execCommand('underline',false,'');"></a></li>
</ul>
<section id="textBox" contenteditable="true">
<h1 style="color: red">Título</h1>
<p>Escribir aquí...</p>
</section>
</body>
</html>
El listado que sigue es una simplificación del anterior, en el que hemos agrupado algunos estilos, con la finalidad de hacer más eficiente el HTML resultante y, por ende, la carga y el redibujado más eficiente. Lo ponemos aquí y lo hemos hecho así como mera ilustración de una mejora en el diseño y prestaciones a costa, si acaso de una menor legibilidad. Todo será a criterio del programador. Insistimos en que ambos son estructuralmente idénticos.
Listado 2:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Sprite-1</title>
<style>
#opciones {
position: relative;
}
#opciones li {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
top: 0;
}
#opciones li, #opciones a {
height: 24px;
display: block;
}
#negrilla, #italica, #subrayado, #negrilla a:hover, #italica a:hover, #subrayado a:hover {
background: url('sprite-1.png');
}
#negrilla {
left: 0px;
width: 31px;
background-position: 0 0;
}
#negrilla a:hover {
background-position: 0 -24px;
}
#italica {
left: 31px;
width: 30px;
background-position: -31px 0;
}
#italica a:hover {
background-position: -31px -24px;
}
#subrayado {
left: 61px;
width: 30px;
background-position: -61px 0;
}
#subrayado a:hover {
background-position: -61px -24px;
}
#textBox {
position: absolute;
top: 40px;
width: 600px;
height: 300px;
border: 2px #000000 solid;
padding: 10px;
overflow: scroll;
background-color: yellow;
}
</style>
</head>
<body>
<ul id="opciones">
<li id="negrilla"><a href="#" onclick="document.execCommand('bold',false,'');"></a></li>
<li id="italica"><a href="#" onclick="document.execCommand('italic',false,'');"></a></li>
<li id="subrayado"><a href="#" onclick="document.execCommand('underline',false,'');"></a></li>
</ul>
<section id="textBox" contenteditable="true">
<h1 style="color: red">Título</h1>
<p>Escribir aquí...</p>
</section>
</body>
</html>
Trabajo con imágenes embebidas
Queremos decir con ello el insertar directamente los bytes de la imagen en el archivo que contiene el documento HTML –o en su caso en el archivo CSS-. La gran ventaja obtenida es nuevamente el ahorro de tránsito en la red, dado que no habrá que obtener la o las imágenes de archivos externos. Es un paso más allá en la línea que hemos iniciado con el uso de los sprites. Para obtener el código de las imágenes en el formato estándar para ser embebidas –normalmente se usará el Base64-, acudiremos a utilidades disponibles en Internet, como por ejemplo las Web Coder Tools:http://webcodertools.com/imagetobase64converter
El modo de trabajo es del todo simple:
- Deberemos ir a Image to Base64 converter
- Una vez allí, cargaremos nuestra imagen a convertir
- La imagen será automáticamente convertida y se nos proporcionarán dos modos de insertarla
- Cómo imagen en un documento HTML
- Cómo imagen de fondo en un documento CSS
- Bastará copiar y pegar él o los códigos de las áreas correspondientes en nuestros documentos
Ninguna de las opciones que se nos dan por defecto.
El ejemplo que sigue es exactamente el mismo que el anterior, pero prescindiendo de la imagen externa e incluyéndola como imagen embebida en el documento HTML. Obsérvese, sobre todo, lo indicado de cómo referenciar la imagen embebida y cómo el resto del código permanecerá invariante.
Naturalmente, todo el sistema de acotaciones de los sprites ha de ser realizado previamente sobre la imagen real y el modo de trabajar con imágenes embebidas será habitualmente un último paso del proceso de nuestros desarrollos estándar con las imágenes reales. Es visto de alguna manera, una etapa final de optimización de código.
Listado 3:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Sprite-1</title>
<style>
#opciones {
position: relative;
}
#opciones li {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
top: 0;
}
#opciones li, #opciones a {
height: 24px;
display: block;
}
#negrilla, #italica, #subrayado, #negrilla a:hover, #italica a:hover, #subrayado a:hover {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFsAAAAwCAMAAABJ2/YyAAADAFBMVEX9/f33+fj09fTv8fDv7/Hu8O/r7Ovn6ejm5ujm6Ofj4+Tf4OHe3+Ha2tzX19nU1NXMzMzDw8PBwb+8vLy2uLezs7Oqq6qkpKSenqCbm5yUlJSRkI6Li4uGhoiJiYeGiIeCgoJ/gYCBf4B/f4GAgH5+gH+Af359fX15d3h2d3l0dHRucG9rbGtoaGZjY2NcXFxXWVhVVVVMTExDQ0I8PDwzMzMqKiopJygoKCYlJSMhIR8gHx0dHBsZFxgZGBYYFx
YUExMRDxAPDhESEQ8QDg8LCgsHCQgJBwgGBggIBgcCAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAn8j/UAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFjklEQVRYhZVXgW7iOBBNxCJvZSlGcIElp+ZkQJU3CisI4GKscso2qtL//6GbsRPb
lDarmyTO+L2ZNxMrIiaKBedw2kEIvkJHGHBlCWcmgtt4m2LHlWO5z4DASERfWhwNsUDnA2wErLAioWBgQ9p/YouID/L/DLL8QycfWVP7y5D/2ffNAvCB2oh/
tqKx0xh+Zj7cWXyvHQfevXbYp/B8nFeHfbYt53EQdlOZzkWRp71AHPQdL4+HjEUTvs3Cvrkv9etYsnS/XfiHvtWOSVFOKe25OGS3x4SSaFokjkZt/zg7uaO0qjLixYNsQNiuYCT2wFPnALQ9MXRLL9313T3kTu1ZejzMqYk2tgq042hRLWmnBVds34PYDLsTRahwvNV2tlcSzoxB7R7yLAFsd5zSODARxyYUKclQswz
4QDsC7WqaK7UEn9xpg7FTxcK5Z0m0Vwyqs+3n2gS09yw+KPVA7rORz3RODTX6wBJ8ZhbReNppmwB4B0fjeAwXId/2uqJkr3RCSEw
AicmIj0fWcFapGaaORu
PxGIDRaDM2OKrnmoOzzUwAJMMEfgcJGROCUqQCbXrSB3gXEMGRE28TZIyNx/Ym7BTiYlrow+4kKHXh2Dd5AAcuulZa7U6ynFmejgk
NtfNKH4VPRTMshYOkaZo
VYrlYpJ41fROoRin9TinD8wEmDwjBnVPyYA0jGPbdzWH6wCmOWK811sAFOtYojzbUKBN7S/AemPDz77cMzn8GGLYFFgTAe9IzNPFw0vm
JoF8ZRoh7KFB5ijjUYgZi
NDElEoY8A33GHlmYyhKfCVksZyyB9AQnyU1TlE6oiH6iLMoYXVsHp4kJA7YzzMZIZzATjNo2
bBbUSUyAqQjajxMUskWtblccyySrxHdNXaClE8qZVeweyi8JjhMefXtc9998GGE7sFojsDZHYLChWK8ezX7BXmsA+i3D2qJr0WXb+Kj
BXYYQwu1KBO98sbGENXCfDN
rtX/qwfjSx3GeAG4l2yIbYZpBtW9hDdO/855YPZvNBNv9D38UgKwa6Atb0/XXIcGd3bKjTwO/J21Dtz/punIYYrCz+sN732k3g3WuHSjxaO7hIZ/Nyme1D/ilM1Hu
eF1XjBRzbbKezUrYnsSzDvoPai2kmq/ly9+br36xoU+fZUdZBZ95dTpWu22Mua1cZ19trs4VS6V9l7Vc0yAZELsJcv94AZROJXq
Y9HfbdLOhcVtPpXrdN8yEb6abdpVsFnutGOOm3xURBQJMj/+60m/YNl7BpmjllczopsbUOaTeNMwhbTI+6fXvHyijUCuOZY8EkYp
nC0YagdvNuc9s5TY8lpVtwa0QAF00gLiepDObN+8pzcyqhhFzqLhHMaFuroe+5bGaUXuuO/t2I34FWSQsVatvKb8YF7fbf38cfz55dR
U8gao66hr41DPS5rt9ri4m6rwyzlB50NzHxzaq2PowFxQValrqjIRu+l7U1QFKaKj2hM9C+duhT7e1EZ7K+Me5S4fWk
s8WEax2w0dMVp9fXV41f/B8T9vdBX68Gql9exIsLLVI63ahA+VqvIO5Vv+r6WlXVNufb3a4y1IvVhtpXqAZv/lUpeYHzCgAcUFNrAXdr9UWr8xmCnemr0GA19
hb1f4NirV+MQW600eoCIvX1glqq1r1dNFTgfl53YE+Ddn5FDzJBQ0JnZymVi1DwnkA/6nLG66LQVQjgAMeZX1Rv
kG8YP9dcA3TpMwzmaQ3fNKglEYfK8oyoPONN4iF/Sh997hhryBZSQq9IqJ5x8SfFoxzKIisRNYF4yk4mhyRrWPi
MoQ5Q6lH2etidfEYRpMziKOy700XBrrB87hsXrg8DSf8YEhDMPZ+7NMvJ7hGhcRHV7uPfbQA2m40
Dboy7XUO/SeBmo+H2DwYw2Zb+D7GrXPoWJtj2AAAAAElFTkSuQmCC);
}
#negrilla {
left: 0px;
width: 31px;
background-position: 0 0;
}
#negrilla a:hover {
background-position: 0 -24px;
}
#italica {
left: 31px;
width: 30px;
background-position: -31px 0;
}
#italica a:hover {
background-position: -31px -24px;
}
#subrayado {
left: 61px;
width: 30px;
background-position: -61px 0;
}
#subrayado a:hover {
background-position: -61px -24px;
}
#textBox {
position: absolute;
top: 40px;
width: 600px;
height: 300px;
border: 2px #000000 solid;
padding: 10px;
overflow: scroll;
background-color: yellow;
}
</style>
</head>
<body>
<ul id="opciones">
<li id="negrilla"><a href="#" onclick="document.execCommand('bold',false,'');"></a></li>
<li id="italica"><a href="#" onclick="document.execCommand('italic',false,'');"></a></li>
<li id="subrayado"><a href="#" onclick="document.execCommand('underline',false,'');"></a></li>
</ul>
<section id="textBox" contenteditable="true">
<h1 style="color: red">Título</h1>
<p>Escribir aquí...</p>
</section>
</body>
</html>
Jaime Peña Tresancos
Escritor. Colaborador habitual de revistas de tecnología y experto en nuevas tec...