Si bien el otro día os hablaba de unas animaciones caseras en javascript que había creado, con en inconveniente de que eran muy lentas (pero mucho), ahora vengo a publicar una versión mucho mejor, ya que no carga casi nada al navegador y, además, la calidad se puede modificar cambiando sólo una cifra.

Bueno, iré paso a paso. Empezaremos por las funciones de medida. Son dos funciones para hallar el ancho y el alto (cuando está, por ejemplo, en “auto”). No tienen demasiada chicha.


/*********************************************************
* FUNCIONES DE MEDIDAS
*/
function alturaAuto(elem){
var id=document.getElementById(elem);
var alturaTotal=id.offsetHeight;
//Padding Top
var paddingTop=parseInt(window.getComputedStyle(id).getPropertyValue("padding-top"));
//paddingBottom
var paddingBottom=parseInt(window.getComputedStyle(id).getPropertyValue("padding-bottom"));;
//borderTop
var borderTop=parseInt(window.getComputedStyle(id).getPropertyValue("border-top"));
//borderBottom
var borderBottom=parseInt(window.getComputedStyle(id).getPropertyValue("border-bottom"));;
var altura=alturaTotal-paddingTop-paddingBottom-borderTop-borderBottom;
return altura;
}
function anchuraAuto(elem){
var id=document.getElementById(elem);
var anchuratotal=id.offsetWidth;
//paddingLeft
var paddingLeft=parseInt(window.getComputedStyle(id).getPropertyValue("padding-left"));
//paddingRight
var paddingRight=parseInt(window.getComputedStyle(id).getPropertyValue("padding-right"));;
//borderLeft
var borderLeft=parseInt(window.getComputedStyle(id).getPropertyValue("border-left"));
//borderRight
var borderRight=parseInt(window.getComputedStyle(id).getPropertyValue("border-right"));;
var anchura=anchuraTotal-paddingLeft-paddingRight-borderLeft-borderRight;
return anchura;
}

Ahora llega lo interesante: la función para animar. La calidad se puede cambiar aumentando o disminuyendo la variable fps. He incluido la opción de callback,para usarla más abajo. Tened en cue


/*********************************************************
* Animaciones
*/
/*===================================================
* Kit completo de animaciones (faltan:color,margin,padding y demás propiedades mixtas);
*/
function animar(elem,prop,valfinal,tiempo,callback){//elemento, propiedead para animar, valor final, tiempo que se va a tardar (por defecto 400) y función de callback
var id=document.getElementById(elem);
//Frames por segundo. Con 45 va perfecto, pero con 34 también va bien
var fps=45;

if(!tiempo){tiempo=400}//tiempo por defecto
//Segundos
var secs=tiempo/1000;

//Veces que se repetirá la función
var veces=fps*secs;

//valor inicial
var valinicial=parseFloat(window.getComputedStyle(id).getPropertyValue(prop));

if ((prop=="top"||prop=="bottom"||prop=="left"||prop=="right")&&window.getComputedStyle(id).getPropertyValue(prop)=="auto"){valinicial=0;}//Ponemos el valor a cero si se posiciona automáticamente

//Para evitar top y bottom a la vez y left y right a la vez
if(prop=="top"){id.style.bottom="auto"}else if(prop=="bottom"){id.style.top="auto"} else if(prop=="left"){id.style.right="auto"}else if(prop=="right"){id.style.left="auto"}

//si altura y anchura son auto, calculamos
if(prop=="height"&&window.getComputedStyle(id).getPropertyValue(prop)=="auto"){valinicial=alturaAuto(elem)}
if(prop=="width"&&window.getComputedStyle(id).getPropertyValue(prop)=="auto"){valinicial=anchuraAuto(elem)}

//Asignamos ese valor (para facilitar después las cosas)
if(prop=="opacity"||prop=="z-index"||prop=="zoom"){
id.style[prop]=valinicial;
}else{
id.style[prop]=valinicial+'px';
}

//Cambio (valor absoluto)
var cambio=valfinal-valinicial;
if(cambio<0){cambio=-cambio}

//Pixels por vez (lo que se moverá cada vez que llamemos a la función)
var ppv=cambio/veces;
if(prop!="opacity"){
if(ppv<1){ppv=1}
}

//El tiempo tras el que se llamará la función vez tras vez

var tpv=tiempo/veces;
if(veces<1){veces=1}

//Posición para que se vea el cambio
var position=window.getComputedStyle(id).getPropertyValue("position");
if(position=="static"){id.style.position="relative"}

//Llamamos a la función para animar
animar2(elem,prop,valinicial,valfinal,tpv,ppv,callback);
}

function animar2(elem,prop,valinicial,valfinal,tpv,ppv,callback){//guardamos el valor inicial para usarlo como argumento en el callback
var id=document.getElementById(elem);

//Animamos
//Lo de "ppv" es porque hay un margen donde puede no ser exacto.
//Los condicionales son para animar sea cual sea el sentido
if (ppv+parseFloat(id.style[prop])<valfinal){
if(prop=="opacity"||prop=="z-index"||prop=="zoom"){
id.style[prop]=parseFloat(id.style[prop])+ppv;
}else{
id.style[prop]=parseFloat(id.style[prop])+ppv+'px';
}
//Llamamos a la función. Usaremos "Timeout" para evitar colapsar funciones
Timeout=setTimeout("animar2('"+elem+"','"+prop+"',"+valinicial+","+valfinal+","+tpv+","+ppv+","+callback+")",tpv);
//Lo de antes pero en otro sentido
}else if(parseFloat(id.style[prop])-pp>>valfinal){
if(prop=="opacity"||prop=="z-index"||prop=="zoom"){
id.style[prop]=parseFloat(id.style[prop])-ppv;
}else{
id.style[prop]=parseFloat(id.style[prop])-ppv+'px';
}
Timeout=setTimeout("animar2('"+elem+"','"+prop+"',"+valinicial+","+valfinal+","+tpv+","+ppv+","+callback+")",tpv);
//Si se ha aproximado lo suficiente
}else{
//lo ponemos al valor final
if(prop=="opacity"||prop=="z-index"||prop=="zoom"){
id.style[prop]=valfinal;
}else{
id.style[prop]=valfinal+'px';
}

//callback con argumentos (si hay)
if (callback && typeof(callback) === "function") {
callback.apply(id,[valinicial,valfinal]);
}

//Ponemos "Timeout" como undefined (tendrá su utilidad)
Timeout=undefined;
//Terminamos
return false;
}

}

Ya está casi todo hecho pero así, aunque podamos animar, no podremos hacer algunos efectos chulos como ocultar y mostrar elementos con efectos.

Por eso he realizado les siguientes funciones valiéndome del callback: expandir, contraer, expandirContraer, fadeIn, fadeOut y fadeInOut.


/*====================================================
* Expandir
*/
function expandir(elem,tiempo){
var id=document.getElementById(elem);
if (id.style.display!="none"&&id.style.display){return false;}
id.style.visibility="hidden";
id.style.display="block";
var altura=window.getComputedStyle(id).getPropertyValue("height");
if(altura=="auto"){altura=alturaAuto(elem)}else{altura=parseInt(altura)}
id.style.height="0px";
id.style.visibility="visible";
id.style.overflow="hidden";
animar(elem,"height",altura,tiempo)
}
/*======================================================================
* Contraer
*/

function contraer(elem,tiempo){
var id=document.getElementById(elem);
if (window.getComputedStyle(id).getPropertyValue("display")=="none"){return false;}
var altura=window.getComputedStyle(id).getPropertyValue("height");
if(altura=="auto"){altura=alturaAuto(elem)}else{altura=parseInt(altura)}
id.style.height=altura+'px';
animar(elem,"height",0,tiempo,function(){
this.style.display="none";
this.style.height=arguments[0]+'px';
//Recordad que "arguments[0]" era la altura con la que empezó
});
}
/*======================================================================
* Expandir/Contraer
*/
function expandirContraer(elem,tiempo){
var id=document.getElementById(elem);
if(typeof(Timeout) != "undefined"){return false;}
if(window.getComputedStyle(id).getPropertyValue("display")=="none"){
expandir(elem,tiempo);
}else{
contraer(elem,tiempo);
}
}
/*======================================================================
* Fade in-out
*/
function fadeIn(elem,tiempo){
var id=document.getElementById(elem);
if (window.getComputedStyle(id).getPropertyValue("display")!="none"){return false;}
id.style.opacity=0;
id.style.display="block";
animar(elem,"opacity",1,tiempo)
}
function fadeOut(elem,tiempo){
var id=document.getElementById(elem);
if (window.getComputedStyle(id).getPropertyValue("display")=="none"){return false;};
animar(elem,"opacity",0,tiempo
,function(){
this.style.display="none";
this.style.opacity=arguments[0];
}
);
}
function fadeInOut(elem,tiempo){
var id=document.getElementById(elem);
if(typeof(Timeout) != "undefined"){return false;}

if (window.getComputedStyle(id).getPropertyValue("display")!="none"){
fadeOut(elem,tiempo);
}else{
fadeIn(elem,tiempo)
}
}

Ahora os dejo con la demo. Divertíos

Demo

Si os interesa el tema, os recomiendo un blog llamado #Web{border:none} , que aunque esté desactualizado, me ayudó por ejemplo, a darme cuenta de que la mejor forma de hacerlo era ponerlo todo en función de frames por segundo.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Puedes usar las siguientes etiquetas y atributos HTML:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre data-language=""> <ul> <ol> <li>
Para poner código usa <pre data-language="[lenguaje]"><code>[código]</code></pre>, y no olvides escapar el HTMl.