Browser Detection and Cross Browser Support

  • Revision slug: Browser_Detection_and_Cross_Browser_Support
  • Revision title: Browser Detection and Cross Browser Support
  • Revision id: 59810
  • Created:
  • Creator: Zameer Manji
  • Is current revision? No
  • Comment /* Misidentifying Browsers */

Revision Content

Introduction

In an ideal world, we could author HTML, XML, CSS and JavaScript and only worry about the W3C and ECMA standards. However, we don't quite live in such a world yet. Due to bugs, incomplete implementations of the standards and legacy browsers, web developers must be able to determine which browser a visitor is using and provide the appropriate content and scripting code path.

Although browser detection is perhaps the most common scripting task that every web developer faces, it seems that the variety of different strategies in use for detecting browsers is unlimited. As a member of the Netscape Evangelism team who has spent over a year investigating existing web content, I can say without a doubt that most compatibility problems found on the web today are due to a lack of understanding of the standards combined with inadequate and inappropriate browser detection strategies.

This article is intended to provide an overview of browser detection strategies and best practices. For more specific Netscape Gecko™ recommendations, please see the Gecko Compatibility Handbook


Netscape Gecko

Although many web developers are aware of Netscape 6 and Netscape 7, far fewer are aware that Netscape 6 and 7 are members of an entire family of user agents based upon Netscape Gecko that includes the commercial browser CompuServe 7, and open source browsers such as Mozilla, Galeon, and Kmeleon.

Netscape Gecko was designed from the ground up to be compliant with the W3C HTML, W3C CSS, W3C XML, W3C DOM, and ECMAScript (JavaScript) standards. It also includes compatibility features which allow it to reasonably handle legacy content which was developed for earlier generations of browsers such as Netscape Navigator 4 as well as features which provide compatibility with Internet Explorer 5 and 6. Unlike other browsers, Netscape Gecko is truly a cross platform browser and provides identical support on all operating systems where it is supported.

The easiest way to support Netscape Gecko is to create content which only uses the standards. Unfortunately, no other browser supports the standards as completely as Netscape Gecko which means that web developers and authors are forced to continue to provide support for other browsers which do not support the standards as fully. Fortunately, other browsers such as Internet Explorer 5 and 6 for Windows, to a lesser extent Internet Explorer 5 for Macintosh and Opera 6 also support the standards to a degree. These other browsers also appear to be moving towards more complete and rigorous support for the standards and there is hope that in the future web developers and authors will be able to dispense with browser detection at least with regard to features governed by standards.

We are still faced with the question of how to develop standards based content while supporting the differing implementations of modern browsers while at the same time supporting (to a lesser degree) older and less capable browsers. Browser detection is key to accomplishing this task.


Browser Detection History Primer

To understand why many common browser detection strategies are inappropriate, we must first look back on how these strategies came into being.

In the earliest days of the web, HTML was very simple, not standardized and did not include any support for client side scripting. HTML itself was not standardized until HTML 2.0 was introduced in late 1995 and it did not even include tables. Browser vendors such as Netscape and Microsoft competed to add compelling features to the HTML they supported in their browsers in order to provide the richest most compelling content to their users and to entice web authors to support them. The abilities of browsers to support the latest and greatest content changed on an almost daily basis.

Web authors were faced from the beginning with a variety of browsers, some of which supported the latest and greatest version HTML and some which did not. The solution was either to provide the lowest-common denominator of HTML or to use browser detection techniques on the web server to send customized content to each browser depending on what level of support the browser provided. Server side browser detection using user agent strings was born.

User agent strings are defined in the HTTP protocol and are available to web servers (see RFC 1945 - Hypertext Transfer Protocol -- HTTP 1.0 and RFC 2068 - Hypertext Transfer Protocol -- HTTP 1.1).

The most common approach at this time was to distinguish user agents by vendor and version using the reported user agent string. Although this approach was considered reasonable at the time, this approach caused problems for browser vendors right from the beginning. The original Netscape browsers used a user agent string which began with the code name for the Netscape browser followed by it's version number, e.g. Mozilla/version followed by a comment token which gave additional information regarding the operating system being used, etc. Since the earliest browser detection techniques were based upon looking for a Netscape based browser and only provided customized content to browsers which used the Mozilla/version user agent string, other browser vendors standardized on using Mozilla/version to signal that they were compatible with a particular Netscape version. Since other browsers pretended to be Netscape browsers and encoded their version information in a non-standard fashion in the user agent comment area, the task of determining which browser was being used became more complicated than it should have been.

Netscape Navigator 2 introduced the ability to run JavaScript in web browsers. As browser evolution continued, differences in the implementation of scripting and the objects supported by browsers appeared. Web authors were no longer limited to detecting browsers on their web servers, but could now execute scripts client side (in the browser itself) which could be used to distinguish browsers. One of the earliest approaches to client side browser detection involved testing whether the browser supported particular objects. An example of this approach involved testing for the existence of the document.images object.

While object based detection was used in some circumstances, many web authors continued to use the vendor/version approach to distinguishing web browsers in their client side scripts. Since the user agent string was exposed as a property of the navigator object (e.g. navigator.userAgent), many web authors used the same logic in their client side scripts as they had used earlier in their server side browser detection. In addition to navigator.userAgent other properties such as appName and appVersion were available in the navigator object which could be used in browser vendor/version detection strategies.

The classic example of this vendor/version client side detection strategy can be found in the Ultimate Browser Sniffer. This script and variants of it can be found today on many web sites where it is a common source of detection problems.

Netscape Navigator 4 and Internet Explorer 4 introduced the ability to manipulate HTML content in a browser (Dynamic HTML or DHTML) rather than on the web server and began the introduction of support for CSS to style content. This generation of browser, in addition to sharing several features which were not available in earlier versions, each implemented their own (incompatible) competing abilities to manipulate content in a web page.

Since each vendor's browser implemented different objects to perform DHTML, web authors began to use object detection to distinguish vendor/version through the existence of particular JavaScript objects. The existence of document.layers was sufficient to be sure that the browser was Netscape Navigator 4 while the existence of document.all was sufficient to be sure that the browser was Microsoft Internet Explorer 4. An implicit assumption by many web authors around this time was the there were only two types of browser available... Netscape Navigator and Microsoft Internet Explorer.

These strategies of classifying browsers by vendor/version, assuming that the only browsers being used where either Netscape Navigator 4 or Internet Explorer 4 failed when alternative browsers such as those based upon Netscape Gecko were introduced. Many of the problems reported in the press regarding Gecko's inability to display content were directly related to inadequate, inappropriate browser detection strategies.

A final note on vendor/version strategies. A web developer who fully utilizes the browser detection and distinctions in the Ultimate Browser Sniffer will produce code which uses code forks for many browsers and versions. Imagine attempting to maintain a web site which uses many of the browser variables available from the Ultimate Browser Sniffer.

browser vendor
         is_nav, is_ie, is_opera, is_hotjava, is_webtv, is_TVNavigator, is_AOLTV
browser version number
         is_major (integer indicating major version number: 2, 3, 4 ...)
         is_minor (float   indicating full  version number: 2.02, 3.01, 4.04 ...)
browser vendor AND major version number
          is_nav2, is_nav3, is_nav4, is_nav4up, is_nav6, is_nav6up, is_gecko, is_ie3,
          is_ie4, is_ie4up, is_ie5, is_ie5up, is_ie5_5, is_ie5_5up, is_ie6, is_ie6up, is_hotjava3, is_hotjava3up,
          is_opera2, is_opera3, is_opera4, is_opera5, is_opera5up
JavaScript version number
         is_js (float indicating full JavaScript version number: 1, 1.1, 1.2 ...)
OS platform and version
         is_win, is_win16, is_win32, is_win31, is_win95, 
         is_winnt, is_win98, is_winme, is_win2k,
         is_os2, is_mac, is_mac68k, is_macppc, 
         is_unix, is_sun, is_sun4, is_sun5, is_suni86,
         is_irix, is_irix5, is_irix6,
         is_hpux, is_hpux9, is_hpux10,
         is_aix, is_aix1, is_aix2, is_aix3, is_aix4,
         is_linux, is_sco, is_unixware, is_mpras, is_reliant,
         is_dec, is_sinix, is_freebsd, is_bsd,
         is_vms

Detecting browsers using this level of detail is unworkable, unmaintainable and violates the basic principles of web authoring! I strongly advise everyone to avoid this trap.


Problems caused by inappropriate Browser Detection

Excluding Unknown Browsers

If you only provide tests for specific browsers in your detection logic, your site will not be usable if a visitor uses a different browser. Consider the following example: // WRONG APPROACH - do not use! if (document.all) {

 // Internet Explorer 4+
 document.write('<link rel="stylesheet" type="text/css" src="style-ie.css">');

} else if (document.layers) {

 // Navigator 4
 document.write('<link rel="stylesheet" type="text/css" src="style-nn.css">');

} Note how the above example only provided stylesheets for Internet Explorer and Navigator 4 and even then only if the visitor has JavaScript support turned on in their browser. Users of Netscape 6, Netscape 7, CompuServe 7, Mozilla, Opera will not be able to view the site properly.

Misidentifying Browsers

A common mistake web authors make is to assume that if a browser is not Netscape Navigator 4, it must be Internet Explorer and vice versa. For example:

// WRONG APPROACH - do not use! if (document.all) {

 // Internet Explorer 4+
 elm = document.all['menu'];

} else {

 // Assume Navigator 4
 elm = document.layers['menu'];

}

Note how the above example assumed that any browser that was not Internet Explorer was Navigator 4 and attempted to use Layers. This is a common source of problems when using browsers based upon Netscape Gecko as well as Opera. A similar error can be seen in the following example:

// WRONG APPROACH - do not use! if (document.layers) {

 // Navigator 4
 elm = document.layers['menu'];

} else {

 // Assume Internet Explorer 4+
 elm = document.all['menu'];

}

Revision Source

<h3 name="Introduction"> Introduction </h3>
<p>In an <i>ideal</i> world, we could author HTML, XML, CSS and JavaScript and only worry about the W3C and ECMA standards. However, we don't quite live in such a world yet. Due to bugs, incomplete implementations of the standards and legacy browsers, web developers must be able to determine which browser a visitor is using and provide the appropriate content and scripting code path.
</p><p>Although browser detection is perhaps the most common scripting task that every web developer faces, it seems that the variety of different strategies in use for detecting browsers is unlimited. As a member of the Netscape Evangelism team who has spent over a year investigating existing web content, I can say without a doubt that most compatibility problems found on the web today are due to a lack of understanding of the standards combined with inadequate and inappropriate browser detection strategies.
</p><p>This article is intended to provide an overview of browser detection strategies and best practices. For more specific Netscape Gecko™ recommendations, please see the <a href="en/Gecko_Compatibility_Handbook">Gecko Compatibility Handbook</a>
</p><p><br>
</p>
<h3 name="Netscape_Gecko"> Netscape Gecko </h3>
<p>Although many web developers are aware of Netscape 6 and Netscape 7, far fewer are aware that Netscape 6 and 7 are members of an entire family of user agents based upon <a href="en/Netscape_Gecko">Netscape Gecko</a> that includes the commercial browser CompuServe 7, and open source browsers such as <a class="external" href="http://www.mozilla.org">Mozilla</a>, <a class="external" href="http://galeon.sourcef.orge.net/">Galeon</a>, and <a class="external" href="http://kmeleon.sourceforge.net/">Kmeleon</a>.
</p><p>Netscape Gecko was designed from the ground up to be compliant with the W3C HTML, W3C CSS, W3C XML, W3C DOM, and ECMAScript (JavaScript) standards. It also includes compatibility features which allow it to reasonably handle <i>legacy</i> content which was developed for earlier generations of browsers such as Netscape Navigator 4 as well as features which provide compatibility with Internet Explorer 5 and 6. Unlike other browsers, Netscape Gecko is truly a cross platform browser and provides identical support on all operating systems where it is supported.
</p><p>The easiest way to support Netscape Gecko is to create content which only uses the standards. Unfortunately, no other browser supports the standards as completely as Netscape Gecko which means that web developers and authors are forced to continue to provide support for other browsers which do not support the standards as fully. Fortunately, other browsers such as Internet Explorer 5 and 6 for Windows, to a lesser extent Internet Explorer 5 for Macintosh and Opera 6 also support the standards to a degree. These other browsers also appear to be moving towards more complete and rigorous support for the standards and there is hope that in the future web developers and authors will be able to dispense with browser detection at least with regard to features governed by standards.
</p><p>We are still faced with the question of how to develop standards based content while supporting the differing implementations of modern browsers while at the same time supporting (to a lesser degree) older and less capable browsers. Browser detection is key to accomplishing this task.
</p><p><br>
</p>
<h3 name="Browser_Detection_History_Primer"> Browser Detection History Primer </h3>
<p>To understand why many common browser detection strategies are inappropriate, we must first look back on how these strategies came into being.
</p><p>In the earliest days of the web, <a class="external" href="http://www.w3.org/MarkUp/">HTML</a> was very simple, not standardized and did not include any support for client side scripting. HTML itself was not standardized until HTML 2.0 was introduced in late 1995 and it did not even include tables. Browser vendors such as Netscape and Microsoft competed to add compelling <i>features</i> to the HTML they supported in their browsers in order to provide the richest most compelling content to their users and to entice web authors to support them. The abilities of browsers to support the latest and greatest content changed on an almost daily basis.
</p><p>Web authors were faced from the beginning with a variety of browsers, some of which supported the latest and greatest version HTML and some which did not. The solution was either to provide the lowest-common denominator of HTML or to use browser detection techniques on the web server to send customized content to each browser depending on what level of support the browser provided. Server side browser detection using user agent strings was born.
</p><p>User agent strings are defined in the HTTP protocol and are available to web servers (see <a class="external" href="http://www.faqs.org/rfcs/rfc1945.html"></a><a class="external" href="http://tools.ietf.org/html/rfc1945" title="http://tools.ietf.org/html/rfc1945">RFC 1945</a> - Hypertext Transfer Protocol -- HTTP 1.0 and <a class="external" href="http://www.faqs.org/rfcs/rfc2068.html"></a><a class="external" href="http://tools.ietf.org/html/rfc2068" title="http://tools.ietf.org/html/rfc2068">RFC 2068</a> - Hypertext Transfer Protocol -- HTTP 1.1). 
</p><p>The most common approach at this time was to distinguish user agents by <i>vendor</i> and <i>version</i> using the reported user agent string. Although this approach was considered reasonable at the time, this approach caused problems for browser vendors right from the beginning. The original Netscape browsers used a user agent string which began with the code name for the Netscape browser followed by it's version number, e.g. Mozilla/version followed by a comment token which gave additional information regarding the operating system being used, etc. Since the earliest browser detection techniques were based upon looking for a Netscape based browser and only provided customized content to browsers which used the Mozilla/version user agent string, other browser vendors standardized on using Mozilla/version to signal that they were compatible with a particular Netscape version. Since other browsers <i>pretended</i> to be Netscape browsers and encoded their version information in a non-standard fashion in the user agent comment area, the task of determining which browser was being used became more complicated than it should have been.
</p><p>Netscape Navigator 2 introduced the ability to run JavaScript in web browsers. As browser evolution continued, differences in the implementation of scripting and the objects supported by browsers appeared. Web authors were no longer limited to detecting browsers on their web servers, but could now execute scripts client side (in the browser itself) which could be used to distinguish browsers. One of the earliest approaches to client side browser detection involved testing whether the browser supported particular <i>objects</i>. An example of this approach involved testing for the existence of the document.images object.
</p><p>While <i>object based detection</i> was used in some circumstances, many web authors continued to use the <i>vendor/version</i> approach to distinguishing web browsers in their client side scripts. Since the user agent string was exposed as a property of the navigator object (e.g. navigator.userAgent), many web authors used the same logic in their client side scripts as they had used earlier in their server side browser detection. In addition to navigator.userAgent other properties such as appName and appVersion were available in the navigator object which could be used in browser <i>vendor/version</i> detection strategies.
</p><p>The classic example of this <i>vendor/version</i> client side detection strategy can be found in the <a class="external" href="http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html">Ultimate Browser Sniffer</a>. This script and variants of it can be found today on many web sites where it is a common source of detection problems.
</p><p>Netscape Navigator 4 and Internet Explorer 4 introduced the ability to manipulate HTML content in a browser (Dynamic HTML or DHTML) rather than on the web server and began the introduction of support for CSS to style content. This generation of browser, in addition to sharing several features which were not available in earlier versions, each implemented their own (incompatible) competing abilities to manipulate content in a web page.
</p><p>Since each vendor's browser implemented different objects to perform DHTML, web authors began to use object detection to distinguish <i>vendor/version</i> through the existence of particular JavaScript objects. The existence of document.layers was sufficient to be sure that the browser was Netscape Navigator 4 while the existence of document.all was sufficient to be sure that the browser was Microsoft Internet Explorer 4. An implicit assumption by many web authors around this time was the there were only two types of browser available... Netscape Navigator and Microsoft Internet Explorer.
</p><p>These strategies of classifying browsers by <i>vendor/version</i>, assuming that the only browsers being used where either Netscape Navigator 4 or Internet Explorer 4 <b>failed</b> when alternative browsers such as those based upon Netscape Gecko were introduced. Many of the problems reported in the press regarding Gecko's inability to display content were directly related to inadequate, inappropriate browser detection strategies.
</p><p>A final note on <i>vendor/version</i> strategies. A web developer who fully utilizes the browser detection and distinctions in the <a class="external" href="http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html">Ultimate Browser Sniffer</a> will produce code which uses code forks for many browsers and versions. Imagine attempting to maintain a web site which uses many of the browser variables available from the Ultimate Browser Sniffer.
</p>
<table border="1" cellpadding="2" cellspacing="0">
      <tbody><tr>
        <td>browser vendor</td>
        <td>
<pre class="eval">         is_nav, is_ie, is_opera, is_hotjava, is_webtv, is_TVNavigator, is_AOLTV
</pre>
        </td>
      </tr>

      <tr>
        <td>browser version number</td>
        <td>
<pre class="eval">         is_major (integer indicating major version number: 2, 3, 4 ...)
         is_minor (float   indicating full  version number: 2.02, 3.01, 4.04 ...)
</pre>
        </td>
      </tr>
      <tr>
        <td>browser vendor AND major version number</td>
        <td>
<pre class="eval">          is_nav2, is_nav3, is_nav4, is_nav4up, is_nav6, is_nav6up, is_gecko, is_ie3,
          is_ie4, is_ie4up, is_ie5, is_ie5up, is_ie5_5, is_ie5_5up, is_ie6, is_ie6up, is_hotjava3, is_hotjava3up,
          is_opera2, is_opera3, is_opera4, is_opera5, is_opera5up
</pre>
         </td>
      </tr>
      <tr>
        <td>JavaScript version number</td>
        <td>
<pre class="eval">         is_js (float indicating full JavaScript version number: 1, 1.1, 1.2 ...)
</pre>
        </td>

      </tr>
      <tr>
        <td>OS platform and version</td>
        <td>
<pre class="eval">         is_win, is_win16, is_win32, is_win31, is_win95, 
         is_winnt, is_win98, is_winme, is_win2k,
         is_os2, is_mac, is_mac68k, is_macppc, 
         is_unix, is_sun, is_sun4, is_sun5, is_suni86,
         is_irix, is_irix5, is_irix6,
         is_hpux, is_hpux9, is_hpux10,
         is_aix, is_aix1, is_aix2, is_aix3, is_aix4,
         is_linux, is_sco, is_unixware, is_mpras, is_reliant,
         is_dec, is_sinix, is_freebsd, is_bsd,
         is_vms
</pre>
        </td>
     </tr>
   </tbody></table>
<p><b>Detecting browsers using this level of detail is unworkable, unmaintainable and violates the basic principles of web authoring!</b> I strongly advise everyone to avoid this trap.
</p><p><br>
</p>
<h3 name="Problems_caused_by_inappropriate_Browser_Detection"> Problems caused by inappropriate Browser Detection </h3>
<h4 name="Excluding_Unknown_Browsers"> Excluding Unknown Browsers </h4>
<p>If you only provide tests for specific browsers in your detection logic, your site will not be usable if a visitor uses a different browser. Consider the following example:
<code>
// WRONG APPROACH - do not use!
if (document.all)
{
</code></p>
<pre class="eval"> // Internet Explorer 4+
 document.write('&lt;link rel="stylesheet" type="text/css" src="style-ie.css"&gt;');
</pre>
<p>}
else if (document.layers)
{
</p>
<pre class="eval"> // Navigator 4
 document.write('&lt;link rel="stylesheet" type="text/css" src="style-nn.css"&gt;');
</pre>
<p>}

Note how the above example only provided stylesheets for Internet Explorer and Navigator 4 and even then only if the visitor has JavaScript support turned on in their browser. Users of Netscape 6, Netscape 7, CompuServe 7, Mozilla, Opera will not be able to view the site properly.
</p>
<h4 name="Misidentifying_Browsers"> Misidentifying Browsers </h4>
<p>A common mistake web authors make is to assume that if a browser is not Netscape Navigator 4, it must be Internet Explorer and vice versa. For example:
</p><p><code>
// WRONG APPROACH - do not use!
if (document.all)
{
</code></p>
<pre class="eval"> // Internet Explorer 4+
 elm = document.all['menu'];
</pre>
<p>}
else
{
</p>
<pre class="eval"> // Assume Navigator 4
 elm = document.layers['menu'];
</pre>
<p>}

</p><p>Note how the above example assumed that any browser that was not Internet Explorer was Navigator 4 and attempted to use <i>Layers</i>. This is a common source of problems when using browsers based upon Netscape Gecko as well as Opera. A similar error can be seen in the following example:
</p><p><code>
// WRONG APPROACH - do not use!
if (document.layers)
{
</code></p>
<pre class="eval"> // Navigator 4
 elm = document.layers['menu'];
</pre>
<p>}
else
{
</p>
<pre class="eval"> // Assume Internet Explorer 4+
 elm = document.all['menu'];
</pre>
<p>}

</p>
Revert to this revision