Accessibility
 
Icon or Spacer
   
Revealing the Hidden—CSS Visibility and Display Properties
by Robert Crooks

Editor's Note: This article uses CSS properties and DHTML effects that will not be rendered by all browsers; for best results, you should view this one in IE 4.0+. A future article in this series will look at techniques for creating cross-browser DHTML effects. Click here to download this page in .HTM format.

In my last article, we looked at dynamic positioning of HTML elements using Cascading Style Sheet properties and scripted style class changes. Now we will look at another crucial ingredient of DHTML: dynamically hiding and revealing information.

We will look at two CSS properties that can be used for selectively hiding and revealing information -- display and visibility. Then we will look at scripting techniques for dynamically hiding and revealing information, considering three typical scenarios. Along the way, we will also make a brief excursion into JavaScript event handlers.

Note: this is the third in a series of articles on DHTML. If you have not read the previous two articles, you may want to do so:

CSS Display and Visibility Properties

Like positioning, display and visibility comprise an area where CSS offers more than just an alternative to HTML formatting. Here CSS provides interesting possibilities for handling web content that HTML alone simply cannot give us.

The visibility of an element on a page is determined by one of two CSS properties:

  • visibility (values: inherit | visible | hidden)
  • display (values: block | none | inline | list-item)

For practical purposes, the difference between these two properties is that when you hide information using the visibility property, the browser creates the appropriate amount of space in the browser window for the information when the page loads. When you use the display property, space for the information is not created until the element becomes visible. We will look at demonstrations shortly, but first let's define a set of style classes that will be used for these and other demonstrations later in this article:

	/* Normal style */
	 .normal {
	  font-family: Comic Sans MS, sans-serif; 
	 }
	/* highlight */
	 .highlight {
	  font-family: Comic Sans MS, sans-serif;
	  background-color: #ffffcc 
	 }
	/* Display block */
	 .DisplayBlock {
	  display : block;
	}
	/* Display none */
	 .DisplayNone {
	  display: none;
	 }
	/* Visibility Hidden */
	 .Hidden {
	  visibility: hidden;
	 }
	/* Visibility Visible */
	 .Visible {
	  visibility: visible;
	 }
	/* Position 0 */
	 .Position0 {
	  position: relative;
	  width: 420px;
	  height: 200px;
	  background-color: #e6e6fa; 
	  border: thin; 
	  border-color: #4B0082; 
	  border-style: solid; 
	  font-family: Comic Sans MS, Sans-Serif;
	  font-style: italic;  
	  font-weight: normal;  
	  color: #4B0082;  
	   
	 }
	/* Position 1 */
	 .Position1 {
	  position: absolute;
	  left: 10px;
	  top: 10px;
	  width: 90px; 
	 }
	/* Position 2 */
	 .Position2 {
	  position: absolute;
	  left: 110px;
	  top: 10px;
	  width: 90px; 
	 }
	/* Position 3 */
	 .Position3 {
	  position: absolute;
	  left: 210px;
	  top: 10px;
	  width: 90px; 
	 }
	/* Position 4 */
	 .Position4 {
	  position: absolute;
	  left: 10px;
	  top: 30px;
	  width: 90px; 
	 }
	/* Position 5 */
	 .Position5 {
	  position: absolute;
	  left: 110px;
	  top: 30px;
	  width: 90px; 
	 }
	/* Position 6 */
	 .Position6 {
	  position: absolute;
	  left: 210px;
	  top: 30px;
	  width: 90px; 
	 }
	/* Position 7 */
	 .Position7 {
	  position: absolute;
	  left: 10px;
	  top: 30px;
	  width: 330px; 
	 }

Now let's look at a demonstration of the display property:

This paragraph has class DisplayNone. It will be visible in the source code, but completely invisible in the rendered page.

This is a normal paragraph, placed after a paragraph that has the class DisplayNone. Note that there is no evidence of the preceding paragraph in the rendered page. You will find the concealed paragraph if you look at the page source and search for the text Marker1.

And now a demonstration of the visibility property:

This is a normal paragraph, placed after a paragraph that has the class Hidden. Note the empty space where the preceding paragraph would appear in the rendered page. You will find the concealed paragraph if you look at the page source and search for the text Marker2.

 

Dynamically Revealing Hidden Elements

Obviously the display: none and visibility: hidden properties are of limited use in themselves. By using client-side scripting to change these properties in response to some event, however, we can create several useful DHTML effects.

We already saw in my previous two articles how to change an element's CSS class in response to an event, and we will use the same technique here. But before we proceed to actual demonstrations, let's take another look at JavaScript event-handlers.

Reusable Event-Handlers

In the previous articles in this series on DHTML, we created ad-hoc JavaScript event-handlers to create various dyanamic effects in an HTML element's appearance or position. Since these kinds of JavaScript functions are generally useful in DHTML, it makes sense to write more flexible functions that can be reused in many different pages. The key to creating these generalized event-handlers is simply to pass some parameters when we call the JavaScript function. These parameters will determine exactly what the function does in a particular instance.

For example, in the previous articles I defined custom functions to change the style class for a some particular element. To create a general JavaScript class-changer, all I need to do is write the function in such a way that it accepts parameters that indicate the element to be changed and new classname, and perform the operation:

  	function classChange(element,newclass) {
	element.className = newclass;
	}
  

When we call this function, we simply need to pass the name or id of the element we want to manipulate (we can use the keyword this for the current element) and the new classname.

I'll put this function to work now by redeploying the two demonstrations above. This time, I will use the mouseover event in the visible paragraph to change the class of the hidden one to something visible.

Display: none --> Display: block

This paragraph has class DisplayNone. It will be visible in the source code, but completely invisible in the rendered page.

This is a normal paragraph, placed after a paragraph that has the class DisplayNone. Move the mouse over this paragraph to reveal the hidden one; then click anywhere inside this paragraph to hide it again..

Visibility: hidden --> Visibility: visible

This is a normal paragraph, placed after a paragraph that has the class Hidden. Move the mouse over this paragraph to reveal the hidden one; move the mouse off to hide it again.

Here is the code for the previous two demonstrations:

	<div class="Position0">
	<p class="DisplayNone" id="undisplayed">
	<!-- Marker1 -->This paragraph has class 
	<strong>DisplayNone</strong>.  
	It will be visible in the source
	code, but completely invisible in the rendered page.
	</p>
	<p class="normal" 
	onMouseOver="classChange(undisplayed,'DisplayBlock')" 
	onClick="classChange(undisplayed,'DisplayNone')">
	This is a normal paragraph, placed after a paragraph 
	that has the class 
	<strong>DisplayNone</strong>. 
	Move the mouse over this paragraph to reveal 
	the hidden one; then click 
	anywhere inside this paragraph to hide it again..
	</p>
	</div>

	<div class="Position0">
	<p class="Hidden" id="invisible">
	<!-- Marker2 -->This paragraph has class 
	<strong>Hidden</strong>.  It will be 
	visible in the source code, but appear
	 as empty space in the rendered page.
	</p>
	<p class="normal" 
	onMouseOver="classChange(invisible,'Visible')" 
	onMouseOut="classChange(invisible,'Hidden')">
	This is a normal paragraph, placed after a paragraph 
	that has the class <strong>Hidden</strong>.
	Move the mouse over this paragraph to reveal the 
	hidden one; move the mouse off to hide it again.
	</p>
	</div>

Now that we have the basics of hiding and revealing, we will look at some pratical applications of this DHTML technique.

Example 1: Menu with details

In this example, we will use the visibility property and a slightly modified version of the simple event-handler we created earlier to reveal a hidden description when the user passes the mouse over a link. The visible and invisible elements are arranged using the positioning techniques I discussed in the previous article in this seris.

For the event-handler, we'll a few more line to the classChange function, changing the class for the srcElement (where the event occurs) to either highlight or normal, depending on the present class:

  	function newClassChange(element,newclass) {
	if (event.srcElement.className == "normal") {
	event.srcElement.className = "highlight";
	}
	else {
	event.srcElement.className = "normal";
	}	
	element.className = newclass;
	}
  

Here is the HTML code for the sample above:

	<div class="Position0">
	<div class="Position1">
	<a href="JavaScript:nolink()" class="normal" 
	onMouseOver="newClassChange(p1desc,'Visible')" 
	onMouseOut="newClassChange(p1desc,'Hidden')">Page One</a>
	</div>
	<div class="Position2">
	<a href="JavaScript:nolink()" class="normal" 
	onMouseOver="newClassChange(p2desc,'Visible')" 
	onMouseOut="newClassChange(p2desc,'Hidden')">Page Two</a>
	</div>
	<div class="Position3">
	<a href="JavaScript:nolink()" class="normal" 
	onMouseOver="newClassChange(p3desc,'Visible')" 
	onMouseOut="newClassChange(p3desc,'Hidden')">Page Three</a>
	</div>
	<div class="Position4">
	<p id="p1desc" class="Hidden">This is the description 
	for <strong>Page One</strong>.</p>
	</div>
	<div class="Position5">
	<p id="p2desc" class="Hidden">This is the description 
	for <strong>Page Two</strong>.</p>
	</div>
	<div class="Position6">
	<p id="p3desc" class="Hidden">This is the description 
	for Page <strong>Three</strong>.</p>
	</div>
	</div>

Example 2: Expanding and Collapsing Menu

For the second example, we will create a little expanding menu similar to one you can create using one the DHTML Wizards in Allaire HomeSite. In this demonstration, we will use the display: none property to hide the submenu items until the user clicks on the main item.

Since there is no unclick event corresponding to the onMouseOut event, we will need a slightly different event handler to toggle the style class changes. For the classToggle event-handler, we will pass the element id and two class names as parameters and then use the JavaScript conditional logic control structure to toggle the class names:

	function classToggle(element,class1,class2) {
		if (element.className==class1) {
			element.className = class2;
		}
		else if (element.className==class2) {
			element.className = class1;
		}
	}

So here is the demonstration, and the HTML code is shown below it:

Section (Click Me)
  • Item One
  • Item Two (Click Me Too)
    • SubItem One
    • SubItem Two
  • Item Three

Code:

	<div class="Position0">
	<strong onClick="classToggle(sub1,'DisplayNone','DisplayBlock')">
	Section (Click Me)
	</strong>
	<ul id="sub1" class="DisplayNone">
		<li>
		Item One
		</li>
		<li 
		onClick="classToggle(sub2,'DisplayNone','DisplayBlock')">
		Item Two (Click Me Too)
		</li>
		<ul id="sub2" class="DisplayNone">
			<li>SubItem One</li>
			<li>SubItem Two</li>
		</ul>
		<li>
		Item Three
		</li>
	</ul>
	</ul>
	</div>

Example 3: Multipage Content in a Single Page

We all know that most users would rather click than scroll, so web designers try when they can to confine contents to a single screen. One of the unfortunate side-effects is that the browser has to return a new HTTP request to the server for each of many little chunks of information. Using the DHTML visibility property, we can load these short chunks onto a single page, but display them as if they were a series of separate pages.

For this example, we'll cycle through 3 blocks of information -- you'll see that the logic could easily be extended to work with as many parts as you like. We will need a custom event-handler for the style class changes. We'll also need to set a global variable for a counter. We'll start the counter at 1. Then we will have a function that takes as parameters the two class names we'll be toggling, and also a flag that tells the function whether the user is trying to go forward or back. From that, we can use the incremented or decremented counter to determine whether we should be going to part 1, 2, or 3, and set the classes for the various parts accordingly:

	var pcount = 1;
	function goNext(oneClicked,class1,class2) {
		if (oneClicked=="prev") {
			if (pcount==1) {
				alert("This is the first part.")
			}
			else { 
				pcount = --pcount;
			}
		}
		else {
			if (pcount==3) {
				alert("This is the last part.")
			}
			else {
				pcount = ++pcount;
			}
		}
		switch (pcount) {
			case 1 :
			p1.className = class1;
			p2.className = class2;
			p3.className = class2;
			break;
			case 2 :
			p1.className = class2
			p2.className = class1;
			p3.className = class2;
			break;
			case 3 :
			p1.className = class2
			p2.className = class2;
			p3.className = class1;
			break;
		}
	}

Here then is our third working example, with the HTML code following:

This is the first part of the multipart content. Click the Previous and Next links to move back and forth between the parts.

Code:

	<div class="Position0">
		<div class="Position1">
		<a href="javascript:goNext('prev','Visible','Hidden')"
		id="prev"><strong>Previous</strong></a>
		</div>
		<div align="right" class="Position3">
		<a href="javascript:goNext('next','Visible','Hidden')" 
		id="next"><strong>Next</strong></a>	
		</div>
		<div class="Position7">
		<p id="p1" class="Visible">
		This is the <strong>first</strong> part 
		of the multipart content.  
		Click the <strong>Previous</strong>
		and <strong>Next</strong> links to move 
		back and forth between the parts.
		</p>
		</div>
		<div class="Position7">
		<p id="p2" class="Hidden">
		This is the <strong>second</strong> part 
		of the multipart content.  
		Click the <strong>Previous</strong>
		and <strong>Next</strong> links to move 
		back and forth between the parts.
		</p>
		</div>
		<div class="Position7">
		<p id="p3" class="Hidden">
		This is the <strong>third</strong> part 
		of the multipart content.  
		Click the <strong>Previous</strong>
		and <strong>Next</strong> links to move 
		back and forth between the parts.
		</p>
		</div>
	</div>

We now know how to use the display and visibility properties, and how to script against them to reveal information as it is needed, without having to go back to the server for a new page. As cross-browser DHTML becomes easier over the next year, you should expect to see these kinds of DHTML effects to be especially popular among web developers.