function morph( element, options, animationTime, callback ) {
// options is an array with the same structural of Properties and DiffValues and which contains the properties values we want the animation make
var ComputedElementStyle = window.getComputedStyle(element,null);
var AttrElementStyle = element.style;
var Properties = { // the actuals computed properties
width: parseInt( ComputedElementStyle.getPropertyValue("width")),
height: parseInt( ComputedElementStyle.getPropertyValue("height")),
padding: {
top: parseInt(ComputedElementStyle.getPropertyValue("padding-top")),
right: parseInt(ComputedElementStyle.getPropertyValue("padding-right")),
bot: parseInt(ComputedElementStyle.getPropertyValue("padding-bottom")),
left: parseInt(ComputedElementStyle.getPropertyValue("padding-left"))
},
margin:{
top: parseInt(ComputedElementStyle.getPropertyValue("margin-top")),
right: parseInt(ComputedElementStyle.getPropertyValue("margin-right")),
bot: parseInt(ComputedElementStyle.getPropertyValue("margin-bottom")),
left: parseInt(ComputedElementStyle.getPropertyValue("margin-left"))
}
};
var DiffValues = { // the differences between actual properties values and values we want to
width: (options['width']!=null) ? (options['width'] - Properties['width']) : 0,
height: (options['height']!=null) ? (options['height'] - Properties['height']) : 0,
padding: {
top: (options['padding']&&options['padding']['top']!=null) ? options['padding']['top'] - Properties['padding']['top'] : 0,
right: (options['padding']&&options['padding']['right']!=null) ? options['padding']['right'] - Properties['padding']['right'] : 0,
bot: (options['padding']&&options['padding']['bot']!=null) ? options['padding']['bot'] - Properties['padding']['bot'] : 0,
left: (options['padding']&&options['padding']['left']!=null) ? options['padding']['left'] - Properties['padding']['left'] : 0
},
margin:{
top: (options['margin']&&options['margin']['top']!=null) ? options['margin']['top'] - Properties['margin']['top'] : 0,
right: (options['margin']&&options['margin']['right']!=null) ? options['margin']['right'] - Properties['margin']['right'] : 0,
bot: (options['margin']&&options['margin']['bot']!=null) ? options['margin']['bot'] - Properties['margin']['bot'] : 0,
left: (options['margin']&&options['margin']['left']!=null) ? options['margin']['left'] - Properties['margin']['left'] : 0
}
};
var beginTime = new Date().getTime(); // time at begining of animation
animationTime = (animationTime!=null) ? animationTime : 250;
AttrElementStyle.overflow = "hidden"; // disable the potentials scrollbars
var sinceBeginTime; // time since the begining
var progressFactor; // coeficient that correspond to the advancement of the animation
timer = setInterval(function() { // begin of the animation
sinceBeginTime = new Date().getTime() - beginTime;
if( sinceBeginTime < animationTime ) {
progressFactor = sinceBeginTime / animationTime;
AttrElementStyle.width=(Properties['width'] + DiffValues['width'] * progressFactor) +"px";
AttrElementStyle.height=(Properties['height'] + DiffValues['height'] * progressFactor) +"px";
AttrElementStyle.padding=
(Properties['padding']['top'] + DiffValues['padding']['top'] * progressFactor) +"px "+
(Properties['padding']['right'] + DiffValues['padding']['right'] * progressFactor) +"px "+
(Properties['padding']['bot'] + DiffValues['padding']['bot'] * progressFactor) +"px "+
(Properties['padding']['left'] + DiffValues['padding']['left'] * progressFactor) +"px";
AttrElementStyle.margin=
(Properties['margin']['top'] + DiffValues['margin']['top'] * progressFactor) +"px "+
(Properties['margin']['right'] + DiffValues['margin']['right'] * progressFactor) +"px "+
(Properties['margin']['bot'] + DiffValues['margin']['bot'] * progressFactor) +"px "+
(Properties['margin']['left'] + DiffValues['margin']['left'] * progressFactor) +"px";
}else {
AttrElementStyle.width=options['width'] +"px";
AttrElementStyle.height=options['height'] +"px";
AttrElementStyle.padding=
(Properties['padding']['top'] + DiffValues['padding']['top']) +"px "+
(Properties['padding']['right'] + DiffValues['padding']['right']) +"px "+
(Properties['padding']['bot'] + DiffValues['padding']['bot']) +"px "+
(Properties['padding']['left'] + DiffValues['padding']['left']) +"px";
AttrElementStyle.margin=
(Properties['margin']['top'] + DiffValues['margin']['top']) +"px "+
(Properties['margin']['right'] + DiffValues['margin']['right']) +"px "+
(Properties['margin']['bot'] + DiffValues['margin']['bot']) +"px "+
(Properties['margin']['left'] + DiffValues['margin']['left']) +"px";
clearInterval( timer ); // end of the animation
if( callback!=null ) // if there is a CALLBACK then call it
callback(Properties);
}
},15);
}
function slideUp( element, animationTime , callback) {
morph( element, {
height:0,
padding:{
top:0,
bot:0
},
margin:{
top:0,
bot:0
} }, animationTime, function(Properties) {
// at the end of the slideUp we display: none the element and clean the other properties from style attribute
var AttrElementStyle = element.style;
AttrElementStyle.width="";
AttrElementStyle.height="";
AttrElementStyle.padding="";
AttrElementStyle.margin="";
element.style.display = 'none';
if(callback)
callback();
});
}
function slideDown( element, animationTime , callback) {
var AttrElementStyle = element.style;
var ComputedElementStyle = window.getComputedStyle(element,null);
AttrElementStyle.display="block";
var options = { // the computed properties when element is displayed
width: parseInt( ComputedElementStyle.getPropertyValue("width")),
height: parseInt( ComputedElementStyle.getPropertyValue("height")),
padding: {
top: parseInt(ComputedElementStyle.getPropertyValue("padding-top")),
bot: parseInt(ComputedElementStyle.getPropertyValue("padding-bottom"))
},
margin:{
top: parseInt(ComputedElementStyle.getPropertyValue("margin-top")),
bot: parseInt(ComputedElementStyle.getPropertyValue("margin-bottom"))
}
};
// after getting the actuals properties values of the element we flatten it
AttrElementStyle.height="0";
AttrElementStyle.paddingTop="0";
AttrElementStyle.paddingBottom="0";
AttrElementStyle.marginTop="0";
AttrElementStyle.marginBottom="0";
morph( element, options , animationTime, function() { // morph the element from flat to the options properties that are right
// at the end of slideDown we clean up the style but keep the display: block if the element is display: none in the stylesheet
AttrElementStyle.width="";
AttrElementStyle.height="";
AttrElementStyle.padding="";
AttrElementStyle.margin="";
element.style.display = 'block';
if(callback) // if there is a CALLBACK then call it (we are in the morph() callback)
callback();
})
}
p{
width:50%;
height:auto;
padding:40px 0 10px;
margin: 10px 0 40px;
border:2px solid red
}
div{
border:1px solid blue;
padding:10px
}
<div>
<p id='p'>loiloilozoifboiygdouhbodihfgsd</br>rihgdggisbifghbsoifnsf</br>giodsbgsigfbsjgsgs</p>
</div>
<button onClick="slideUp( document.getElementById('p') ,500)">testUp</button>
<button onClick="slideDown( document.getElementById('p') ,500)">testDown</button>
<button id='btn1' onClick="morph( document.getElementById('btn1'),{ width: 120,height:130,padding:{top:70,left:50},margin:{right:40}} ,1000)">morphIt</button>
<button onClick="document.getElementById('btn1').style=''">reset btn1</button>