Download Source Code: AnimatedCollapsiblePanel.zip - 16.03KB
Animated Collapsible Panel Design

Content goes here...
Time to add our final touch: animation. When the panel expands or collapses, the user must see its content's height gradually shrinking or growing, which actually creates the effect of animation.
Again, we'll try to keep the implementation as simple as possible, to avoid using IDs or storing intermediate values in client-side cookies.
It's obvious we need to determine what the height of the rendered content will be. This is usually hard, because we do not have a height value set, and the actual height is dynamically determined at runtime, by the browser.
However, we're lucky to have the offsetHeight property of a HTML element, but this has to be visible. When our content is collapsed and hidden, first thing to do is to make it visible (set display="block") and read its offsetHeight.
<html> <head> <link type="text/css" rel="stylesheet" href="Animated-Collapsible-Panel-5.css" /> <script language="javascript" type="text/javascript" src="Animated-Collapsible-Panel-5.js"></script> </head> <body> <!-- Animated collapsible panel, with separate CSS and JavaScript --> <div style="width:170px;"> <div class="squarebox"><div class="squareboxgradientcaption" style="height:20px; cursor: pointer;" onclick="togglePannelAnimatedStatus(this.nextSibling,50,50)"><div style="float: left">Title goes here...</div><div style="float: right; vertical-align: middle"><img src="../images/collapse.gif" width="13" height="14" border="0" alt="Show/Hide" title="Show/Hide" /></div> </div><div class="squareboxcontent"> <img width="150" height="100" src="../images/sample_photo.jpg" alt="This is an image" title="This is an image" /><br /> Content goes here... </div> </div> <img width="170" height="20" alt="" src="../images/shadow.gif" /> </div> </body> </html>
Our final implementation uses separate CSS and JS JavaScript files, referenced from the HTML page.
External .css stylesheet files can be referenced by a <link type="text/css" rel="stylesheet" href="...css" /> line in the HEAD section of the page. Here is the CSS file we used before:
.squarebox {
width: 100%;
border: solid 1px #336699;
text-align: center;
overflow: hidden; }
.squareboxgradientcaption {
color: #ffffff;
padding: 5px;
background-image: url(../images/gradient_blue.png);
background-repeat: repeat-x; }
.squareboxcontent {
background-color: #f5f5f5;
padding: 10px;
overflow: hidden;
border-top: solid 1px #336699; }External JavaScript .js code files can be referenced by a <script type="text/javascript" src="...js"></script> line. Here is the required JavaScript JS file we separated from the HTML page:
// not animated collapse/expand
function togglePannelStatus(content)
{
var expand = (content.style.display=="none");
content.style.display = (expand ? "block" : "none");
toggleChevronIcon(content);
}
// current animated collapsible panel content
var currentContent = null;
function togglePannelAnimatedStatus(content, interval, step)
{
// wait for another animated expand/collapse action to end
if (currentContent==null)
{
currentContent = content;
var expand = (content.style.display=="none");
if (expand)
content.style.display = "block";
var max_height = content.offsetHeight;
var step_height = step + (expand ? 0 : -max_height);
toggleChevronIcon(content);
// schedule first animated collapse/expand event
content.style.height = Math.abs(step_height) + "px";
setTimeout("togglePannelAnimatingStatus("
+ interval + "," + step
+ "," + max_height + "," + step_height + ")", interval);
}
}
function togglePannelAnimatingStatus(interval,
step, max_height, step_height)
{
var step_height_abs = Math.abs(step_height);
// schedule next animated collapse/expand event
if (step_height_abs>=step && step_height_abs<=(max_height-step))
{
step_height += step;
currentContent.style.height = Math.abs(step_height) + "px";
setTimeout("togglePannelAnimatingStatus("
+ interval + "," + step
+ "," + max_height + "," + step_height + ")", interval);
}
// animated expand/collapse done
else
{
if (step_height_abs<step)
currentContent.style.display = "none";
currentContent.style.height = "";
currentContent = null;
}
}
// change chevron icon into either collapse or expand
function toggleChevronIcon(content)
{
var chevron = content.parentNode
.firstChild.childNodes[1].childNodes[0];
var expand = (chevron.src.indexOf("expand.gif")>0);
chevron.src = chevron.src
.split(expand ? "expand.gif" : "collapse.gif")
.join(expand ? "collapse.gif" : "expand.gif");
}To show the panel initially collapsed, we do what we did before: set the display style of the content to "none" and the chevron image source to expand.gif.
We kept the not-animated collapsing panel behavior handled by togglePanelStatus. We separated changing of the chevron image in toggleChevronIcon, because this action has to be used also by the animated panel. Each animated expand or collapse will call, once, togglePanelAnimatedStatus, passing as arguments some animation tuning parameters: interval specifies the number of milliseconds between repainting the browser during the animation, and step gives the number of pixels the height is increased or decreased between two refresh sequences. Combination of these two values defines essentially animation's speed.
When a collapse/expand animation starts, the currentContent global variable is set to the panel being processed. This prevents other panels being collapsed or expanded in the same time, and also makes unnecessary to call document.getElementById from togglePanelAnimatingStatus. This is because this last function is always scheduled to run after the interval value through a setTimeout JavaScript call, and you cannot pass objects as arguments to this function!
To use these functions for both collapse and expand, we pass a positive step_height value for collapse and negative for expand. When step_height - which holds the current height of an animated panel - becomes less than 0 or larger than max_height - which holds the rendered offsetHeight value of the panel - animation ends.
Things left to do:
- It looks like offsetHeight's value is somehow larger than the actual height. The animated panel gets extended to a bigger size, but after the final step is reset to its actual height.
- The GIF image used as shadow does not have its "background" color set as transparent. Try to show the panel on a different background color: all appears well, but the shadow.
August 13, 2007 at 03:32 PM
August 13, 2007 at 09:51 PM
August 14, 2007 at 09:13 AM
August 14, 2007 at 12:36 PM
A quick solution can be applied for the first collapsible panel in page 2 (sorry I don't have time enough now for the code - tomorrow I go in vacation :)).
In the generic togglePannelStatus JavaScript function, insert code, at the beginning, to identify all DIVs with squareboxgradientcaption class name and collapse all panels from the page.
September 13, 2007 at 02:44 PM
September 17, 2007 at 05:41 AM
I found your 'Animated Collapsible Panel' tutorial extremely interesting and was wondering if it can be tweaked so that the panels extend and collapse horizontally instead of vertically as in the sreenshot link below:
http://www.igolfscorer.com/widget.jpg
Any advice would be great! Thanks again for the great tutorial!
Kind regards,
Declan
October 12, 2007 at 12:10 PM
October 18, 2007 at 11:26 AM
April 07, 2008 at 07:08 PM
April 18, 2008 at 07:12 PM
April 18, 2008 at 09:45 PM