Revealing
the HiddenCSS 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 paragraph has class Hidden. It will
be visible in the source code, but appear as empty space
in the rendered page.
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 paragraph has class Hidden. It will
be visible in the source code, but appear as empty space
in the rendered page.
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;
}
This is the description
for Page One.
This is the description
for Page Two.
This is the description
for Page Three.
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)
- 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.
This is the second
part of the multipart content. Click the Previous
and Next links to move back and forth
between the parts.
This is the third
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.
|