Cómo crear un precargador de imágenes impresionante
Spanish (Español) translation by Andrijana Mitevska (you can also view the original English article)
¿Con qué frecuencia encuentras que las imágenes en un sitio web se cargan correctamente? ¿del tipo en el que aparece por primera vez un icono de carga y luego la imagen se desvanece una vez cargada? Esta técnica puede mejorar enormemente el rendimiento de tu sitio web. Si aún no estás familiarizado con este método, ¡estás de suerte! Hoy, crearemos un complemento de precargador para tus proyectos. ¿Intrigado? ¡Empecemos!
Paso 1: Configuración de tu espacio de trabajo
Primero, vamos a configurar la carpeta del proyecto para este tutorial. Necesitaremos:
- Nuestro archivo HTML principal
- Carpeta CSS para nuestra hoja de estilo e ícono de carga (en la carpeta 'i')
- Carpeta JS para jQuery y nuestro complemento
- IMÁGENES
Paso 2: el HTML
Empezaremos con el código HTML.
1 |
<DOCTYPE html> |
2 |
<html>
|
3 |
<head>
|
4 |
<meta charset=utf-8" /> |
5 |
<title>Image Preloader</title> |
6 |
|
7 |
<script type="text/javascript" src="js/jquery-1.4.4.min.js"></script> |
8 |
<script type="text/javascript" src="js/jquery.preloader.js"></script> |
9 |
|
10 |
<link rel="stylesheet" href="css/preloader.css" type="text/css" /> |
11 |
|
12 |
</head>
|
13 |
|
14 |
<body>
|
15 |
|
16 |
<div id="container"> |
17 |
<h2>Preloader - Load images with style</h2> |
18 |
|
19 |
<ul id="gallery" class="clearfix"> |
20 |
<li><p><a href="#"><img src="images/1.jpg" /></a></p></li> |
21 |
<li><p><a href="#"><img src="images/2.jpg" /></a></p> </li> |
22 |
<li><p><a href="#"><img src="images/3.jpg" /></a></p> </li> |
23 |
<li><p><a href="#"><img src="images/4.jpg" /></a></p></li> |
24 |
<li><p><a href="#"><img src="images/5.jpg" /></a></p> </li> |
25 |
<li><p><a href="#"><img src="images/6.jpg" /></a></p> </li> |
26 |
<li><p><a href="#"><img src="images/7.jpg" /></a></p> </li> |
27 |
<li><p><a href="#"><img src="images/8.jpg" /></a></p> </li> |
28 |
<li><p><a href="#"><img src="images/9.jpg" /></a></p> </li> |
29 |
</ul>
|
30 |
|
31 |
</div>
|
Nada especial aquí: solo código HTML simple para una galería simple. Hemos importado jQuery, nuestro complemento jquery.preloader.js (actualmente en blanco) y la hoja de estilo de nuestro precargador. Para terminar, agregaremos una lista desordenada, que contendrá elementos de la lista como imágenes envueltas por una etiqueta de anclaje (generalmente se hace en un sitio web para abrir una caja de luz o vincular a un sitio).
Ten en cuenta que la etiqueta
padicional que envuelve cada ancla se utiliza con el fin de dar estilo a la imagen; no se requieren explícitamente.
Paso 3: el CSS
Ahora, crearemos una hoja de estilo preloader.css en la carpeta css y, dentro de ella, crearemos una subcarpeta i en la que guardaremos nuestro icono de precargador. Preloaders.net tiene una buena colección de iconos de carga entre los que puedes elegir. Agrega el siguiente código a tu hoja de estilo:
1 |
* { margin:0; padding:0; } |
2 |
|
3 |
body { background:url(i/bg.jpg); } |
4 |
|
5 |
#container { width:960px; margin:0px auto; } |
6 |
|
7 |
h2 { font-weight:100; text-shadow:#ffffff 1px 1px 0px; text-align:center; padding:20px; font-size:32px; color:#555555; border-bottom:1px dashed #ccc; margin-bottom:30px; font-family: Georgia, "Times New Roman", Times, serif ; } |
Primero, hemos creado un contenedor centrado de 960px y hemos agregado un fondo a la página. Además, hemos agregado algunos estilos básicos al título (etiqueta h2).
Diseñando la Galería
A continuación, aplicaremos estilo a la galería y, mientras lo hacemos, agregaremos algunas bondades de CSS3.
1 |
#gallery { |
2 |
list-style:none; |
3 |
}
|
4 |
|
5 |
#gallery li { |
6 |
background:#e8e8e8; |
7 |
float:left; |
8 |
display:block; |
9 |
border:1px solid #d7d7d7; |
10 |
-moz-border-radius:4px; |
11 |
-webkit-border-radius:4px; |
12 |
border-radius:4px; |
13 |
-webkit-box-shadow:1px 1px 6px #ddd; |
14 |
-moz-box-shadow:1px 1px 6px #ddd; |
15 |
box-shadow:1px 1px 6px #ddd; |
16 |
margin:15px 56px; |
17 |
padding:0; |
18 |
}
|
19 |
|
20 |
#gallery li p { |
21 |
border:1px solid #fff; |
22 |
-moz-border-radius:4px; |
23 |
-webkit-border-radius:4px; |
24 |
border-radius:4px; |
25 |
margin:0; |
26 |
padding:7px; |
27 |
}
|
28 |
|
29 |
#gallery li a { |
30 |
display:block; |
31 |
color:#fff; |
32 |
text-decoration:none; |
33 |
padding:0; |
34 |
}
|
35 |
|
36 |
#gallery img { |
37 |
width:315px; |
38 |
height:210px; |
39 |
margin:0; |
40 |
padding:0; |
41 |
}
|
En este punto, nuestra galería debería verse así:


Configuración de la clase de precargador
Creemos una clase de precargador que se encargará de mostrar el icono de carga, mientras se cargan las imágenes.
1 |
.preloader { |
2 |
background:url(i/89.gif) center center no-repeat #ffffff; |
3 |
display:inline-block; |
4 |
}
|
La propiedad de visualización del elemento de precargador debe establecerse en block o inline block; de lo contrario, el icono de carga no se mostrará.
Paso 4: escribir el complemento
Comencemos por crear la estructura y las opciones del complemento.
Permitir opciones de personalización hace que un complemento sea mucho más flexible para el usuario.
Partimos de la estructura base:
1 |
$.fn.preloader = function(options){
|
2 |
|
3 |
var defaults = {
|
4 |
delay:200, |
5 |
preload_parent:"a", |
6 |
check_timer:300, |
7 |
ondone:function(){ },
|
8 |
oneachload:function(image){ },
|
9 |
fadein:500 |
10 |
}; |
11 |
|
12 |
// variables declaration and precaching images and parent container |
13 |
var options = $.extend(defaults, options), |
14 |
|
15 |
} |
Nuestras Opciones
- demora: retraso sucesivo entre el desvanecimiento de las imágenes
- precargar_padre: agrega la clase de precarga al padre mencionado. Si no se encuentra, la imagen se envuelve dentro de una etiqueta de anclaje
- hecho: devolución de llamada que se ejecutará cuando se carguen todas las imágenes
- oneachload: se llama cuando cada imagen se carga con una imagen como parámetro
- fadein - Desvanecimiento en la duración de la animación
Paso 5: Variables
A continuación, declaramos y precacheamos las variables que usaremos en el resto del complemento.
1 |
var defaults = {
|
2 |
delay:200, |
3 |
preload_parent:"a", |
4 |
check_timer:300, |
5 |
ondone:function(){ },
|
6 |
oneachload:function(image){ },
|
7 |
fadein:500 |
8 |
}; |
9 |
|
10 |
// variables declaration and precaching images and parent container |
11 |
var options = $.extend(defaults, options), |
12 |
root = $(this), |
13 |
images = root.find("img").css( {"visibility":"hidden", opacity:0} ),
|
14 |
timer, |
15 |
counter = 0, |
16 |
i=0 , |
17 |
checkFlag = [], |
18 |
delaySum = options.delay; |
Primero, precacheamos el elemento raíz (siempre una buena práctica), luego buscamos las imágenes (también ocultándolas), y finalmente declaramos las variables que se explicarán con mayor detalle a medida que las contrarrestamos.
Hay dos cosas que vale la pena señalar aquí: inicialmente podrías pensar que la solución más fácil es ocultar las imágenes y luego desvanecerlas, en lugar de saltar a través de todo este código. Sin embargo, el problema es que, si ocultamos las imágenes, el navegador marca el espacio que solían ocupar como vacío y, por lo tanto, el diseño, en sí mismo, se estropea cuando finalmente se desvanecen. Está bien, bueno, ¿y si usamos opacidad para "mostrar" y "ocultar" las imágenes? Sin embargo, esa es una mejor práctica, a algunas versiones de IE no les gusta este método.
Paso 6: agregar la clase de precargador
Ahora iteraremos sobre cada elemento de la imagen y verificaremos si su padre es el mencionado en la opción. Si es así, le agregamos nuestra clase de precargador; de lo contrario, envolvemos la imagen dentro de una etiqueta de anclaje con una clase de precargador.
1 |
images.each(function(){
|
2 |
var $this = $(this); |
3 |
if( $this.parent( options.preload_parent ).length==0 ) {
|
4 |
$this.wrap("<a class='preloader' />");
|
5 |
} else {
|
6 |
$this.parent().addClass("preloader");
|
7 |
} |
8 |
|
9 |
checkFlag[i++] = false; |
10 |
}); |
11 |
images = $.makeArray(images); |
Aquí, estamos usando un checkFlag de matriz y estamos configurando el valor del elemento de cada matriz en falso. Su uso se irá aclarando a medida que avance.
Paso 7: Reunirlo todo
Ahora implementaremos lo que realmente sucede detrás de escena. Hay una propiedad booleana, llamada completa, asociada con el objeto de imagen. Cuando la imagen se ha cargado por completo, este valor booleano se establece en verdadero. Por lo tanto, seguimos verificando esta propiedad para cada imagen y, si de hecho se establece en verdadero, atenuamos esa imagen.
Podemos usar la función setInterval para determinar continuamente si las imágenes se han cargado o no. Aquí es donde entra en juego la opción check_timer: se asigna directamente a la frecuencia de nuestro temporizador.
Una imagen también tiene un evento de carga asociado; probablemente se estés preguntando por qué no lo estamos usando. La razón es que algunos navegadores no funcionan bien con ese evento; como tal, lo estamos saltando. Necesitamos una solución que funcione a la perfección en todos los navegadores. Empezamos con:
1 |
init = function(){
|
2 |
timer = setInterval(function(){}
|
3 |
},options.check_timer); |
temporizador es la variable que hará referencia al temporizador. Esto es necesario para detener finalmente el temporizador. Esta función se declara junto con todas las variables.
Comprobación de cada imagen
Iremos a través de la matriz y comprobaremos la propiedad completa de cada imagen para determinar si ha terminado de descargarse. Si se ha descargado, lo configuraremos como visible y se desvanecerá lentamente. Cuando la animación ha terminado, eliminamos la clase de precargador de su padre.
1 |
for(i=0; i<images.length; i++) {
|
2 |
if(images[i].complete == true) {
|
3 |
$(images[i]).css("visibility","visible")
|
4 |
.delay(delaySum) |
5 |
.animate({opacity:1}, options.fadein, function(){
|
6 |
$(this) |
7 |
.parent() |
8 |
.removeClass("preloader");
|
9 |
}); |
10 |
} |
11 |
} |
Aquí hay un pequeño problema: el temporizador continuará verificando, incluso después de que se hayan cargado todas las imágenes. Para contrarrestar esto, agregaremos una variable de contador y la incrementaremos después de que se haya cargado cada imagen. De esta manera, podemos verificar si la variable de contador es igual al tamaño de la matriz de imágenes. Si ese es el caso, paramos.
1 |
timer = setInterval(function(){
|
2 |
if(counter>=checkFlag.length) {
|
3 |
clearInterval(timer); |
4 |
options.ondone(); |
5 |
return; |
6 |
} |
7 |
|
8 |
for( i=0; i<images.length; i++) {
|
9 |
if(images[i].complete==true) {
|
10 |
$(images[i]) |
11 |
.css("visibility","visible")
|
12 |
.delay(delaySum) |
13 |
.animate({opacity:1}, options.fadein, function(){
|
14 |
$(this) |
15 |
.parent() |
16 |
.removeClass("preloader");
|
17 |
}); |
18 |
|
19 |
counter++; |
20 |
} |
21 |
} |
22 |
|
23 |
},options.check_timer) |
Sin embargo, ahora hay otro pequeño problema. Nuestro temporizador puede detenerse antes de lo esperado; si se ha cargado una imagen, su propiedad completa se ha establecido en verdadero y, por lo tanto, el contador aumenta en 1. Ahora, cuando el bucle se ejecuta la próxima vez, la imagen ya está cargada, la propiedad completa se establece en verdadero y, por lo tanto, ¡el ciclo se ejecutará dos veces! Para superar este problema, usamos la matriz checkFlag. Cuando se carga una imagen, estableceremos checkFlag en verdadero y estableceremos la condición para que el contador se incremente solo con la condición de que el valor de checkFlag sea falso. Por lo tanto, el contador se incrementa solo una vez: cuando se carga una imagen por primera vez.
1 |
timer = setInterval(function () {
|
2 |
|
3 |
if (counter & gt; = checkFlag.length) {
|
4 |
clearInterval(timer); |
5 |
options.ondone(); |
6 |
return; |
7 |
} |
8 |
|
9 |
for (i = 0; i & lt; images.length; i++) {
|
10 |
if (images[i].complete == true) {
|
11 |
if (checkFlag[i] == false) {
|
12 |
checkFlag[i] = true; |
13 |
options.oneachload(images[i]); |
14 |
counter++; |
15 |
|
16 |
delaySum = delaySum + options.delay; |
17 |
} |
18 |
|
19 |
$(images[i]).css("visibility", "visible").delay(delaySum).animate({
|
20 |
opacity: 1 |
21 |
}, options.fadein, function () {
|
22 |
$(this).parent().removeClass("preloader");
|
23 |
}); |
24 |
} |
25 |
} |
26 |
|
27 |
}, options.check_timer); |
Ten en cuenta que llamamos a la función ondone cuando la bandera del contador es mayor que la longitud de la matriz, es decir, cuando se cargan todas las imágenes. Cuando se incrementa el contador, se llama a oneachload con la imagen actual pasada como parámetro.
Paso 8: La parte fácil
Finalmente, en este paso, llamamos init (); función al final del complemento.
1 |
init(); // called at the last line of plugin |
Eso es todo; Hemos creado un complemento de precarga completamente funcional y su tamaño es inferior a 2 kb. Aún así, queda un problema: la imagen del icono de carga se carga aleatoriamente. No queremos eso. En la siguiente sección nos ocuparemos de eso.
Paso 9: hacer un esfuerzo adicional
Para solucionar el problema mencionado anteriormente, primero cargaremos el ícono y luego llamaremos a la función init. Pero el icono de carga es una imagen de fondo, por lo que lo inyectamos como una imagen en la página, mientras lo mantenemos oculto. Cuando se carga, llamamos a la función init. Básicamente, estamos precargando el ícono en sí.
1 |
var icon = jQuery("<img />", {
|
2 |
|
3 |
id: 'loadingicon', |
4 |
src: 'css/i/89.gif' |
5 |
|
6 |
}).hide().appendTo("body");
|
7 |
|
8 |
timer = setInterval(function () {
|
9 |
|
10 |
if (icon[0].complete == true) {
|
11 |
clearInterval(timer); |
12 |
init(); |
13 |
icon.remove(); |
14 |
return; |
15 |
} |
16 |
|
17 |
}, 100); |
Primero creamos un objeto de imagen con un id de loadingicon y una fuente que apunta a la ruta del icono de carga. Luego, le agregamos el cuerpo y lo ocultamos inicialmente. Por último, configuramos el intervalo para comprobar si el icono se ha cargado o no. Si es así, matamos el temporizador y comenzamos a precargar las imágenes. ¡No olvida eliminar ese icono también!
Conclusión
Con ese último paso, ¡hemos terminado! Esta funcionalidad funciona en todos los navegadores, tal como se esperaba, y se degrada con elegancia. Solo asegúrate de establecer la propiedad de visualización del elemento de precargador en block o inline-block. Ahora está listo para ser utilizado en tus proyectos. ¡Gracias por leer!



