The short answer: It's complicated. To really understand all the factors that affect CSS 100% heights (and widths) you'll need to know about terms such as: the view port, initial containing block, flow, overflow, inline formatting contexts, block formatting contexts, the W3C box model, the IE box model and Quirks Mode.
If you're really interested on getting on top of it there is no better place to start than the spec: The Visual Formatting Model
But here's an overview.
Heights on inline elements are calculated differently than block elements -- so from here on this only refers to block elements or elements which have been given new block formatting contexts.
To start with when you give an element 100% height, it will take it's height from it's containing block eg. it's parent and it's parent takes it's height from it's parent and so-forth back to the initial containing block.
The initial containing block is different in HTML (body) and XML/XHTML (html) and it's default height isn't 100% of the viewport so normally you would cover your butt and define it this way:
html, body {
margin:0;
padding:0;
height:100%;
}
We had to zero the margin and padding because in CSS the Height property refers to the height of the Content Box and if there was any margin or padding (or border) we'd get a scrollbar. The height would be 100% + padding + border + margin... W3C Box Model
The exception to this is if IE is in Quirks Mode... IE box model
...so unless you maintain this "100% height" through all descendant elements then you are redefining the meaning of "100% height" to each new descendant. This can also be affected by the creation of a new Block Formatting Context. You create new bock formatting contexts when you Float or Absolutely Position an element (as well as some other things)
About the height of Table cells...
People often ask "Why won't my Div with 100% height work in a table cell?".
This has to do with how a Table cell's height is calculated. When a cell is rendered the height of it's content box isn't stretched to match the height of the parent Row. The renderer instead adds extra padding as required so that the overall height matches the height of the Row. So in this example...
<tr>
<td>
line one<br>
line two<br>
line three
</td>
<td>
<div style="height:100%">
Hello world!
</div>
</td>
</tr>
...the height of the Div is 100% -- 100% of the cell's Content Box. The cell's content box was given extra padding so that it matched the overall height of the row. The Div's height is 100% of it's parents content box (not the overall height).
See Table height algorithms.
As this question seems to be asked almost daily I've check the Wiki check box -- I'm a newbie but presumable this will make it easier for others to make corrections and additions as needed.