Inline JS Progress Bars

2011-05-17: A richer version is available at http://www.barneyb.com/barneyblog/2011/05/17/even-better-inline-progress-bars/.

If you've ever built a web app that does background and/or batch processing of stuff, you've invariably created a bit of markup like this:

#numberFormat(sentEmailCount, ',')# of #numberFormat(emailCount, ',')# sent...

which then renders like this:

Wouldn't it be nice to create this markup (simply with a wrapping span) instead:

<span class="progress" rel="#sentEmailCount / emailCount#">
#numberFormat(sentEmailCount, ',')# of #numberFormat(emailCount, ',')# sent...
</span>

and have it render like this:

You think it would be?  I thought so too, so I wrote a simple little jQuery snippet to do exactly that.  Here she be:

jQuery(".progress").each(function() {
  var $this = jQuery(this)
  var frac = parseFloat($this.attr("rel"))
  if (isNaN(frac)) {
    return // nothing to do
  }
  $this.css({
      display: "inline-block",
      position: "relative",
      border: "1px solid #ccc",
      backgroundColor: "#eee",
      color: "#eee",
      padding: "0 5px"
    })
    .append(''
      + '<span style="display:inline-block;position:absolute;z-index:0;top:0;left:0;'
        + 'height:100%;width:' + (frac * 100) + '%;background-color:#cfc;"></span>'
      + '<span style="display:inline-block;position:absolute;z-index:1;top:0;left:5px;'
        + 'color:#000;">' + $this.html() + '</span>'
    )
})

The basic idea is to take the span, make it render like a bar, hide the text (same color as the background), and then append a pair of absolutely positioned spans to draw the progress bar and then lay the existing content atop it.  It's not terribly robust, but it works like a champ if your needs are simple, and the code is straightforward enough that it should be easy to tweak if you have specific needs.

Use it as is, hack it up, turn it into a massively popular plugin and make a bazillion dollars.  Have fun.

Update: here's the same functionality, repackaged into separate JS and CSS so it's easier to deal with. JS first:

jQuery(".progress").each(function() {
  var $this = jQuery(this)
  var frac = parseFloat($this.attr("rel"))
  if (isNaN(frac) || frac > 1) {
    return // nothing to do
  }
  $this.addClass("container")
    .append(''
      + '<span class="progress-bar" style="width:' + (frac * 100) + '%;"></span>'
      + '<span class="status-text">' + $this.html() + '</span>'
    )
})

And the CSS:

.progress.container {
  display: inline-block;
  position: relative;
  border: 1px solid #ccc;
  background-color: #eee;
  color: #eee;
  padding: 0 5px;
}
.progress.container .progress-bar {
  display: inline-block;
  position: absolute;
  z-index: 0;
  top: 0;
  left: 0;
  height: 100%;
  background-color: #dfd;
  border-right: 1px solid #6c6;
}
.progress.container .status-text {
  display: inline-block;
  position: absolute;
  z-index: 1;
  top: 0;
  left: 5px;
  color: #000;
}

One response to “Inline JS Progress Bars”

  1. John Allen

    I like it.