Building compatible pages means knowing which features each browser supports, and how you can adjust the page to suit most of them. We won’t be going into the mechanics of this in depth here, because it's a huge subject on its own. However, the following sections describe some of the things you might like to look out for:
HTML as a language was designed to avoid direct formatting of page content. The original plan was that you would just use text (and possibly images) to convey technical information. Formatting was limited to the use of tags like <EM>
for emphasizing a point, or <DL>
to create a definition list. As the language developed, browser manufacturers added lots of new tags that control formatting and presentation of information, such as <FONT>
, <SMALL>
, <BLINK>
, <MARQUEE>
etc.
Browsers will ignore any elements or element attributes that they don’t recognize. For example, if you use the <BLINK>
element, you'll only annoy Navigator users. Internet Explorer users will just see the content as normal static text. And, of course, Navigator users will be spared the effort of reading the oscillating text in your <MARQUEE>
elements, as it only scrolls from side to side in Internet Explorer.
If we're aiming to achieve maximum compatibility from a single set of pages, we will probably decide to use the <FONT>
element to provide all the basic formatting we need, plus the standard and almost universally supported <B>
and <I>
elements. If the browser doesn’t recognize <FONT>
, the worst that will happen is that all the text will appear in the same default font and size. Not ideal, but acceptable.
The one possible discrepancy between different <FONT>
implementations is that Navigator 2 will not recognize the FACE
attribute for the <FONT>
element—you can control the size and color but not the font face itself.
It's not just the tags that each browser supports which are important. Different browsers can treat the same tag in different ways. For example, the <PRE>
element produces text in a mono-spaced font and preserves formatting, so that carriage returns and multiple spaces are not lost as they are in normal HTML rendering. But using <PRE>
within a table produces unpredictable results.
For example, in the left column of the table shown in the next screenshot, we want a mono-pitch font. The obvious choice is the <PRE>
element. This would allow us to use spaces to indent each line as appropriate. However, because <PRE>
is a block-level element, the next element should be placed on a new line below it. In Netscape Navigator, this means that there is a blank line below the text in each row of the table, producing unsightly results. The same happens in Internet Explorer 4, but not in Internet Explorer 3:
Instead, we can use the <CODE>
tag, which produces an in-line, rather than block-level, element. However, because it's in-line, we lose the ability to precede the text with spaces to provide the appropriate indentation of the elements. The way we get round this is to use the non-breaking space character
. Most browsers recognize this, and it gives us the ability to indent lines as required. Where a browser doesn’t recognize it, the text will just appear flush to the left margin. It's not exactly what we want, but it doesn’t stop the page performing its task.
But we're still not finished. The <CODE>
element displays text in a smaller font than the surrounding text. So, to balance it out, we have to specify a larger font size as well. The 'normal' font size for our page is 2, but the text in the <CODE>
element needs to have a font size of 3.
Most browsers recognize the special characters defined with an ampersand, such as
for a non-breaking space and ©
for a copyright symbol. Watch out for others, however. Internet Explorer is happy to display ™
as a 'trademark' symbol, while Navigator doesn't know about this one. Instead, you can specify the ANSI code of the character, using ™
to get a 'trademark' symbol in Navigator.
In HTML, many closing element tags are optional, for example the </TD>
and </TR>
tags in a table. The browser knows where a cell or row ends, because the next tag will be an opening cell or row tag or the closing </TABLE>
tag. However, you should avoid this shorthand technique, which can cause formatting problems—in particular Navigator can lose cells at the end of a table in some circumstances.
<TABLE>
<TR>
<TD>
cell content here
</TD> <!-- optional, but safer if always included -->
</TR> <!-- optional, but safer if always included -->
</TABLE>
Even though a browser may support a particular element, you cannot assume that it will recognize all the attributes of that element. For example, the <TABLE>
element provides a WIDTH
attribute, to let you specify the overall width of the table. This is supported as far back as version 2 by Navigator, but only from version 3 onwards in Internet Explorer.
Also, try not to depend on the use of the more esoteric attributes (such as BORDERCOLORDARK
in Internet Explorer to change the inner border of a 3D table). Instead, look to find other ways of achieving the same end.
By default, the browser provides a margin of some 10 to 20 pixels around the actual content of a page when it renders it. For a 'busy' page, this is wasted space. If you're a confirmed Internet Explorer user, you'll probably avoid this by setting the TOPMARGIN
and LEFTMARGIN
attributes in the opening <BODY>
tag.
However, this isn't going to do much good in any other browser. Only Internet Explorer supports these attributes. Instead, in Navigator 2+, and now in version 4.0 of HTML, we can use the MARGINWIDTH
and MARGINHEIGHT
attributes of the <FRAME>
tag to do the same (providing we host the page within a frameset). Internet Explorer only supports this from version 3 onwards, however. The easy answer, as we often do in our pages, is to use both. We're covered then for browsers that support either method. We define the MARGINWIDTH
and MARGINHEIGHT
in the frameset, and then add the TOPMARGIN
and LEFTMARGIN
attributes to the opening <BODY>
tag.
In the frameset page:
<FRAME SRC=".." MARGINWIDTH=3 MARGINHEIGHT=5>
and in the page that appears within that frame:
<BODY BGCOLOR="#FFFFFF" TOPMARGIN=3 LEFTMARGIN=5>
Some older browsers will not recognize color names either, or at least not the less popular ones. Rather than using:
<BODY BGCOLOR="lavenderblush">
you'll get a more universal level of support with:
<BODY BGCOLOR="#FFF0F5">
You can find the equivalent color values using a graphics program such as PaintShop Pro or Windows' own Paint applet. Define a custom color then read off the values in the Custom Color dialog and convert them into hexadecimal—you can use the Windows Calculator applet for this.
We provide a page that allows you to preview the various colors, and get the matching hexadecimal color values, on our Web site. Open the page http://webdev.wrox.co.uk/resources/ and select Gallery, then Wrox Color Chooser. We've included this page in the code that you can download for this book as well.
The situation is often complicated with inserted objects, or inclusions. You've more chance of a browser recognizing an <APPLET>
element and a Java applet, than an ActiveX control in an <OBJECT>
element. We can tell the user what went wrong with the page by including alternative content within the <APPLET>
or <OBJECT>
element, but outside any <PARAM>
elements:
<OBJECT NAME="MyControl" CLASSID="...">
<PARAM NAME="param1" VALUE="value1">
There should be an ActiveX control here. If you see this text
instead, your browser can’t display the object. Sorry...
</OBJECT>
There are occasions when we really need to do some work in script code to provide the maximum usability for our pages, but we want to ensure that they will work on non-script enabled browsers as well. Through some careful design and planning, this is quite possible to achieve. For example, we can use script to automatically submit a form in response to an event such as selecting a value in a list. This can make the page much more intuitive. At the same time, if the browser doesn’t support scripting, our code will automatically display a normal SUBMIT
button so that the user can click this to submit the form.
The <NOSCRIPT> element is particularly useful for controlling the appearance of a SUBMIT button on a form. The theory is simple enough:
<FORM ACTION="http://myserver.com/scripts/doit.asp" NAME="MyForm" METHOD="POST">
<INPUT TYPE=CHECKBOX NAME="MyCheck" ONCLICK="document.MyForm.submit();">
<NOSCRIPT>
<INPUT TYPE=SUBMIT VALUE="Do it now">
</NOSCRIPT>
</FORM>
Browsers that support scripting should also support the <NOSCRIPT>
element, and ignore its content. This means that they won’t display the SUBMIT
button, but will run the code specified in the ONCLICK
attribute of the checkbox <INPUT>
tag when the user clicks on the checkbox. This code can carry out any tasks required, then submit the form for processing by calling its submit()
method.
Browsers that don’t support scripting won’t know about <NOSCRIPT>
, so they will ignore the tags and display the content. The user gets a SUBMIT
button, which is handy because clicking the checkbox will have no effect (other than changing its value). Their browser won’t recognize the ONCLICK
attribute either, so will ignore the script code it contains. This technique is used in the HTML Reference Database on our own Web site (http://webdev.wrox.co.uk/html4db/):
One point to be aware of is that Opera 3.0 has a problem with this technique if the SUBMIT
button is not the last control on the form. It doesn’t send the values of any controls defined after a <NOSCRIPT>
section back to the server. We discovered this when our HTML Reference Database refused to work in this browser. We solved it by including ASP code in the page that detects if the browser is Opera 3.0, and prevents the <NOSCRIPT>
and </NOSCRIPT>
tags being included in this case.
It's also worth adding an instruction for script-enabled browsers, which indicates to the user that the form is being submitted when they click on any of the controls (remember they won’t see any visual indication of how to submit the form). So, in all the controls on the form we can add code that displays a message in the browser's status bar:
ONCLICK="window.status='Searching...';document.MyForm.submit();">
This displays the message Searching... in the browser's status bar (to show something is happening) and submits the form to the address in the ACTION
attribute of the <FORM>
element—just as though a SUBMIT
button had been clicked.
Because you can detect the browser version client-side using script, you can change the appearance of the page to suit the particular browser easily—as we demonstrated earlier in this chapter. Browsers that support scripting offer a huge opportunity to create interactive pages, and most sites these days use client-side scripting to some extent. As we mentioned earlier, for maximum compatibility you should aim to use JavaScript unless you are creating pages that are only designed to be used on Microsoft browsers.
However, even though most browsers support JavaScript, there are still issues to be aware of. Navigator 4 supports a new version of JavaScript, version 1.2, which adds extra capabilities that Internet Explorer doesn’t recognize. If you aim to stick to the JavaScript 1.1 or 1.0 standard, you will avoid these difficulties.
In the case of Internet Explorer, the language interpreter is actually JScript, and you can use SCRIPT="JScript"
in the opening <SCRIPT>
tag. However, for compatibility with Navigator and other browsers such as Opera, you should stick to SCRIPT="JavaScript"
, which IE recognizes and passes to its JScript interpreter. There is a new language definition called ECMAScript (from the European Computer Manufacturers Association) which is designed to be JavaScript 1.1 and JScript compatible. No doubt it will gradually replace the existing mix of languages in time.
Even though most browsers these days will accept JavaScript, the browser itself will have different capabilities. This means that the objects you can manipulate in script will be different. For example, Internet Explorer 4 introduced the all
collection to allow access in script to any element on the page. Navigator has no such object, and trying to refer to it will create an error.
However, Navigator has a plugins
collection for its navigator
object that allows you to iterate through all the plug-ins loaded by the browser. Internet Explorer doesn’t support these plug-ins, and the plugins
collection will always be empty, so your code will get no usable result.
There are also differences between objects that appear on both browsers, for example, the event
object occurs in both Navigator 4 and IE4, but has different properties in each browser. It doesn’t exist at all in earlier browsers, or browsers from other manufacturers. And worse than this—where two properties do have the same name, they can return different information. The meanings are different even if the names are the same.
There are moves at W3C to define a standard Document Object Model (DOM). However, like most standards in our section of the industry, the two browser manufacturers are moving ahead so quickly that they make even the latest proposals appear out of date. The good news is that both Netscape and Microsoft have promised to support all the standards that appear in new versions of their browsers. The problem is that there will still be features they implement beyond the standards that you will want to use in your pages.
If the code in our page needs to access the object model at the kind of depth that we've just been describing, one route you can take is to build a page that contains duplicated sections of code. That way, depending on the browser that loads the page, you can use the appropriate script code. Here's a simple example that displays the user's system color depth, read from the screen
object that has different properties in the two mainline browsers:
...
<SCRIPT LANGUAGE="JavaScript">
<!--
var sorryText = 'Sorry, cannot display the color depth of your system';
if (navigator.appName.indexOf('Netscape') != -1)
if (navigator.appVersion.substr(0, 1) > 3)
document.write('System color depth is ' + window.screen.pixelDepth)
else
document.write(sorryText);
if (navigator.appName.indexOf('Microsoft') != -1)
if (navigator.appVersion.substr(0, 1) > 3)
document.write('System color depth is ' + window.screen.colorDepth)
else
document.write(sorryText);
//-->
</SCRIPT>
<NOSCRIPT>
Sorry, your browser doesn't support client-side scripting,
so it can't display the color depth of your system.
</NOSCRIPT>
...
Here are the results in Netscape Navigator 4 and Internet Explorer 4:
One easy way to use duplicated script sections is to allow ASP to insert the correct code automatically. The following example shows how you can use ASP to decide if the browser can produce the information at all, and, if it can, which code to use. The extra bonus here is that, because we are positively identifying the browser, we can use script sections in VBScript for IE4, and JavaScript version 1.2 for Navigator 4 if required. In this case we do not require the comment tags around the script to hide it from non script-enabled browsers, because we are only going send it to script-enabled ones:
...
<%
Set objBCap = Server.CreateObject("MSWC.BrowserType")
If objBCap.Browser = "IE" And CInt(objBCap.Version) >= 4 Then
%>
<SCRIPT LANAGUAGE=VBScript">
'client-side script here to suit IE 4 and above
</SCRIPT>
<%
ElseIf objBCap.Browser = "Netscape" And CInt(objBCap.Version) >= 4 Then
%>
<SCRIPT LANAGUAGE=JavaScript1.2">
'client-side script here to suit Navigator 4 and above
</SCRIPT>
<%
ElseIf objBCap.javascript = True Then
%>
<SCRIPT LANAGUAGE=JavaScript">
'client-side script here to suit generic JavaScript enabled browsers
</SCRIPT>
<%
Else
%>
<P>This page requires a script enabled browser to work properly ... etc.</P>
<%
End If
%>
...
An alternative, to make the page easier to maintain and update, is to use SSI to insert the appropriate <SCRIPT>
code or 'sorry' message. This is also useful if you need to use the same code in several pages:
...
<%
Set objBCap = Server.CreateObject("MSWC.BrowserType")
If objBCap.Browser = "IE" And CInt(objBCap.Version) >= 4 Then
%>
<!-- #include file="ie4_code.inc" -->
<%
ElseIf objBCap.Browser = "Netscape" And CInt(objBCap.Version) >= 4 Then
%>
<!-- #include file="nav4_code.inc" -->
<%
ElseIf objBCap.javascript = True Then
%>
<!-- #include file="generic_code.inc" -->
<%
Else
%>
<!-- #include file="no_code.inc" -->
<%
End If
%>
...
You might be tempted to try something like this instead:
'Note: this doesn’t work
If objBCap.Browser = "IE" And CInt(objBCap.Version) >= 4 Then
strInclude = "ie4_code.inc"
ElseIf objBCap.Browser = "Netscape" And CInt(objBCap.Version) >= 4 Then
strInclude = "nav4_code.inc"
Else
...
<!-- #include file="<% = strInclude %>" -->
This won’t work, because the include file is inserted into the page before the ASP code interpreter gets to see it. You'll just get an error to say it can't find the include file. Also note that include files cannot be used inside the global.asa
file.