Animación en JavaScript
- Artículo anterior—Manejando eventos en JavaScript
- Siguiente artículo—Degradación elegante frente a Mejora progresiva
- Tabla de contenidos
Introducción
En este artículo, echaremos un vistazo al arte de crear animaciones utilizando JavaScript — las animaciones se suelen utilizar para añadir experiencia de usuario, para la gente que utiliza navegadores que pueden soportarlo. Los usos más comunes son expansiones y contracciones suaves de paneles, barras de progresos, y efectos visuales en formularios.
Como cualquiera que haya visto una película sabe, la animación se hace actualmente mediante una gran cantidad de pequeños pasos, que hacen que parezca que algo se está moviendo. La animación es una técnica poderosa; es muy buena llamando la atención. La pega es que llama la atención tanto si es lo que queremos como si no. Los efectos animados pueden hacer lucir mejor una página web, con una mejor experiencia de usuario, pero es como la salsa de chile: no hay que pasarse añadiendo.
El contenido del artículo es el siguiente:
- Un ejemplo bastante simple: yellow fade technique
- Animación con librerías de JavaScript
- Un ejemplo más complejo: moviendo y cambiando el tamaño
- Transiciones CSS
- Resúmen
- Ejercicios
Un ejemplo bastante simple: yellow fade technique
Un uso bastante común de la animación es la Yellow fade technique, donde, a un área de la página que ha cambiado, se le pone un color de fondo amarillo, y poco a poco vuelve a convertirse al color de fondo original. Es una forma bonita y no invasiva de resaltar que algo ha cambiado (por ejemplo, hay nuevo contenido, o hay mensajes de feedback) sin molestar lo que el usuario está haciendo. Se puede echar un vistazo a un ejemplo para ver cómo funciona.
El funcionamiento detrás de esta técnica es que se pone el color de fondo de un elemento a amarillo, y
entonces, en una serie de pasos, vuelve a ser el que tenía originalmente. Así que si el color de fondo original
era rojo, entonces el color se pone a amarillo, luego a naranja-amarillo, luego naranja, luego rojo-naranja,
y finalmente rojo. El número de pasos que se dan dicta cómo cambian los colores, y el tiempo entre pasos dicta
cuanto tiempo se tarda en cambiar el color totalmente. En los cambios de colores, podemos usar una ventaja de
CSS: un color puede definirse tanto como un triplete de números, ó una cadena hexadecimal. Así, rojo
#FF0000
puede especificarse como rgb(255,0,0)
. Cambiar del amarillo al rojo se puede
hacer en 5 pasos, que es ir del rgb(255,255,0)
(amarillo) al rgb(255,0,0)
:
rgb(255,255,0)
rgb(255,192,0)
rgb(255,128,0)
rgb(255,64,0)
rgb(255,0,0)
Ponemos el color de fondo del elemento a rgb(255,255,0)
, después de un periodo de tiempo
(digamos 100 milisegundos), cambiamos ese color de fondo a rgb(255,192,0)
, y tras otros 100
milisegundos a rgb(255,128,0)
, y así:
Color | Tiempo |
---|---|
rgb(255,255,0) | 0 |
rgb(255,192,0) | 100ms |
rgb(255,128,0) | 200ms |
rgb(255,64,0) | 300ms |
rgb(255,0,0) | 400ms |
El proceso completo dura 400ms (por debajo de medio segundo), y hace un cambio suave del amarillo al rojo. Convenientemente, aquí solo estamos cambiando una parte del color (el canal de verde; los tres canales del color rgb son el rojo, el verde y el azul), pero cambiar más de un canal a la vez es perfectamente posible. En este ejemplo, estamos cambiando el canal de verde de 255 a 0 en cuatro pasos, lo que significa que se cambia en 64 en cada paso.
Lanzar una acción después de un cierto periodo de tiempo se hace en JavaScript por medio de las funciones
setTimeout
y setInterval
. La función setTimeout
ejecuta nuestra acción
después de un cierto retardo de tiempo; setInterval
ejecuta nuestra acción una y otra vez, con
cada ejecución separada por un intervalo de tiempo; esto es ideal para animación. En esencia, lo que tenemos
que hacer para conseguir el cambio de fondo, es definir que tenemos que hacer en cada paso, e invocar a la
función setInterval
para que nos invoque en cada paso. La función setInterval
tiene
dos parámetros, la función a llamar para ejecutar nuestra acción, y el intervalo de tiempo en milisegundos.
Obviamente, quizás no queramos cambiar siempre del amarillo al rojo, así que nuestra función tendría que
ser más genérica. Si conocemos los colores de inicio y fin, y el número de pasos, entonces falta utilizar
las matemáticas para saber cuanto hay que cambiar cada color en cada paso. Si definimos un array
startcolour
como una lista de tres números ([255,255,0]
) y endcolour
como una lista similar ([255,0,0]
), entonces la cantidad en la que tenemos que variar cada
color en cada paso es:
var red_change = (startcolour[0] - endcolour[0]) / steps;
var green_change = (startcolour[1] - endcolour[1]) / steps;
var blue_change = (startcolour[2] - endcolour[2]) / steps;
Utilizamos setInterval
para cambiar el color de fondo de un elemento en varios pasos:
var currentcolour = [255,255,0];
var timer = setInterval(function(){
currentcolour[0] = parseInt(currentcolour[0] - red_change);
currentcolour[1] = parseInt(currentcolour[1] - green_change);
currentcolour[2] = parseInt(currentcolour[2] - blue_change);
element.style.backgroundColor = 'rgb(' + currentcolour.toString() + ')';
}, 50);
En cada paso, tenemos currentcolour
y cambiamos el color rojo en la cantidad
red_change
, el color verde en la cantidad green_change
, y el color azul en la cantidad
blue_change
. Entonces, establecemos el color de fondo del elemento al nuevo color:
[255,255,0].toString()
es "255,255,0", así que para obtener el color rgb(255,255,0)
utilizamos toString()
para crear rgb(255,255,0)
y utilizarlo como el color de fondo
del elemento.
No obstante, setInterval
llamará a nuestra función indefinidamente, no parará cuando el color
de fondo deseado se haya alcanzado. Para parar un intervalo, hay que utilizar clearInterval()
;
el siguiente código cuenta el número de veces que la acción se ha llamado, y borra el intervalo después del
número de pasos correctos:
var currentcolour = startcolour;
var stepcount = 0;
var timer = setInterval(function(){
currentcolour[0] = parseInt(currentcolour[0] - red_change);
currentcolour[1] = parseInt(currentcolour[1] - green_change);
currentcolour[2] = parseInt(currentcolour[2] - blue_change);
element.style.backgroundColor = 'rgb(' + currentcolour.toString() + ')';
stepcount += 1;
if (stepcount >= steps) {
element.style.backgroundColor = 'rgb(' + endcolour.toString() + ')';
clearInterval(timer);
}
}, 50);
Y así es como se hace una animación: un paso en cada momento de tiempo.
¿Cómo conseguir que startcolour
y endcolour
se inicializen? Una forma fácil de hacerlo
es envolver el código de más arriba en una función fade
:
fade: function(element, startcolour, endcolour, time_elapsed) {
...code from above...
}
y podemos activar el cambio de color de fondo de un elemento con una función como esta:
fade(document.getElementById("yft"), [255,255,60], [0,0,255], 750);
o una "atenuación a rojo", que pone el elemento a rojo y luego lo atenúa a azul (el color de fondo del elemento), como:
fade(document.getElementById("yft"), [255,0,0], [0,0,255], 750);
Este ejemplo cambia el color de fondo, pero se podría cambiar cualquier cosa: el color del primer plano (para efectos sicodélicos de texto), opacidad (para ocultar o mostrar cosas), posición (para mover un elemento en la página), altura y anchura (para hacer crecer un elemento, o reducirlo a la nada antes de que desaparezca).
Animación con librerías de JavaScript
La animación es un efecto muy usado, así que la mayoría de las librerías JavaScript tienen alguna forma de soporte, incluyendo animaciones preconstruidas para los efectos más comunes. Por ejemplo, jQuery tiene un soporte incorporado para hacer que un elemento se vuelva transparente:
$("#myelement").fadeOut();
y una función animate()
para hacer código propio más complicado:
$("#block").animate({
width: "70%",
}, 1500 );
Esto es muy intuitivo - coge el elemento y cambia el atributo CSS width
, en 1500 milisegundos,
desde el valor que tuviera, al 70% - la función animate
está documentada aquí.
El framework Scriptaculous de Prototype ofrece facilidades del estilo, como
Effect.Fade('id_of_element')
, y otras muchas. La librería Yahoo UI también ofrece efectos similares:
new Y.Anim({ node: '#demo', to: { width: 70%, }}).run();
Si estamos utilizando una librería JavaScript en nuestro código, ya deberíamos saber que nos ofrecen formas
más sencillas de animación que manejar esas animaciones por nuestra cuenta, con setInterval
.
No obstante, es muy importante entender qué hay bajo la cubierta - esto hará que nuestros scripts mejoren a largo
plazo. Esta es la razón por la que empezar por un ejemplo con los principios básicos, antes de entrar con
las librerías.
Se pueden encontrar más sobre cómo usar las diferentes librerías JavaScript en dev.opera.com, Introduction to JavaScript toolkits.
Un ejemplo más complejo: moviendo y cambiando el tamaño
Yellow Fade Technique sirve para demostrar las animaciones, pero es un poco, bueno, aburrida. Cuano la mayoría de la gente piensa en animación, piensa en movimiento. El Coyote habría sido menos gracioso si todo lo que él hubiera hecho hubiese sido cambiar de color.
Un buen truco para alertar al usuario de que algo está ocurriendo sin interrumpir su actividad son los
mensajes no modales. En vez de mostrar un dialogo de alert()
, que implica que usuario debe
pinchar sobre el OK para poder continuar, simplemente ponemos el mensaje en un div flotante en la página, que,
sin molestar, puede permanecer hasta que el usuario se de cuenta. Otra cosa interesante que podríamos hacer es
permitir al usuario volver a ver el mensaje que ya había visto. Así, podemos implementar un mensaje flotante
que, cuando se le pinche, se mueva a una esquina de la ventana, y que se le pueda pinchar para tenerlo de vuelta.
Podemos ver una breve demo del "zooming message" para tener una idea.
Si estamos haciendo algún trabajo serio de animación, ó cualquier trabajo serio en JavaScript, merecerá más
la pena utilizar una librería JavaScript. Esto nos permitirá poder dar la experiencia de usuario que deseamos
sin tener que preocuparnos por las matemáticas necesarias para hacer funcionar las animaciones. (Sabemos, no
obstante, cómo utilizar las matemáticas y cómo usar setInterval
, habiendo leido el primer
ejemplo más arriba, pero ahorraremos tiempo y neuronas permitiendo que alguien haga el trabajo duro por
nosotros.)
La demo anterior utiliza la librería jQuery para hacer el trabajo, pero como se ha mencionado antes, la mayoría de librerías provee conceptos similares para animación; por tanto deberíamos ser capaces de reimplementar nuestro trabajo utilizando la librería que deseemos. En esencia, lo que tenemos que hacer es lo siguiente:
- Mostrar un mensaje flotante centrado en la pantalla
- Cuando se pinche sobre él:
- Mover su posición horizontal lo más a la derecha
- Mover su posición vertical hacia arriba
- Cambiar su anchura a 20px de ancho
- Cambiar su altura a 20px de alto
- Cambiar su opacidad a 20% para que sea bastante transparente
- Cuando se pinche sobre esta "mini" version del mensaje, se trae de nuevo al centro de la pantalla (por ejemplo, lo contrario de lo que hicimos al encogerlo)
y así, mientras el usuario consigue una imagen clara de lo que ha ocurrido con su mensaje, la transición desde el mensaje hacia el mini-mensaje debería ser animada (para que pueda ver que su mensaje ha encogido hacia la esquina de la ventana).
Hacer esta animación con jQuery es sencillo: utilizamos la función .animate
y especificamos que
queremos como resultado de la animación (y cuanto va a llevar el conseguirlo):
$(ourObject).animate({
width: "20px", height: "20px", top: "20px",
right: "20px", marginRight: "0px", opacity: "0.2"
}, 300);
Esto cogerá ourObject
y, en unos 300 ms, cambiará su anchura y altura a 20px, su tope y posición
derecha a 20px, su propiedad de estilo margin-right
a 0px, y su opacidad (en los navegadores que lo
soporten) al 20%. Después, para hacer que la animación funcione cuando se pinche en el mensaje,
falta programar algo en el estilo jQuery:
$(ourObject.click, function(){
$(this).animate({
width: "20px", height: "20px", top: "20px",
right: "20px", marginRight: "0px", opacity: "0.2"
}, 300)
});
Restaurar el mensaje cuando se pinche sobre él requiere otra llamada a .animate()
:
$(ourObject).animate({
width: "400px", height: "75px", top: "50px",
right: "50%", marginRight: "-200px", opacity: "0.9"
}, 300);
y con una poca de lógica para saber cuando el mensaje se está mostrando en grande o en pequeño (para saber que animación debe ejecutarse), y algo de CSS para definir el estilo inicial del mensaje (grande, verde, centrado horizontalmente), eso es todo lo que necesitamos. Unas 30 lineas de script. ¡Esto es por lo que utilizar librerías es una muy buena idea!
Transiciones CSS
Finalmente, algunas animaciones (no todas) puede hacerse in utilizar JavaScript para nada!!. Safari y otros navegadores basados en Webkit, y Firefox 3.1 pueden hacer transiciones de un valor CSS a otro sin utilizar JavaScript. El código:
div { opacity: 1; -webkit-transition: opacity 1s linear; }
div:hover { opacity: 0; }
hará que el div
se haga transparente en un segundo, en navegador que lo soporte, cuando se
pasa el ratón por encima. Estas transiciones CSS son nuevas, no obstante, no están totamente soportadas salvo
en las versiones más modernas, asi que si queremos que nuestra animación funcione para la mayoría de nuestro
público entonces necesitaremos utilizar scripts para ello.
Resúmen
Esto concluye un vistazo a la funcionalidad de animar páginas web utilizando JavaScript - hemos visto
algunos ejemplos creados con los principios básicos utilizando las funciones setTimeout
y
setInterval
, y luego hemos echado un vistazo a cómo usar librerías JavaScript para crear animaciones
más deprisa.
Ejercicios
- ¿Cúal es la diferencia entre
setTimeout
ysetInterval
? - Si
setInterval
no existe, ¿cómo podríamos emularla? - ¿Cómo podríamos hacer que un elemento pasase del visible total al invisible total en 20 pasos con un intervalo de 1.5 segundos?
- ¿Cómo podríamos hacer que un elemento pasase del visible total al invisible total y luego volverlo visible de nuevo en 20 pasos con un intervalo de 1.5 segundos?
- Artículo anterior—Manejando eventos en JavaScript
- Siguiente artículo—Degradación elegante frente a Mejora progresiva
- Tabla de contenidos
Sobre el autor
Stuart Langridge es posiblemente la única persona en el mundo en tener un BSc en Informática y Filosofía. Cuando él no esta trasteando con ordenadores, él es un hacker de JavaScript, Django y Python en GCap Media, autor de DHTML Utopia en SitePoint, y un bebedor de cervezas decentes. Además, es una cuarta parte del equipo en LugRadio, un programa de radio de estreno mundial sobre temas de software "Free and Open Source". Sus divagaciones sobre la web, scripts, software open source, y cualesquiera otras muchas cosas, se pueden encontrar en kryogenix.org; Stuart puede ser encontrado fuera buscando en el área de fumadores.
This article is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported license.
Comments
The forum archive of this article is still available on My Opera.