<<< Exporting IP

Home

Tuesday, May 15, 2007 10:00 PM >>>


dynamic page sizing

Tuesday,  05/15/07  09:29 PM

This is a nerdy exposition, for those of you creating web apps and for me to be able to find it later :)

The subject is dynamically sizing web page elements based on the size of the browser window.  Usually when you are creating a web page on a server, you don’t know the size of the user’s browser window.  At the highest level, there are three things you can do, first, you can create pages which work no matter what, second, you can have the page tell the server the size of the window, and regenerate the page accordingly, or third, you can have JavaScript in the page which dynamically reconfigures the page contents.

The first solution is the best if you can get away with it, and this is what the vast majority of websites do today.  Most web content distributes itself in a reasonable way inside a browser window, regardless of the size of the window.  However there are cases where you really want to know the size – for example, you might have an array of thumbnails and you want the number of columns in the array to correspond to the width of the browser window.

The second solution works, but it is a bit klunky.  It requires that the page be generated with a URL which gives the browser window size.  If the browser’s window size changes, then you use an “onresize” event to send a new URL to the server, which generates a new page and sends it to the browser.  The advantage is that you can have all the logic for page generation on the server.  The disadvantage is that you have uglier URLs (not really a big deal), and you have to have an interaction with the server every time the page is resized (also not really a big deal).  There is one situation where this doesn’t work at all – when there is no server!  For example you may be creating pages for a stand-alone DVD.  In this situation all the logic for dynamic sizing must be done on the client.

The third solution is cleanest and accommodates the situation where there is no server.  However there is more complexity on the client side because of the JavaScript, so it may not always be the simplest solution.  The remainder of this email describes how this works.


Okay, let’s say you have a web page, and you want to dynamically adjust the content based on the browser window size.  How do you do this?

Well, first a brief digression into some JavaScript basics.  JavaScript can be embedded into any web page with <script> tags, like this:

      <script>
      ...a bunch of JavaScript code...
      </script>

You can also embed brief sections inline, like this:

      ...HTML stuff<script>...some JavaScript code...</script>more HTML stuff...

Wherever you put the <script> tags, the JavaScript inside will be executed “immediately”.

One of the powerful things you can do with JavaScript is you can output HTML.  You do this with the document.write() function.  The output of the document.write() goes right inline where the HTML is being processed.  For example:

      ...HTML stuff<script>document.write('HTML to be inserted')</script>more HTML stuff...

In this example “HTML to be inserted” will be inserted inline into the HTML.  This HTML can include tags, text, anything.  Here’s a little more complicated example:

<script>
function setfont(color)
{
document.write('<font size=5 color='+color+'>');
}
</script>

...

...<script>setfont('red')</script>this will be red</font>...

In this example we’ve defined a JavaScript function called setfont, which outputs an HTML font tag, using a color passed in as a parameter.  In the HTML the setfont function is called with a parameter of “red”, causing “<font size=5 color=red>” to be written inline into the HTML.

Okay, so that’s a bit about JavaScript.

Next, in order to do conditional stuff based on the size of the browser window, we have to know the size of the browser window.  So, how do we know that?  Well, here’s some JavaScript which figures it out…

<script>
var   width, height;

if (navigator.appName == "Microsoft Internet Explorer") {
      width = document.body.clientWidth;
      height = document.body.clientHeight;
} else {
      width = window.innerWidth;
      height = window.innerHeight;
}
</script>

This JavaScript code sets the variables width and height to the dimensions of the browser window in pixels.  (This finds the dimensions of the inside client area of the browser window, not including menu bars, status bars, borders, etc.  If the page content grows scroll bars, the scroll bars will be inside this area.)  You will note that the logic is slightly different depending on whether you are running in Internet Explorer or anything else.  There is a simple rule that applies to browsers, all browsers behave the same except Internet Explorer.  Unfortunately about 80% of the world uses Internet Explorer, so you have deal with two cases, Internet Explorer and everything else.  Thank you Microsoft.

So now that we know the width and height, how can we do something cool?  Well as an example, consider that table of image thumbnails.  The table has a certain number of columns, but the number will depend on the width of the browser window.  So you can do something like this:

<script>
var   width, height;

if (navigator.appName == "Microsoft Internet Explorer") {
      width = document.body.clientWidth;
      height = document.body.clientHeight;
} else {
      width = window.innerWidth;
      height = window.innerHeight;
}

var   col = 0;

function chkEOL()
{
if (col % parseInt(width / 200) == 0)
      document.write('</tr><tr>');
col = col+1;
}
</script>

...

<table...>
<tr>
<script>chkEOL()</script>
<td>...HTML to create first thumbnail...</td>
<script>chkEOL()</script>
<td>...HTML to create second thumbnail...</td>
<script>chkEOL()</script>
<td>...HTML to create third thumbnail...</td>
<script>chkEOL()</script>
<td>...HTML to create fourth thumbnail...</td>
...
</tr>
</table>

Okay, here’s what’s going on.  First, at the top we figure out the width and height of the browser window as before.  Then, a little function named chkEOL is defined.  Further down is the table itself.  It consists of a whole bunch of <td>…</td> sequences to generate the cells of the table for each thumbnail.  In between each cell is a JavaScript call to chkEOL.  This function uses a global variable named col to keep track of the current column number.  On each call it checks to see if the current column is an even multiple of “width / 200”, and if so it generates a “</tr><tr>” sequence to end the current row and start the next one.  This assumes that the columns are about 200 pixels wide, so if the browser window was 850 pixels wide, there would be four columns, and if the browser window was 1080 pixels wide, there would be five columns.  You could compute the column width instead of hard-coding 200, you get the idea.

Okay, so the main idea is that wherever you might want to generate some HTML dynamically, you make a JavaScript function call, and in the function you check to see what to do, and you can output HTML with document.write().

So this is great, it takes care of the initial layout of the page.  But what happens if the window is resized?  How do we handle that?  Well, it is amazingly easy.  Do this:

<body ... onresize='location.href=location.href'>

In the <body> tag, force a refresh of the page whenever the browser window is resized.  Setting location.href to itself is a portable way to force a refresh.  This causes everything to be reevaluated, and all the JavaScript will be reexecuted again, possibly yielding different results this time because the browser window size has changed.

Happy coding!