Animated "Reveal" Effects

Power and rich content can also mean clutter. Hiding some of the content or power until needed can help minimize clutter, and animation can help to guide the user's attention.

Exposing elements with animation does not require absolute positioning, but it is often useful. For this kind of animation the key is to enclose the animated element in a parent element of smaller size with overflow: hidden. Parts of the child within the parent's rectangle are visible. For this, the offsetWidth and offsetHeight properties of the child can help to compute the parent's size.

The examples on this page give the parent position: absolute without any coordinates, so its position is where it "would have gone" without absolute positioning. With absolute position of the child element you will often give an explicit width, which will prevent its width from shrinking more than desired. A tabular layout for the child may also help.

This DHTML effect does not need a sophisticated client-side library; in fact all of the JavaScript for it is right in this page.

This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.

At the left is an area that can animate into the display, implemented by a DIV with overflow: hidden. When the button is pressed it expands to overlap other content.

HTML source for this area is:

 <div style="width: 0px; overflow: hidden; position: absolute;">
  <div id=pop
   style="width: 15em; background-color: beige; border: 1px solid silver;">
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  </div>
 </div>

With small changes, the content can slide in as it appears. Define the child style to include position: absolute; right: 0px;. This attaches it to the right edge of the parent. You can use JavaScript to set parent.style.height = child.offsetHeight since the parent's height will not automatically accommodate the height of the child.

This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.
This is a test of animated reveal.

The HTML source becomes:

 <div style="width: 0px; overflow: hidden; position: absolute;">
  <div id=pop
   style="width: 15em; background-color: beige; border: 1px solid silver;
          position: absolute; right: 0px;">
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  This is a test of animated reveal.<br>
  </div>
 </div>

JavaScript Source Code

var pop;
var pop2;
var loaded = false;

// Called on page load.
function start() {
  pop = document.getElementById("pop");
  pop2 = document.getElementById("pop2");
  dad = pop.parentNode;
  dad2 = pop2.parentNode;
  // In case the child is absolutely positioned.
  dad.style.height = pop.offsetHeight;
  dad2.style.height = pop2.offsetHeight;
  loaded = true;
}

// Run by the Toggle buttons
function toggle(el, duration, done) {
  if (!loaded) {
    return;
  }
  var dad = el.parentNode;
  var open = dad.offsetWidth;
  var from = open ? open : 0;
  var to = open ? 0 : el.offsetWidth;
  var a = new Animator(from, to, duration,
                       function(w) { dad.style.width = w; });
  a.play();
}

// Class to play an animation.
Animator = function Animator(start, end, duration, callback, done) {
  this.timer = null;
  this.start = start;
  this.end = end;
  this.duration = duration;
  this.startTime = new Date().valueOf();
  this.callback = callback;
  this.done = done;
}

// Method to start the animation.
Animator.prototype.play = function() {
  var _this = this;
  this.timer = setInterval(function() {_this.animate()}, 40);
};

// Internal method that runs at intervals during the animation.
Animator.prototype.animate = function() {
  var now = new Date().valueOf();
  // Duration of zero is OK here.
  var progress = (now-this.startTime)/this.duration;
  if (progress>=1) {
    clearInterval(this.timer);
    progress = 1;
    if (this.done) {
      this.done();
    }
  }
  var position = this.start + (this.end-this.start)*progress;
  this.callback.call(this, position, progress);
};