ref: http://firblitz.com/2007/3/6/re-how-to-create-digg-comment-style-sliding-divs-with-javascript-and-css

wrote a nice blog entry on how to make sliding DIVs using Javascript and CSS from scratch without having the overhead of Effects libraries such as script.aculo.us. Long story short, it made it to the front page of Digg, I thought it was cool but I think I can do better, so here it is:

Let’s start with a Javascript object:

function Slide(objId) {
this.obj = document.getElementById(objId);
this.duration = 1;
this.height = parseInt(this.obj.style.height);
return this; }

And we will want two functions to slide our element up and down:

this.up = function() {
this.curHeight = this.height;
this.newHeight = '1'; }
this.down = function() {
this.newHeight = this.height;
this.curHeight = '1'; }

And then we need a function to do the actual work:

this.slide = function() {
var frames = 30 * duration;
// Running at 30 fps
var tIncrement = (duration*1000) / frames;
tIncrement = Math.round(tIncrement);
var sIncrement = (this.curHeight-this.newHeight) / frames;
var frameSizes = new Array();
for(var i=0; i < frames; i++) {
if(i < frames/2) {
frameSizes[i] = (sIncrement * (i/frames))*4;
} else {
frameSizes[i] = (sIncrement * (1-(i/frames)))*4;
}
}
for(var i=0; i < frames; i++) {
this.curHeight = this.curHeight - frameSizes[i];
window.setTimeout("document.getElementById('"+objId+"').style.height='"
+Math.round(this.curHeight)+"px';",tIncrement * i); 	} }

Whoa. WTF is going on here? First we figure out how many frames total are used and store it in frames, tIncrement is the time in milliseconds spent on each frame, and sIncrement is the size in pixels moved every frame. After that, we create a new array called frameSizes that will actually hold the size that the DIV should be at each frame. We run it through my magic for loop that adds adjusts for acceleration and deceleration (yes I wrote it, no I didn’t steal it, yes you can use it, no I don’t mind, yes I like credit, no you don’t have to).

Now lets create a global array that “checks out” the object if an animation is currently happening. This will prevent weird issues if you invoke the animation many times quickly:

var slideInUse = new Array();  this.up = function() { 	...
if(slideInUse[objId] != true) {
this.slide(); 	} }  this.down = function() { 	.
..
if(slideInUse[objId] != true) {
this.slide(); 	} }  this.slide = function() {
slideInUse[objId] = true; 	...
window.setTimeout("delete(slideInUse['"+objId+"']);",tIncrement * i); }

Finally, we add in a function to reset the DIV to it’s actual height after it’s slide up and been hidden, or to show it at 1 pixel when it’s about to be slid down:

this.up = function() { 	...
...
window.setTimeout("Slide('"+objId+"').
finishup("+this.height+");",finishTime);
... }  this.down = function() { 	...
this.obj.style.height = '1px';
this.obj.style.display = 'block';
...
... }  this.finishup = function(height) {
this.obj.style.display = 'none';
this.obj.style.height = height + 'px'; }

Add everything else I forgot to outline here (but included in the final file, and you can animate like so:

<a href="javascript:Slide(&apos;mydiv&apos;).down();"
mce_href="javascript:Slide(&apos;mydiv&apos;).down();">Slide Down</a>
<a href="javascript:Slide(&apos;mydiv&apos;).up();"
mce_href="javascript:Slide(&apos;mydiv&apos;).up();">Slide Down</a>
<div id="mydiv" style="display:none;
overflow:hidden; height:100px;">Hello world!</div>

var slideInUse = new Array(); function Slide(objId, options) { this.obj = document.getElementById(objId); this.duration = 1; this.height = parseInt(this.obj.style.height); if(typeof options != ‘undefined’) { this.options = options; } else { this.options = {}; } if(this.options.duration) { this.duration = this.options.duration; } this.up = function() { this.curHeight = this.height; this.newHeight = ‘1’; if(slideInUse[objId] != true) { var finishTime = this.slide(); window.setTimeout(“Slide(‘”+objId+”‘).finishup(“+this.height+”);”,finishTime); } } this.down = function() { this.newHeight = this.height; this.curHeight = ‘1’; if(slideInUse[objId] != true) { this.obj.style.height = ‘1px’; this.obj.style.display = ‘block’; this.slide(); } } this.slide = function() { slideInUse[objId] = true; var frames = 30 * duration; // Running at 30 fps var tIncrement = (duration*1000) / frames; tIncrement = Math.round(tIncrement); var sIncrement = (this.curHeight-this.newHeight) / frames; var frameSizes = new Array(); for(var i=0; i < frames; i++) { if(i < frames/2) { frameSizes[i] = (sIncrement * (i/frames))*4; } else { frameSizes[i] = (sIncrement * (1-(i/frames)))*4; } } for(var i=0; i < frames; i++) { this.curHeight = this.curHeight – frameSizes[i]; window.setTimeout(“document.getElementById(‘”+objId+”‘).style.height='”+Math.round(this.curHeight)+”px’;”,tIncrement * i); } window.setTimeout(“delete(slideInUse[‘”+objId+”‘]);”,tIncrement * i); if(this.options.onComplete) { window.setTimeout(this.options.onComplete, tIncrement * (i-2)); } return tIncrement * i; } this.finishup = function(height) { this.obj.style.display = ‘none’; this.obj.style.height = height + ‘px’; } return this; }Example:

Slide Down Slide Up

Hello world!

In addition, I’ve added some extra options to control duration in seconds and an optional onComplete call:

<a href="javascript:Slide(&apos;mydiv&apos;,
{duration:5,onComplete: function()
{alert(&apos;Hello World!&apos;);} }).down();">Slide Down</a>

Example:

Slide Down (2 seconds) Slide Up (with alert)

Hello again.

You will notice that the alert above triggers a little early. This was to force Safari to redraw elements on a page correctly if the onComplete is used to show/hide elements in/around the DIV that is being animated. If you don’t care about Safari, or you are not encountering the redraw issue with your content, replace if(this.options.onComplete) with this:

if(this.options.onComplete) {
window.setTimeout(this.options.onComplete, tIncrement * i); }

The majority of this was written during my lunch break, so I am sure there are bugs, crappy ways that I did things, and plenty of comments and constructive criticism coming my way.

Download slider.js.