javascript : void(0)

You see "javascript:void(0)" all over the place, especially as the href value for a link that uses the onclick event for functionality.  Ever wondered exactly what this line of javascript does? 

According to the MSDN JScript 8.0 Reference,

"The void operator evaluates its expression, and returns undefined. It is most useful in situations where you want an expression evaluated but do not want the results visible to the remainder of the script."

As an added bonus, here are some more client-side references (from w3schools):

HTML 4.01 Entities Reference
HTML URL-encoding Reference

posted by snyholm with 1 Comments

Simple Exceptions

We all know to organize our try…catch blocks with the most specific exceptions first, right?  Right???  Of course!  (Recommended reading: Exception Management Architecture Guide and Best Practices for Handling Exceptions.)

But how do you actually tell which exceptions are more specific?  Look up the inheritance hierarchy of the exception classes.

You could use the object browser:

Or the MSDN (.NET Framework Class Library Online Reference):

How do you tell which exceptions you need?  Look up the .NET FCL classes in the MSDN .NET Framework Class Library Online Reference.  The class description usually tells you which exceptions to watch for.  For example, the "The HttpWebRequest class throws a WebException when errors occur while accessing a resource."

Here's a quick code example.  Now, you only want to include the exceptions that could actually occur in your code.  I put a lot of exceptions in here just to make a point.

public static string DownloadFileContents(string fileUrl)
{
    string contents = null;
    StreamReader reader =
null;
    HttpWebRequest webRequest;
    HttpWebResponse webResponse =
null;

    try 
    {
        webRequest = WebRequest.Create(fileUrl)
as HttpWebRequest;
        if (webRequest != null)
        {
            webResponse = webRequest.GetResponse()
as HttpWebResponse;
            if (webResponse != null)
            {
                reader =
new StreamReader(webResponse.GetResponseStream());
                contents = reader.ReadToEnd();
            }
        }
    }

    // inheritance hierarchy = WebException : InvalidOperationException : SystemException : Exception 
    // this will catch all unhandled exceptions that are of type WebException or inherit from it
    catch
(System.Net.WebException ex)
    {
        //Log and handle exception
    }

    // inheritance hierarchy = InvalidOperationException : SystemException : Exception 
    // this will catch all unhandled exceptions that are of type InvalidOperationException or inherit from it
    catch (System.InvalidOperationException ex)
    {
        //Log and handle exception
    }

    // inheritance hierarchy = SecurityException : SystemException : Exception 
    // this will catch all unhandled exceptions that are of type SecurityException or inherit from it
    catch
(System.Security.SecurityException ex)
    {
        //Log and handle exception
    }

    // inheritance hierarchy = ArgumentException : SystemException : Exception
    // this will catch all unhandled exceptions that are of type ArgumentException or inherit from it
    catch
(ArgumentException ex)
    {
        //Log and handle exception
    }

    // inheritance hierarchy = OutOfMemoryException : SystemException : Exception
    // this will catch all unhandled exceptions that are of type OutOfMemoryException or inherit from it
    catch
(OutOfMemoryException ex)
    {
        //Log and handle exception
    }

    // inheritance hierarchy = SystemException : Exception
    // this will catch all unhandled exceptions that are of type SystemException or inherit from it
    catch
(System.SystemException ex) 
    {
        //Log and handle exception
    }

    // inheritance hierarchy = Exception
    // this will catch all unhandled exceptions

    catch (Exception ex) 
    {
        //Log and handle exception
    }

    finally 
    {
        if (reader != null
        {
            reader.Close();
        }
        if (webResponse != null
        {
            webResponse.Close();
        }
    }

    return contents;
}

posted by snyholm with 0 Comments

New Microsoft Developer Certs: MCTS, MCPD, MCITP... replacing MCAD, MCSD, MCDBA

With the release of ASP.NET 2.0 and SQL Server 2005, Microsoft released a new series of certificates and… new acronyms.  Here we go for another round on the certification treadmill.  I’ve been on that treadmill a few times…  MCSD on .NET, MCAD, MCSD on VB6, MCDBA, and even an MCP+SB!  The Microsoft Learning website is a good starting point for looking into the certification maze.  I took a look through the new tests and the new acronyms.  For most web developers getting their first certification, this looks like a good order to take the tests en-route to the premier MCPD Enterprise Applications Developer. (upgrade paths are at the bottom)

Fresh Certification Path

1. MCP - Passing any one test will get you the MCP certification.  Why not start with the foundation test?

Exam 70–536: TS: Microsoft .NET Framework 2.0 - Application Development Foundation

2. MCTS:Web - Then take this test to get the Technology Specialist: .NET Framework 2.0 Web Applications certification:

Exam 70–528: TS: Microsoft .NET Framework 2.0 - Web-Based Client Development

3. MCPD:Web - <optional> To quickly get another acronym, take this test to add the Professional Developer: Web Developer certification:

Exam 70-547: PRO: Designing and Developing Web Applications by Using the Microsoft .NET Framework

4. MCTS:Distributed - Then take this one test to add the Technology Specialist: .NET Framework 2.0 Distributed Applications certification:

Exam 70–529: TS: Microsoft .NET Framework 2.0 - Distributed Application Development

5. MCTS:Win - Then take the next test to add the Technology Specialist: .NET Framework 2.0 Windows Applications certification:

Exam 70–526: TS: Microsoft .NET Framework 2.0 - Windows-Based Client Development

6. MCPD:Enterprise - Finally, add this test for the premier Professional Developer: Enterprise Applications Developer certification:

Exam 70–549: PRO: Designing and Developing Enterprise Applications by Using the Microsoft .NET Framework

SQL Server

SQL Server elective tests were not included in this round of developer certification.  In fact, no "elective" tests were included.  There is a separate certificate for SQL Server. 

MCTS:SQL - Passing this test will get you the Technology Specialist: SQL Server 2005  certification:

Exam 70–431: TS: Microsoft SQL Server 2005 - Implementation and Maintenance

MCITP:SQL Dev - Then add these two tests for the IT Professional: Database Developer certification:

Exam 70–441: PRO: Designing Database Solutions by Using Microsoft SQL Server 2005 Open License 6.0

Exam 70–442: PRO: Designing and Optimizing Data Access by Using Microsoft SQL Server 2005

There are two other paths for SQL Server certification: MCITP:DBA and MCITP:Business Intelligence Developer (data warehousing). 

Other Certs

There are also cert paths for MCTS:Mobile (1 test), MCTS:BizTalk (1 test), MCTS:Office Live Communications Server (1 test), and MCPD:Win (1 more test). 

Upgrade Paths

Upgrade or start over?  What tests do you take for the new certs if you have already passed some .NET 1.0 certification exams?  Well, that's going to be your decision.  Take some pride in the fact that you're already certified on the .NET 1.0 platform, so adding .NET 2.0 certification will show breadth of skills, ability to learn, and the motivation to stay current in your skills.

You may decide that you want to review all of the material and take all of the exams for the new certs... or you can take a pragmatic approach and get the new certs using the upgrade exams.  If this describes you, count the total # of tests you'd need for each approach and take the approach with the fewer tests.  If you're an acronym collector, use the approach that will give you the most certifications. 

Here are the upgrade paths:

MCTS:Web - exam 70-551, upgrade from MCAD

MCTS:Win - exam 70-552, upgrade from MCAD

MCPD:Enterprise - exams 70-553 & 70-554, upgrade from MCSD (yes that is 2 tests to upgrade your MCSD)

MCITP:DBA - exam 70-447, upgrade from MCDBA

posted by snyholm with 3 Comments

Javascript - capturing onsubmit when calling form.submit()

I was recently asked: "Why doesn't the form.onsubmit event get fired when I submit my form using javascript?" 

The answer: Current browsers do not adhere to this part of the html specification.  The event only fires when it is activated by a user - and does not fire when activated by code.

The W3C Document Object Model (DOM) Level 2 HTML Specification says that submit() "submits the form. It performs the same action as a submit button."

However, this browser non-compliance is documented in the DOM Level 2 HTML Issues List.  The Resolution: "Unfortunately, given the differences between implementations, it was not possible to find a common ground on this issue. No changes were in the specification. You cannot rely on having an event when invoking the submit() method."

The Mozilla Client-Side JavaScript Reference says that onsubmit "Executes JavaScript code when a submit event occurs; that is, when a user submits a form."  Notice that it says user action... this excludes javascript code.  (This appears to be the same as the Netscape/Sun reference.)
 
The
Microsoft reference is more explicit, "The submit method does not invoke the onsubmit event handler."

More references:

Many people have written on this topic, including codestore and alexking

ASCII Lookup Table (by the way, ASCII stands for American Standard Code for Information Interchange)

Discussion of capturing the ASCII key code value pressed in Firefox and Internet Explorer 6

Here is a quick code example that demonstrates one workaround for this problem:

<form id="searchForm" name="searchForm" method="get" onsubmit="return validateMyForm()">
<!--
Associate the onsubmit event handler with a javascript validation function.
This function will return a boolean value. This return value determines whether the form is submitted or not.
-->

<label>Search: </label><input name="textboxSearch" id="textboxSearch" maxlength="128" type="text" />

<select name="selectFilter" id="selectFilter" onkeypress="return handleKeystroke(event)">
<option selected value="First">First</option
>
<option value="Second">Second</option
>
<option value="Third">Third</option
>
<option value="Fourth">Fourth</option
>
<option value="Fifth">Fifth</option
>
</
select
>
<!--
Associate the onkeypress event with a javascript function, passing in the event object.
This function will attempt to submit the form if the Enter key is pressed.
-->

<input class="submitButton" type="submit" value="Go" title="Go" />

</form>

<SCRIPT language="JavaScript">

//This function handles the onkeypress event.
//If the Enter key is pressed, it attempts to submit the form.
function handleKeystroke(e)
{
    var keyPressed;

    //Browser compatibility check
    if (document.all) 
    {
        //Browser used: Internet Explorer 6
        keyPressed = e.keyCode;
        alert(
'handleKeystroke: IE property: keyCode');
   
   
else 
    {
        //Browser used: Firefox
        keyPressed = e.which;
        alert('handleKeystroke: FF property: which');
    }
    alert('handleKeystroke: key=' + keyPressed);

    //13 = ASCII code for Enter key
    if (keyPressed == 13) 
   
        alert('handleKeystroke: pressed Enter');
        //Directly calling document.searchForm.submit() will not fire the form's onsubmit event handler.
        //Call a javascript helper funtion that simulates that event.
        submitMyForm();
   
    else 
    {
        alert('handleKeystroke: pressed another key');
    }
}

//This function performs validation and any other pre-form-submit tasks.
//The form will only be submitted if this function returns true.
function validateMyForm()
{
    var isValid = confirm('Do you want to submit the form?');
    alert(
'validateMyForm: isValid = ' + isValid);
    return isValid;
}

//This function simulates the onsubmit event handler.
//This function should be called by javascript code instead of document.MyFormName.submit().
function submitMyForm()
{
    //first, call the same validation function used in the form.onsubmit event handler
    var thisresult = validateMyForm();
    alert(
'submitMyForm: validateMyForm returned: ' + thisresult);

    //if the function returned true, submit the form
    if (thisresult) 
    {
        alert(
'submitMyForm: javascript will submit form');
        document.searchForm.submit();
    }
}

</SCRIPT>

 

posted by snyholm with 3 Comments

Javascript trick: closing a Firefox tab

Find out that the plain ol' window.close() doesn't actually close the window if the window is a tab in Firefox?  Basically, it doesn't consider the tab to be opened by script... so you need to trick the browser into thinking that hte page was opened by script, then close it.  Interwebby.com came up with this nifty workaround:

<script language="javascript" type="text/javascript">
function closeWindow() {
   window.open('','_parent','');
   window.close();
}
</script>

 

posted by snyholm with 3 Comments

AMAZING CSS website

http://www.stunicholls.myby.co.uk/

I ran across this website while debugging a horizontal navigation menu that used <LI> elements to hold the data and CSS to apply the horizontal formatting.  The old menu was great - but we needed to modify it to support RTL.  When we flipped the page, the menu didn't flip with it. :-(  Thanks to this webreference tutorial for a reference to that AMAZING CSS website!  And the answer to today's puzzle. 

Along the way, I also picked up this reference that explained the padding/margin property shortcuts.  As well as one of those simple box pictures to remind you exactly where the margin, padding, border and content really sit. 

And this reference for browser-specific CSS hacks and references to interesting websites like browser stats for the internet (81% for IE6 and 10% for Firefox), an archive of installers for old versions of browsers, and this tool for sending you screenshots of your website as viewed by different browsers & platforms

posted by snyholm with 5 Comments

Web.config: "&" Error

The other day, I tried to debug my code (F5).  But the code would not run.  I was getting this message in a dialog box:

Error while trying to run project: Unable to start debugging on the web server. Server side-error occurred on sending debug HTTP request.

Make sure the server is operating correctly. Verify there are no syntax errors in web.config by doing a Debug.Start Without Debugging. You may also want to refer to the ASP.NET and ATL Server debugging topic in the online documentation.

OK, so I start the project without debugging (CTRL + F5).  I just get a vague error that locates the problem in my web.config app settings.  Some people get the message that the expected token is 'SEMICOLON'.  Turns out, the error was caused by having a ampersand ("&") in the setting value. 

<add key="Setting3" value="Value3 & Value3.1" />

This was easily fixed by HTML-encoding the ampersand:

   <add key="Setting3" value="Value3 &amp; Value3.1" />

When would you get this error?  A common example is a setting that stores a URL with querystring values:

<add key="MyUrl" value="http://www.mysite.com/myapp/mypage?value1=abc&value2=xyz" />

For more web.config errors, check out this MSDN Support Topic:
INFO: Common Errors When You Debug ASP.NET Applications in Visual Studio .NET

The application error went a little something like this:



Server Error in '/MyWebApp' Application


Configuration Error

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: An error occurred while parsing EntityName. Line 8, position 45.

Source Error:


Line 6:          <add key="Setting1" value="Value1.1" />
Line 7:          <add key="Setting2" value="Value2 or 2.1" />
Line 8:          <add key="Setting3" value="Value3 & Value3.1" />        
Line 9:          <add key="Setting4" value="Value4" />        
Line 10:         <add key="Setting5" value="Value5" /> 


Source File: C:\metro\v2.4\ESD\Src\DP Test Harness\TestMetroAddToLocker\web.config    Line: 8

 

posted by snyholm with 4 Comments

Keyboard Shortcuts Reference

If you like keyboard shortcuts, you'll love this handy reference: http://www.seoconsultants.com/windows/keyboard/

For example, here's one I didn't know before:

[Windows Key] + [Pause/Break] opens the System Properties dialog box (aka My Computer Properties). 

Here's another great resource:

http://www.codinghorror.com/blog/archives/000378.html

posted by snyholm with 0 Comments

Scroll clickey in Visual Studio 2005

It's the little things in life...

One nice feature of the Visual Studio 2005 IDE is the improved ability to handle windows.  You can still tile horizontally and vertically as with previous versions.  They added more features to the file tab's context menu.  They also added the ability to close a window without needing to click the little "X" or selecting "Close" from the context menu.  Simply click on the file tab with the scroll button.  Yes, press the middle wheel button... and poof!  The window is closed. 

posted by snyholm with 0 Comments

ASP.NET caching

There are a lot of good articles and tutorials about caching out there.  Here are some notes I've been saving on the topic...

On a very simple level, there are two methods of caching:

  • Output Cache for storing frequently requested pages
  • The .NET Cache API for storing arbitrary data

Output Cache

Output caching is extremely fast.  However, when using output caching, the code-behind is not re-run for each request.  Dynamic data will not be displayed.  The server saves a copy of the fully built page (response) and will return that saved copy for each request.  You can use parameters to generate a set of cached pages/controls.  For example, if you have a querystring parameter with 5 different values, you can set up output caching to save those 5 pre-rendered pages.  Output caching is typically declared in the markup.

<%@OutputCache Duration="240" VaryByParam="none" %>
<%@OutputCache Duration="240" VaryByParam="GetOrPostVariableName" %>

.NET Cache API

The Cache API is very versatile and lets you cache data from your code.  The typical formula for caching is:

  1. Get data from cache
  2. If no data was returned, get the data from the resources (database query, file access, etc.) and store the data in cache

// Check to see if the value is cached
string cachedValue = HttpContext.Current.Cache["CacheKey"] as String;
if (cachedValue != null && cachedValue != string
.Empty)
{
     // Perform the resource intensive operation 
     cachedValue = GetValue();


     // Insert the value into cache
     HttpContext.Current.Cache.Insert("CacheKey", cachedValue, null
, DateTime.Now.AddMinutes(240), TimeSpan.Zero);
}
// Use cachedValue

Application object

Another option for caching is to use the Application object, a common trick from “Classic ASP”.  However, using the cache API will provide you with more features. 

So when do you use cache?  

  • If data can be used more than once
  • If data is general rather than specific to a given request or user
  • If the data is user- or request-specific, but is long lived

Why would you want to avoid using cache?

  • To prevent out of memory errors.

For performance, you can generally consider there are four basic hardware categories: processor (% utilization), memory (# of bytes to # of available bytes), disk (input/output time), network bandwidth (input/output time).  Your servers have finite resources in each of these categories.  Caching reduces the dependence on slow resources (disk and network) and increases the dependence on fast resources (memory).  Thus, if you use too much caching, your server can run out of memory.  Generally on an x86 machine, you want to run a process with no higher than 800MB of private bytes in order to reduce the chance of an out-of-memory error.

What are some advanced caching tips?

  • Cache supports expiration dependencies that can force invalidation. These include time, key, file, and database (added in 2.0).  You can create custom cache invalidators. 
  • Dynamically loading output cached controls 
  • If you use session state in a page that has output caching enabled, and if the application runs on IIS 6.0, then you need to turn off kernel-mode output caching
  • Adding an application-wide bypassCache setting that will allow you to easily turn caching off
  • Preventing race conditions while loading cache in a high-load application

This code snippet adds bypassCache and race condition checks:

// Check to see if we are using caching and if the value is cached
string cachedValue = HttpContext.Current.Cache["CacheKey"] as String;
if (bypassCache || (cachedValue != null && cachedValue != string
.Empty))
{
     // Check to see if we are currently caching this item
     If (isCachingInProgress)
     {
          System.Threading.Thread.Sleep(1000);
          // Try again
     }
    
else
    
{
         
// Perform the resource intensive operation 
          // (inside this operation, set isCachingInProgress to true when starting and false when finishing) 
          cachedValue = GetValue();

         
// Insert the value into cache
         
HttpContext.Current.Cache.Insert("CacheKey", cachedValue, null
, DateTime.Now.AddMinutes(240), TimeSpan.Zero);
     }
}
// Use cachedValue

References
ASP.NET Caching
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspnet/html/asp04262001.asp

ASP.NET Caching: Techniques and Best Practices
http://msdn.microsoft.com/asp.net/reference/state/default.aspx?pull=/library/en-us/dnaspp/html/aspnet-cachingtechniquesbestpract.asp

Caching with ASP.NET
http://aspnet.4guysfromrolla.com/articles/022802-1.aspx

10 Tips for Writing High-Performance Web Applications
http://msdn.microsoft.com/msdnmag/issues/05/01/ASPNETPerformance/

Keep Sites Running Smoothly By Avoiding These 10 Common ASP.NET Pitfalls
http://msdn.microsoft.com/msdnmag/issues/06/07/WebAppFollies/

Output Caching – VaryByCustom attribute
http://vertigoblogs/liam/archive/2005/08/03/1290.aspx

Peter A. Bromberg demonstrates that the Application object is a high-performing method of caching.  Application vs. Cache Class Speed Tests
http://www.eggheadcafe.com/articles/20030405.asp

Accessing ASP.NET Cache from multiple threads
http://www.dotnet247.com/247reference/msgs/56/283604.aspx

 

posted by snyholm with 0 Comments

Globalization & Localization: RTL

I was recently asked to provide a proof of concept to show how a website could be modified to support RTL display (Right-To-Left).  Most US websites use a LTR (Left-To-Right) layout of the page, so they can easily be read by LTR-reading users.  With the right architecture and design, a web app can support RTL-reading users in widely known RTL languages (scripts) such as Hebrew or Arabic. 

The website can be changed to RTL layout by making the following changes:

  • Update the HTML element with the DIR="RTL" attribute setting.  This setting changes most of the page to RTL.  No other attributes need this setting because they will inherit from the HTML element.  Only specify other elements if they need to override the HTML element’s setting.
  • Fix layout issues caused by explicitly set right or left alignment in CSS or html element attributes.  CSS attributes I needed to fix included align, clear and float.
  • Replace images with RTL-directional images.  Note that truly bi-directional images do not need to be replaced.
  • Change the language (script) of the verbiage on the page.  Browsers automatically render certain languages LTR or RTL based on the Unicode algorithm.  Displaying English on an RTL page will result in text that flows backwards to the UI layout.  Also notice that ending punctuation is affected by the RTL attribute setting.
  • Fix other alignment issues.


References

An example RTL page: http://ar.wikipedia.org/wiki/Sandbox
Compare with http://en.wikipedia.org/wiki/Main_Page

MSDN: How to: Display Right-to-Left Text Using HTML Tags for Globalization
http://msdn2.microsoft.com/en-us/library/twe16yc2.aspx

MSDN: direction Attribute | direction Property
http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/properties/direction_1.asp

BDO tag. BDO stands for 'bidirectional override'. This inline element can be used to override the Unicode bidirectional algorithm if the dir attribute doesn't produce the desired result or if you want to produce a different result.  BDO can only be used with inline text.  It does not work to wrap the body content in a BDO tag.
Example: <bdo dir="rtl" style="border:solid 1px red">RIGHT TO LEFT TEXT</bdo> would display as: TXET TFEL OT THGIR.
http://www.w3schools.com/tags/tag_bdo.asp
http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/objects/bdo.asp

W3C FAQ: Script direction and languages
http://www.w3.org/International/questions/qa-scripts

W3C: Authoring Techniques for XHTML & HTML Internationalization: Handling Bidirectional Text 1.0
http://www.w3.org/TR/i18n-html-tech-bidi/

Right-To-Left Text in Markup Languages
http://www.i18nguy.com/markup/right-to-left.html

 

General localization resources:

Web Site Localization in ASP.NET v1.1
http://vertigoblogs/swarren/articles/1343.aspx

Localization in .NET 2.0
http://vertigoblogs/liam/archive/2005/10/21/1553.aspx

Microsoft Global Development and Computing Portal
http://www.microsoft.com/globaldev/default.mspx

Globalization issues in ASP, ASP.NET 1.0 and ASP.NET 2.0
http://support.microsoft.com/default.aspx?scid=kb;en-us;893663&sd=rss&spid=6351

posted by snyholm with 0 Comments

Simple XML read

So you need to read a value from an XML file…  C’mon, XML and XPath aren’t difficult at all! 

1. Load the XML data into an XmlDocument object using the Load method.  You can load the XML from a document referenced by URL.

2. Write an XPath query to access the value you want. 

3. Put the value into an XmlNode object using this method xmlDocument.SelectSingleNode(XPathQuery).

4. Finally, access the value with the xmlNode.Innertext property. 

p.s. Consider caching your XML data to improve performance.


Here are some cool XPath resources:

http://www.w3schools.com/xpath/xpath_syntax.asp

MSDN topic: XPath Examples

(locally installed .NET 1.x MSDN reference)
ms-help://MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.WIN32COM.v10.en/xmlsdk/html/1431789e-c545-4765-8c09-3057e07d3041.htm
MSDN Library | Win 32 and COM Development | XML | MSXML | XML Standards Reference | XPath Reference | XPath Syntax | XPath Examples

(online .NET 2.0 MSDN reference)
http://msdn2.microsoft.com/en-us/library/ms256086.aspx
MSDN Library | .NET Development | General Reference | XML Standards Reference | XPath Reference | XPath Syntax | XPath Examples

posted by snyholm with 1 Comments

Debugging IndexOf

Ever get this annoying error in the command window?  Are you getting it even when you are positively, 100% sure that the syntax is correct? 

error: managed EE does not understand expression's syntax

According to this thread, in some versions of Visual Studio, the debugger does not support string methods like IndexOf.  So here's a little hack/trick... you can assign the value of the string method to a local variable and look at the value of that local variable in the debugger after assignment.  Check out this example: 

...
int
i = stringBeingSearched.IndexOf(stringToFind);
if (stringBeingSearched.IndexOf(stringToFind) < 0)
...

posted by snyholm with 0 Comments

Bottom Aligned Text on a Web Page

If you need to make some bottom-aligned content in your web page and you're using a table-based layout, the tfoot element is pretty cool.  Site Experts gives a good demonstration of how it works.  Here's a quick example:

<table height="100%">

    ...

    <tfoot valign="bottom">
    
    <tr align="center" valign="bottom">
            <td align="center" valign="bottom" colspan="2">
                This text will be aligned at the bottom of the table.
            </td
>
    
    </tr
>
    <tfoot valign="bottom">
</
table>

posted by snyholm with 0 Comments