#masthead{
border:1px dashed #333;
width:0;
position:absolute;
height:100px;
top:0;
} #left{
border:1px dashed #000;
width:252px;
} #center{
border:1px dashed #666;
margin:.5em 0 0 0;
padding:1em;
position:absolute;
top:100px;
}
In a multi-column layout where positioned elements are used, the content within the elements can become aesthetically unappealing and basically illegible when the user decreases the width of their browser window beyond your intended design. Given that the Windows® interface, by it's very design, is a multi-tasking environment only increases the probability that this will happen. The advent of multiple open windows, i.e.: email, word processor, spreadsheet, favorite browser, etc..., users will inevitably view your Web page at aspect ratios you may not have intended. Would not it be nice to allow the user to size the browser's width and and still read the content within your page?
Enter CSS2 and
the min-width property. With the min-width property
you can declare the minimum width of an element, such as a div,
thereby prohibiting ridiculous 20px wide columns, maintain an aesthetically
pleasing presentation and legible content. However, only a few browsers available
in my testing pool recognize the min-width property. Browser
compatibility at this time is limited to Netscape 7 (MAC and PC) and Mozilla
1.0 (Though, not part of my 'official' testing pool, Opera 7 beta is compatible.
I am unsure about earlier versions.)
To address this issue in standards-compliant browsers that do not yet recognize
the min-width property, we will use JavaScript to set minimum
widths for our column objects.
Before we get started, let's lightly address this issue when using the float
property. When using the floated elements to create a multi-column layout,
the right-hand floated elements will 'jump' below left-hand floated elements
when the right-hand floated elements can no longer decrease in width. This
results in your page not displaying as you have intended let alone the illegibility
of the text contained within such a narrow column. (Just one more reason I
simply avoid floats for creating a multi-column layout.)
I will not be providing visual examples of a browsers failure to render minimum widths. Provided that you are reading this lead me to believe that you are already all to familiar with this shortcoming. However, this very page is working example of this very lesson. If the width of this page falls below 890 pixels, the center column (the one containing this very text) will cease to condense. Contrarily, as the page widens beyond 890 this column widens, illustrating a dynamic yet minimum width.
Let's get started! Using this page as our example, our goal is to have this
column, the center column, size dynamically in width yet never drop below
305px in width, regardless of actual window width. The left column object
is fixed at 252px including padding, borders and margins. No width is declared
for the remaining div objects as we are using JavaScript to declare
it for us as explained in the dynamic widths
tutorial.
As with the dynamic width solution this solution addresses workarounds for browser misinterpretation of object widths. See Box Model Hack for further explanation about browser width misinterpretation.
It may look like a lot of code, however, you will find that we are simply addressing the same document objects multiple times. Once to get it's value and again to send it a new value.
window.onresize = findWindowDim;
function findWindowDim(){
var dbcW = document.body.clientWidth;
var objLeft = document.getElementById('left');
var objMasthead = document.getElementById('masthead');
var objCenter = document.getElementById('center');
var objRight = document.getElementById('right');
var objLinks = document.getElementById('links');
var leftWidth = document.getElementById('left').offsetWidth;
var mastheadXPosPx = leftWidth+"px";
objMasthead.style.left = mastheadXPosPx;
var centerXPosPx = leftWidth+"px";
objCenter.style.left = centerXPosPx;
if (dbcW){
mastheadWidth = dbcW-leftWidth;
if (mastheadWidth < 507){
objMasthead.style.width = '507px';
}
else{
mastheadWidthPx = mastheadWidth+"px";
objMasthead.style.width = mastheadWidthPx;
}
centerWidth = parseInt(.64*dbcW-leftWidth);
if (centerWidth < 305){
objCenter.style.width = '305px';
newCenterWidth = objCenter.offsetWidth;
}
else{
centerWidthPx = centerWidth+"px";
objCenter.style.width = centerWidthPx;
newCenterWidth = objCenter.offsetWidth;
}
rightX = newCenterWidth+leftWidth;
rightXPosPx = rightX+"px"
objRight.style.left = rightXPosPx;
objLinks.style.left = rightXPosPx;
rightWidth = dbcW-leftWidth-newCenterWidth;
if (rightWidth < 240){
objRight.style.width = '240px';
objLinks.style.width = '240px';
}
else{
rightWidthPx = rightWidth+"px";
objRight.style.width = rightWidthPx;
objLinks.style.width = rightWidthPx;
}
}
var leftHeight = document.getElementById('left').offsetHeight;
var centerHeight = document.getElementById('center').offsetHeight;
var rightHeight = document.getElementById('right').offsetHeight;
var linksHeight = document.getElementById('links').offsetHeight;
var mastheadHeight = document.getElementById('masthead').offsetHeight;
var objFooter = document.getElementById('footer')
if (document.body.clientHeight > 200){
function hideError() {
return true;
}
window.onerror = hideError;
linksY = rightHeight + mastheadHeight;
linksYPosPx = linksY+"px";
objLinks.style.top = linksYPosPx;
}
var wiW = window.innerWidth;
if (window.setCursor && (wiW)){
mastheadWidth = wiW-leftWidth;
if (mastheadWidth < 507){
objMasthead.style.width = '507px';
}
else{
mastheadWidthPx = mastheadWidth+"px";
objMasthead.style.width = mastheadWidthPx;
}
centerWidth = parseInt(.64*dbcW-leftWidth);
if (centerWidth < 305){
objCenter.style.width = '305px';
newCenterWidth = objCenter.offsetWidth;
}
else{
centerWidthPx = centerWidth+"px";
objCenter.style.width = centerWidthPx;
newCenterWidth = objCenter.offsetWidth;
}
rightX = newCenterWidth+leftWidth;
rightXPosPx = rightX+"px"
objRight.style.left = rightXPosPx;
objLinks.style.left = rightXPosPx;
rightWidth = wiW-leftWidth-centerWidth-20;
rightWidthPx = rightWidth+"px";
if (rightWidth < 240){
objRight.style.width = '240px';
objLinks.style.width = '240px';
}
else{
rightWidthPx = rightWidth+"px";
objRight.style.width = rightWidthPx;
objLinks.style.width = rightWidthPx;
}
}
if (window.setCursor && (window.innerHeight > 200)){
function hideError() {
return true;
}
window.onerror = hideError;
linksY = rightHeight + mastheadHeight;
linksYPosPx = linksY+"px";
objLinks.style.top = linksYPosPx;
}
}
<body onload="findWindowDim">
The CSS used in conjunction with this can be found at the top of each object on this page.
We need to run the function findWindowDim() anytime the user resizes their browser window. The onresize event handler will handle this for us.
window.onresize = findWindowDim;
Start the function and declare a list of variables.
function findWindowDim(){
Document.body.clientWidth finds the width of the browser window for IE, Mozilla and Netscape 7.
var dbcW = document.body.clientWidth;
Creating some shorthand variables for the DOM
var objLeft = document.getElementById('left');
var objMasthead = document.getElementById('masthead');
var objCenter = document.getElementById('center');
var objRight = document.getElementById('right');
var objLinks = document.getElementById('links');
Get the width of our fixed column. Even though we know the width of the fixed column to be at 252px as stated in the CSS, settling for this width would introduce the problem of using a browsers CSS interpretation of widths. Telling the browser via the JavaScript to determine the width makes up for this problem, as it allows for the JavaScript driven CSS to be flexible to each browsers interpretation - or misinterpretation - of widths. We will continue this logic throughout the script.
var leftWidth = document.getElementById('left').offsetWidth;
Set the left position of the masthead and center objects. The first line concatenates "px" to the value so the second line can correctly set the objects new style value. Again, even though we know the left value of the 2 absolute positioned objects, we use the browsers JavaScript interpretation of the left column width determine their left position.
var mastheadXPosPx = leftWidth+"px";
objMasthead.style.left = mastheadXPosPx;
var centerXPosPx = leftWidth+"px";
objCenter.style.left = centerXPosPx;
The 'if statement' to tell us which browsers to address. We'll address DOM compliant browsers, not Netscape 6, first.
if (dbcW){
Dynamically size the width of the masthead column by subtracting the left column from the browser's window width. In Concatenate the value with "px" and set the style with our abbreviated DOM. This process is repeated for each column to be sized.
mastheadWidth = dbcW-leftWidth;
We now set the minimum width for the masthead.
if (mastheadWidth < 507){
objMasthead.style.width = '507px';
}
If the masthead width exceeds 507px, then size the masthead to fit the remaining width of the page.
else{
mastheadWidthPx = mastheadWidth+"px";
objMasthead.style.width = mastheadWidthPx;
}
Set the width of the center column. I want center column to be 64% of the browser's window width minus the width of the left column. Parsing this number rounds the value to a whole number, though this is not required. Altering the equation used to define centerWidth will allow you to set the width as a percent or even fixed in width. Play with it and have some fun.
centerWidth = parseInt(.64*dbcW-leftWidth);
if (centerWidth < 305){
objCenter.style.width = '305px';
Just as we set the new width of the center column, we need to get the new width back - newCenterWidth - so we can use it later.
newCenterWidth = objCenter.offsetWidth;
}
Again, telling the object to expand once it's width exceeds the set minimum width and setting a value to newCenterWidth.
else{
centerWidthPx = centerWidth+"px";
objCenter.style.width = centerWidthPx;
newCenterWidth = objCenter.offsetWidth;
}
Lastly, we need to position and set the widths of our last column which contains 2 objects: right and links. Since links has the same left and width values of right, we set link's values equal to right's.
rightX = newCenterWidth+leftWidth;
rightXPosPx = rightX+"px"
objRight.style.left = rightXPosPx;
objLinks.style.left = rightXPosPx;
rightWidth = dbcW-leftWidth-newCenterWidth;
if (rightWidth < 240){
objRight.style.width = '240px';
objLinks.style.width = '240px';
}
else{
rightWidthPx = rightWidth+"px";
objRight.style.width = rightWidthPx;
objLinks.style.width = rightWidthPx;
}
}
**********************************************************************
The following code is used to keep the footer at the bottom of the page. This
is explained in the dynamic heights article.
The minimum width code for Netscape 6 follows this block of code.
var leftHeight = document.getElementById('left').offsetHeight;
var centerHeight = document.getElementById('center').offsetHeight;
var rightHeight = document.getElementById('right').offsetHeight;
var linksHeight = document.getElementById('links').offsetHeight;
var mastheadHeight = document.getElementById('masthead').offsetHeight;
var objFooter = document.getElementById('footer')
if (document.body.clientHeight > 200){
function hideError() {
return true;
}
window.onerror = hideError;
linksY = rightHeight + mastheadHeight;
linksYPosPx = linksY+"px";
objLinks.style.top = linksYPosPx;
}
End dynamic height script.
**********************************************************************
We need to repeat the entire process for Netscape 6. The property window.setCursor is exclusive to Netscape 6 and including it within the 'if statement' will filter our Netscape 7/Mozilla 1 which also recognize window.innerWidth.
var wiW = window.innerWidth;
if (window.setCursor && (wiW)){
mastheadWidth = wiW-leftWidth;
etc.......
On load of the page, we need to run the function to set all of the objects in place.
<body onload="findWindowDim">
You now posses the knowledge to create pages that will always remain legible
regardless of how the user sizes their browser window. No more columns of
text that
stream
down
the
page
one
word
at
a
time.
No more floated columns that jump to the bottom of the page when the column
can no longer decrease in width. And more columns that overlap each other
because of relative positioning. Have fun.
Comments? I'd love to hear from you. tj@spinwebdesign.com.
[an error occurred while processing this directive]#right{
border:1px dashed #999;
margin:.5em 0 0;
padding:1em 0 1em 1em;
position:absolute;
top:100px;
} #links{
border:1px dashed #CCC;
margin:.5em 0 0;
padding:1em 0 1em 1em;
position:absolute;
}