layouthandler - standards compilant 100% width and 100% height tableless web page layout template

layouthandler is an example how to create a web page that uses 100% screen space in web browser and validates against standards. If you have ever built a web page for a tool with fancy layout then you probably have struggled with <table width="100%" height="100%">. "width" part usually works but "height" on another hand usually has some problems. Very often the easiest way to make things work is to ignore the standards and remove the <!DOCTYPE> from page. The example is different. It is tested with Internet Explorer, Firefox and Google Chrome but it should work with other browsers.

Here is how it works.

If not already there, enter the <!DOCTYPE> into the page header as follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head>
    <title>Test Page</title>
</head>
<body>
    ...
</body>
</html>

Create page layout. For this example I am using classic layout:

Header/Banner/Main menu

Submenu

Content with autoscroll

Footer

Following table illustrates source code. The code is as clean as possible. Each key element has CSS class specified. No element has width or height specified in html code. <!-- html comments --> are placeholders where actual content would be.

<div class="BannerLayer">
    <!-- Header/Banner -->
</div>
<div class="MenuLayer">
    <!-- Submenu -->
</div>
<div class="ContentLayer">
    <!-- Content -->
</div>
<div class="BannerLayer">
    <!-- Footer -->
</div>
Create a style sheet. First we set the html and body elements to use all the space we have. It is important to remove all paddings, margins and borders because these have different defaults and are rendered differently in different browsers. We also hide scrollbars with overflow parameter.

html, body
{
    margin: 0px;
    padding: 0px;
    border: none;
    width: 100%;
    height: 100%;
    overflow: hidden;
}

Next we set up a BannerLayer CSS class. Important key is to make sure the height will never change depending on window size. For this we make sure that wrapping is turned off. The actual height is determined by the content inside and should not be specified here.

.BannerLayer
{
    white-space: nowrap;
    clear: both;
}

The BannerLayer class is used twice on provided html example. For both table rows the html code is actually exactly the same. There is no limit on how many rows like these there are.

Now we have the MenuLayer the place for submenu. There are two parameter we need to set for this class. The "width" in this case would need to be set. Another parameter is the overflow. There are two choices auto turns on the scrollbars if needed, hidden disables scrollbars completely. The height would use all available space but we do not specify this here.

.MenuLayer
{
    width: 160px;
    overflow: auto;
    float
: left;
}

And the last element is ContentLayer. This is the part of the page that would adjust the size to all available space. At this point it is a good idea to enable the scrollbars when needed.

.ContentLayer
{
    overflow: auto;
    float: left;
}

Now create the script that initializes the layout. This is most difficult part to describe. First we need to get the list of <DIV> elements from page. The code proposed here would be slightly slower compared to getElementById but it would be easier to use on ASPX pages for example.

var Layer = document.getElementsByTagName('div');

Now we need to find out how much available space we have:

var DynamicHeight = document.body.clientHeight;
var DynamicWidth = document.body.clientWidth;

Next we iterate through all <DIV> objects and calculate available space for each element with specified class name.

for (var i = 0; i < Layer.length; i++)
{
    ...
}

First we subtract all BannerLayer heights from available space. This means something like "content height" = "screen height" - "banner height" - "footer height".

if (Layer[i].className == 'BannerLayer')
    DynamicHeight -= Layer[i].offsetHeight;

Second we subtract all MenuLayer widths from available space. This means something like "content width" = "screen width" - "submenu width".

if (Layer[i].className == 'MenuLayer')
    DynamicWidth -= Layer[i].offsetWidth;

Now we know the size of ContentLayer this is the scrolling part of the page. Now we just set the sizes in pixels for each element. For BannerLayer we need to set the width to all available space on screen. We do not change the height.

if (Layer[j].className == 'BannerLayer')
    Layer[j].style.width = document.body.clientWidth + 'px';

For MenuLayer we need to set the height to all space left. The "width" is already set to 160px by style sheet.

if (Layer[j].className == 'MenuLayer')
    Layer[j].style.height = DynamicHeight + 'px';

And the last thing we set is the ContentLayer. It gets all the space left.

if (Layer[j].className == 'ContentLayer')
{
    Layer[j].style.width = DynamicWidth + 'px';
    Layer[j].style.height = DynamicHeight + 'px';
}

Last thing left to do is attaching the code to browser events and link the the script to the page. It would be good idea to delay execution of the script. This would minimize the impact while running it together with other scripts.

function DelayedInitLayout()
{
    self.setTimeout('InitLayout()', 1);
}

For Internet Explorer the syntax of attaching the event is different than other browsers.

if (window.addEventListener)
{
    window.addEventListener("load", DelayedInitLayout, false);
    window.addEventListener("resize", DelayedInitLayout, false);
}
else if (window.attachEvent) // ie
{
    window.attachEvent('onload', DelayedInitLayout);
    window.attachEvent('onresize', DelayedInitLayout);
}

To link the script and the style sheet we need to enter following code to <HEAD> of the page.

<script type="text/javascript" src="layouthandler.js"></script>
<link type="text/css" rel="Stylesheet" href="layouthandler.css" />

On ASPX page the location of the script can be calculated with VirtualPathUtility if used on MasterPage, or on base Page class.

<script type="text/javascript" src="<%=VirtualPathUtility.ToAbsolute("~/layouthandler.js")%>"></script>
<link type="text/css" rel="Stylesheet" href="<%=VirtualPathUtility.ToAbsolute("~/layouthandler.css")%>" />

To control if the submenu is visible or not (again on ASPX page) change the DIV element to run on server and set the visibility to false. This removes it from the output and releases the space to ContentLayer.

<div id="MenuLayer" class="MenuLayer" runat="server">

To set padding for a Layer use another DIV inside it and specify the style or class for the DIVs inside. Do not set the padding to the Layer DIV directly.

<div class="BannerLayer">
    <!-- Footer -->
        <div style="padding: 5px; ">
            Footer with 5 pixel padding
        </div>
    <!-- Footer -->
</div>

That is all.

Preview an example with 2 column layout
Preview an example with 3 column layout