Making a progress bar with JavaScript and CSS 

Joined:
02/21/2009
Posts:
151

July 04, 2009 16:30:40    Last update: January 11, 2011 21:21:59
If you are looking for a solution for a progress bar, I direct you to the following resources:
  1. Bare Naked App provides a simple and elegant solution based on pure CSS with two images. You control the percentage of completion through the background-position attribute of the CSS.

    HTML:
    <img src="/images/percentImage.png" 
         alt="9.5%" 
         class="percentImage" 
         style="background-position: -110.315px 0pt;" />
    


    CSS:
    img.percentImage {
     background: white url(/images/percentImage_back.png) top left no-repeat;
     padding: 0;
     margin: 5px 0 0 0;
     background-position: 1px 0;
    }
    


    Images:
    (percentImage.png)
    (percentImage_back.png)

  2. WebAppers extended the above solution with JavaScript. They also added several colored images:









  3. JQuery UI has a built-in progress bar widget.


However, if you want to get to understand some of the foobar needed to get CSS to work (in general) through this example, stay with me for the rest of this note.

Initially I was thinking, a progress bar should be easy: just make two divs with different colors and stack one over the other. So this was my first attempt:
  • Code
  • Demo
<html>
<head>
	<title>Progress Bar Test</title>
	<style type="text/css">
		.progress-bar-background {
			background-color: #D0D0D0;
			width: 100%;
			height: 100%;
			position: relative;
			top: 0;
			left: 0;
		}

		.progress-bar-complete {
			background-color: green;
			width: 50%;
			height: 100%;
			position: relative;
			top: -12px;
			left: 0;
		}

		#progress-bar {
			width: 200px;
			height: 12px;
			border: 1px black solid;
		}
	</style>
</head>

<body>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor 
       incididunt ut labore et dolore magna aliqua.</p>
	<div id="progress-bar">
		<div class="progress-bar-background"></div>
		<div class="progress-bar-complete"></div>
	</div>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor 
       incididunt ut labore et dolore magna aliqua.</p>
</body>
</html>


And indeed, it worked quite well for FireFox:



However, it didn't work as expected in IE:



What's going on? I see 3 problems:
  1. IE did not honor the 12px height style for the outer div. It expanded the outer div to accomodate the 2 inner divs.
  2. IE did not calculate the 100% height for the inner divs from the height of the container div.
  3. IE did not shrink the height of the outer div to account for the upward displacement of 12px of the second inner div.


Further experimentation showed that this HTML snippet:
<p><div style="width:200px;height:10px;border: 1px black solid;"></div></p>
<p><div style="width:200px;height:15px;border: 1px black solid;"></div></p>
<p><div style="width:200px;height:20px;border: 1px black solid;"></div></p>
<p><div style="width:200px;height:40px;border: 1px black solid;"></div></p>
<p><div style="width:200px;height:50px;border: 1px black solid;"></div></p>

<p>
<div style="height:12px;width:200px;border: 1px solid red;">
	<div style="width:100%;height:20%;border: 1px blue solid;"></div>
</div>
</p>
	
<p>
<div style="height:12px;width:200px;border: 1px solid red;">
	<div style="width:100%;height:50%;border: 1px blue solid;"></div>
</div>
</p>
	
<p>
<div style="height:12px;width:200px;border: 1px solid red;">
	<div style="width:100%;height:100%;border: 1px blue solid;"></div>
</div>
</p>

<p>
<div style="height:12px;width:200px;border: 1px solid red;">
	<div style="width:100%;height:100%;border: 1px blue solid;"></div>
	<div style="width:100%;height:100%;border: 1px blue solid;"></div>
</div>
</p>

rendered drastically differently in IE and Firefox:

FirefoxIE


Anyways, two conclusions can be drawn about IE:
  1. IE imposed a minimum height on a div, any attempt to set the height less than the minimum is ignored.
  2. CSS percentage height calculations cannot be trusted.


With a bit of luck, I found that adding "overflow:hidden" to the CSS makes IE to recognize a height less than the built-in minimum value. By replacing the percentage height of the inner divs with the actual pixel values, I made IE to behave the same as Firefox. This is the working CSS:
<style type="text/css">
	.progress-bar-background {
		background-color: #D0D0D0;
		width: 100%;
		height: 12px;
		position: relative;
		overflow:hidden;
		top: 0;
		left: 0;
	}

	.progress-bar-complete {
		background-color: green;
		width: 50%;
		height: 12px;
		position: relative;
		overflow:hidden;
		top: -12px;
		left: 0;
	}

	#progress-bar {
		width: 200px;
		height: 12px;
		overflow:hidden;
		border: 1px black solid;
	}
</style>


That said, I noticed that IE's 12px height is a bit smaller than FireFox's 12px height.

Finally, add some JavaScript to set it in action:
  • Code
  • Demo
<html>
<head>
	<title>Progress Bar Test</title>
	<style type="text/css">
		.progress-bar-background {
			background-color: #D0D0D0;
			width: 100%;
			position: relative;
			overflow:hidden;
			top: 0;
			left: 0;
		}

		.progress-bar-complete {
			background-color: green;
			width: 50%;
			position: relative;
			overflow:hidden;
			top: -12px;
			left: 0;
		}

		#progress-bar {
			width: 200px;
			height: 20px;
			overflow:hidden;
			border: 1px black solid;
		}
	</style>

	<script language="JavaScript" type="text/javascript">
	function createProgressBar(elem) {
		var div1 = document.createElement('DIV');
		div1.className = 'progress-bar-background';
		div1.style.height = elem.offsetHeight + 'px';
		elem.appendChild(div1);

		var div2 = document.createElement('DIV');
		div2.className = 'progress-bar-complete';
		div2.style.height = elem.offsetHeight + 'px';
		div2.style.top = '-' + elem.offsetHeight + 'px';
		elem.appendChild(div2);

		return {
			div1 : div1,
			div2 : div2,
			setValue : function(v) {
				this.div2.style.width = v + '%';
			}
		}
	}
	</script>
</head>

<body>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor 
       incididunt ut labore et dolore magna aliqua.</p>
	<div id="progress-bar"></div>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor 
       incididunt ut labore et dolore magna aliqua.</p>
	<button onclick="resetValue();showProgress();">Demo!</button>

	<script language="JavaScript" type="text/javascript">
		var theBar = createProgressBar(document.getElementById('progress-bar'));
	  
		var value;
		function resetValue() {
			value = 0;
		}

		function showProgress() {
			value += 1;
			theBar.setValue(value);
			if (value < 100) {
				window.setTimeout(showProgress, 100);
			}
		}
	</script>
</body>
</html>


Conclusion: Much of CSS is still voodoo!
Share |
| Comment  | Tags
1 comment