iModernize - The Profound Logic Software Blog

Browser Detection in JavaScript

Posted by DRusso on Dec 30, 2013 12:37:30 AM

In web development, a sometimes useful (but often misused) capability is to detect which browser the user is accessing the site or application with. This is commonly done in client-side (JavaScript) coding to get around browser quirks or bugs, or to present a different experience to users of one browser or another.

In a lot of cases, a developer will become interested in detecting what browser is used when he finds that feature 'X' does not work in browser 'Y' (more likely, browser 'IE'), or that feature 'X' does work, but must be gone about in different way. If the script is aware of what browser is being used, it can employ techniques that will allow the application to function normally (maybe with reduced features) in the troublesome browser.

I say that browser detection is often misused, as there is usually a much better way to go about things. In most cases, rather than worrying about what browser is being used, a script should concern itself with checking what features are / are not available. This is a much more reliable technique, and will cover 99% of cases where browser differences are a factor.

Feature detection can usually be accomplished in JavaScript by checking if the desired method or property is defined. A classic example of this is in detecting which event model the browser supports:

if (myButton.addEventListener) {

  // This works in standards-compliant browsers.
  myButton.addEventListener("click", myHandler);

}
else if (myButton.attachEvent) {

  // This works in older versions of IE.
  myButton.attachEvent("onclick", myHandler);

}

Rather than checking to see what web browser is used, the script determines which event model is supported by checking for the existence of the appropriate methods. The idea is that the script will be more robust, as it does not take the chance of making any mistakes with browser detection -- we'll see why this can be dodgy next. Also, the code is greatly simplified as it doesn't have to be concerned with the multitude of different browsers and versions currently in use, or even the arrival of a brand new web browser on the scene, such as Chrome in recent years.

Now that we've looked at why not to use browser detection, let's look at how it is accomplished, and what it is useful for.

Every web browser has what is called a "user agent string". The term "agent" is used in the sense that the browser is the user's representative, or agent, in the HTTP communication process. The string contains information that identifies the user agent. This includes the name of the browser, the version, and sometimes details about the operating system the browser is running on. The user agent string is sent to an HTTP server when the browser makes a page request (server-side coding can look at this, too), and it also makes it available to JavaScript coding on the page through the property "navigator.userAgent".

For example, here is the current (as of this writing) user agent string for Chrome on Windows 7:

Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.41 Safari/537.36

As you can see, the user agent string is cryptic at best, and at worst purposefully misleading.

Chrome's user agent string mentions Mozilla? Why? This is probably due to the overuse and/or misuse of browser detection by web developers in the mid-1990s. At that time, browsers that did not identify as Mozilla were seen as older/obsolete browsers by a lot of early web sites, and sent a plain vanilla, stripped down version of the website. So, browser vendors quickly got in the habit of including 'Mozilla' in the user agent string. The appearance of 'Apple', 'WebKit', and 'Safari' are due to Chrome's shared pedigree with Safari -- Chrome was initially based on the open-source WebKit browser engine, which powers Safari. To identify Chrome, you would look for the 'Chrome/' token in the string, and the number following is the version.

Internet Explorer user agent strings looked like this through version 10:

Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)

Older versions were very similar -- you would identify Internet Explorer by finding the 'MSIE' token, and the version number follows.

But, with Internet Explorer 11, Microsoft decided to intentionally break years worth of browser detection scripts by removing the 'MSIE' token:

Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko

This was done as Microsoft has made a big effort to make IE more standards-compliant, and to catch up with features available in other browsers. So, the idea was to intentionally break browser detection scripts which would cause web sites to present a stripped down user experience to IE.

As you're probably concluded by now, browser detection can be highly complicated, and is often a moving target. Also, in Profound UI, there is even much less need for browser detection than if you were hand coding HTML and a lot of JavaScript. Profound UI's widgets, along with their JavaScript APIs, are designed to perform consistently across all supported browsers.

With all of this in mind, the only recommended use case for browser detection, is to get around bugs or quirks in the browser that cannot be handled with Profound UI's APIs, or with feature detection as described above. Typically this comes up only in highly advanced JavaScript coding.

As of version 4.7.2, Profound UI includes pre-set JavaScript flags that can be used in your scripts, should the need arise. Our developers have interpreted the user agent strings of the supported browsers for you, and keep them up to date as browsers 'change the rules'. This includes recent changes to IE11 mentioned above.

The following Boolean-type flags are available:

pui.is_ie;
pui.ie_mode;    // Defined only if (is_ie == true)
pui.ie_version; // Defined only if (is_ie == true)

pui.is_android;
pui.is_chrome;
pui.is_firefox;
pui.is_opera;
pui.is_safari;

You'll notice that version numbers are included only for Internet Explorer. This is because it's very common for users to be locked into an older version of IE, and also IE updates are fewer and farther between, with more changes. Users of other browsers typically receive automatic updates and are fairly up to date. Also these other browsers are updated more frequently, and the changes are not so drastic. So, it's highly unusual to have to distinguish between different versions of these browsers.

The additional flags for IE distinguish between the page mode (pui.ie_mode), and the actual version of IE (pui.ie_version) being used, as recent versions of IE include the capability to display the page as in older versions, for backwards compatibility. In most cases, you'll want to use 'pui.ie_mode'. These flags are only defined if 'pui.is_ie' is true.

For example:

if (pui.is_ie && pui.ie_mode < 8) {

  alert("Really?!");
  doNotMuch();
  return;

}

Now, here is an example where browser detection is recommended, as it's the only solution. This has gotten a lot better in recent browser versions, but in the past it's been tricky to calculate the width of an element consistently. Some browser versions simply report different widths for an 'identical' element, depending on borders, padding, etc. Take for example the following script that uses the 'clientWidth' property of an element to determine its width. In this example, the width reported by IE versions prior to 9 is greater than that reported by other browsers, by 4 pixels. In this case, there would be no other way to handle the situation, other than browser detection, since it would be impossible to test for this condition in any other way. In this example, the script detects the browser version and adjusts the calculated width accordingly.

var elem = document.getElementById("myElement");
var width = elem.clientWidth;

if (pui["is_ie"] && pui["ie_mode"] < 9) {

  width -= 4;

}

Hopefully this gives you a good idea on when / when not to employ browser detection in your scripts. Happy coding!

Topics: Development

Subscribe to Blog Updates

....and get The 2017 State of IBM i Modernization White Paper FREE!

cover page.png

Recent Posts