Guide For Fixing Javascript Cross Browser Compatibility
By: Sarah Elson
Tags: Json, JavaScript, Debugging, Browsers, Web Development

Out of all major web technologies, there is no other technology as vilified for cross browser compatibility as JavaScript. But even after striding advancements in pure HTML and CSS, you it’s true that you cannot easily build webapps or websites without it.

In our previous post last week, we delved in detail on cross browser compatibility issues faced in HTML and CSS. So far we have looked into basics of Browser Compatibility and how you can ensure that your website/web application is cross browser compatible.

Extending the same post last week, in this article, we look into common cross browser compatibility issues web developer face in using JavaScript. We will also look into methodologies to fix the issues.

But before we get started with the actual topic of discussion, it is important that we look into the basics and evolution of JavaScript.

So far we have looked into basics of Cross Browser Compatibility and how you can ensure that your website/web application is cross-browser compatible. We also looked into some mechanisms of fixing CSS and HTML cross-compatibility issues.

In this article, we look into cross-browser compatibility issues with JavaScript and methodologies to fix the issues. Before we get started with the actual topic of discussion, it is important that we look into the basics and evolution of JavaScript.

Deep diving into JavaScript

There have been rapid changes in web development since the last decade and along with the emergence of different kinds of devices — desktop, mobiles, tablets, etc. There has also been an increase in the number of web browsers used for surfing the internet. This poses different set of challenges for designers and developers since different browsers could interpret CSS and HTML code in a different manner. The reason behind is that every browser has a unique rendering engine, responsible for rendering web elements in a way that is different than other. CSS HTML & JavaScript are 3 layers of progressive enhancement. Progressive Enhancement is a technique of creating cross browser compatible web design wherein the highest priority while developing is keeping the core web page content, while the other complex add-ons and features remain secondary. When JavaScript was introduced in the 1990’s, there were major cross-browser compatibility issues since every browser development companies had their own way of script implementation and this was primarily done to gain market dominance. Though such issues do not occur now, handling cross-browser compatibility issues with JavaScript can still cause nightmare for developers.

Problems with JavaScript code majorly occur when developers come with features in web pages that do not support old browsers, usage of incorrect DOCTYPEs, or incomplete/incorrect implementation of browser sniffing code. Unless a standard mechanism of processing JavaScript (or other scripting languages) is implemented, cross-browser compatible issues with JavaScript would continue to persist. Let’s look into these cross-browser compatibility issues with JavaScript and learn a bit about the mechanisms on fixing them.

Common JavaScript Problems

Before we look into cross-browser compatibility issues with JavaScript, it is important that we look at some of the common JavaScript problems. It is assumed that you are already aware about JavaScript and have prior implementation experience with JavaScript.

Memory Leaks is one of the common problems faced by developers. Memory Leak simply means that memory that was previously being used by the application is no longer being used. However, due to some reason (e.g. incorrect handling of global variables, out of DOM references, etc.); the allocated memory is not returned back to the ‘free’ pool of memory. Some of the common reasons for memory leaks are incorrect handling of global variables and out of DOM references.

‘Profiling Tools for Chrome’ can be used for memory profiling as well as identifying memory leaks. Below is a sample snapshot of Chrome Memory Profiling in action.

JavaScript executes the code in the order in which it appears in the document. Hence it becomes important to reference code only when it is loaded . In case you are referencing code before it is loaded, the code would result in an error.

. In case you are referencing code before it is loaded, the code would result in an error. Unlike other languages, no error is thrown in case you pass ‘incorrect number of parameters’ to a function in JavaScript. In case those parameters are optional, your code would be executed without any problem. It might result in problems when those parameters are used in the function and not using them can alter the functionality. It is recommended to have uniform naming conventions so that identifying such problems becomes easy.

to a function in JavaScript. In case those parameters are optional, your code would be executed without any problem. It might result in problems when those parameters are used in the function and not using them can alter the functionality. It is recommended to have uniform naming conventions so that identifying such problems becomes easy. Equality Operators are basic in JavaScript, but they have to be used with precision. There is a difference between ‘assignment/equals operator’ (==) and ‘strict equals operator’ (===). These are mainly used in conditional statements and accidently using (==) instead of (===) can cause functionality issues. Thorough code-walkthrough needs to be carried out in order to look into such silly, yet costly mistakes.

are basic in JavaScript, but they have to be used with precision. There is a difference between ‘assignment/equals operator’ (==) and ‘strict equals operator’ (===). These are mainly used in conditional statements and accidently using (==) instead of (===) can cause functionality issues. Thorough code-walkthrough needs to be carried out in order to look into such silly, yet costly mistakes. Variables are used as per their scope (local and global). Ensure that you use consistent naming conventions for different types of variables so that it is easier to maintain the code.

Ensure that your source code does not have any syntax issues .

are used as per their scope (local and global). Ensure that you use consistent naming conventions for different types of variables so that it is easier to maintain the code. Ensure that your source code does not have any . Adding DOM Element in JavaScript is considered to be a costly operation. The primary reason it is being used is because JavaScript makes it easy to implement DOM. In some cases, you would need to add DOM elements consecutively, but doing so is not a good practice. In such a scenario, you could instead use document fragments as it has superior efficiency and performance.

in JavaScript is considered to be a costly operation. The primary reason it is being used is because JavaScript makes it easy to implement DOM. In some cases, you would need to add DOM elements consecutively, but doing so is not a good practice. In such a scenario, you could instead use document fragments as it has superior efficiency and performance. The starting index in JavaScript Arrays is 0 and not 1. If you intend to create an array of 10 elements, you should declare an array with index as 9 (array elements 0..9) and not 10 (array elements 0..10). Referencing out of bound array elements would result in errors.

is 0 and not 1. If you intend to create an array of 10 elements, you should declare an array with index as 9 (array elements 0..9) and not 10 (array elements 0..10). Referencing out of bound array elements would result in errors. Implementing a time-consuming task in a synchronous operation could slow down the performance of your webpage/web application. Ensure that you move that logic to an asynchronous operation so it does not hog the CPU. Since the operation is asynchronous in nature, you have to be careful while using variables used in that operation since they might not be reflecting the latest value (as the async operation execution might still be in progress). Developers are advised to use the Promise object that returns the status (success/failure) of the completion of an async operation. A sample code with Promise is shown below

Incorrect usage of ‘functions inside loops’ thereby resulting in breakage of functionality.

Common cross-browser JavaScript Problems

So far we have looked into some of the Basic JavaScript problems; let’s have a look at some of the mechanisms to solve those problems:

Library Usage

Similar to the jQuery library about which we discussed earlier, there are many libraries (native and third-party) that might not be supported on many versions of browsers. Before using the library, it is recommended that you do a thorough analysis about the library (in terms of browser support, feature support, etc.). You should also check the ‘development history’ of the library as it shouldn’t happen that there are very few updates to the library and once you use the library, there are no updates to it!

Using User Agents And Browser Sniffing

Every browser has a user-agent string which identifies the browser that the user has used in order to access your website/web application. Developers use browser sniffing code in order to tweak the UI/UX/functionalities based on the browser being used by the user. Some of the common user-agent strings are mentioned below.

Developer can use navigator.userAgent.indexOf(‘user-agent’) where user-agent is the user-agent string (mentioned in the table above). Below is a snapshot of a code where developer can come up with functionalities based on the type of browser.

Feature Detection For Modern JavaScript Features

JavaScript is not considered as permissive as HTML and CSS when it comes to handling errors & unrecognized features. JavaScript would definitely signal an error when it comes across a wrongly used syntax/missing brace/semicolon/some other issue.

There are many new features that are implemented under the ECMAScript 6 (ES6)/ECMAScript Next standards and many old browsers would not support those features. For example, the ‘Promise Object’ that we discussed earlier would not work on the old version of the browsers. ‘Typed Arrays’ is another example. ‘Arrow Functions’ was a very useful feature that was introduced in ES6 and it provides a concise manner for writing functions in JavaScript. It is not bound to its own this object i.e. the context inside the Arrow Function is statically defined. Modern JavaScript developers use this feature heavily, but it is also not supported on old browsers/old versions of browsers like IE, Firefox, Chrome, etc. The Safari browser does not support ‘Arrow Functions’.

So, how do you avoid the JavaScript functionality is seamless on older browsers as well? The solution is to verify whether the feature being used is supported on old browsers. You can verify the same using an online resource like caniuse; simply key-in the feature name and it would indicate the version of browsers where the feature is supported. For example, below is the case for ‘Arrow Functions’. Entries in Red Color implies that the ‘feature is not supported.

Based on the target audience, you should provide support for all the latest browsers and some older versions of browsers (depending on your initial market study). You can check out these web analytics tools that would help you understand your customers in a better way. You can also opt for ‘conditional execution’ so that there is always a ‘fallback mechanism’ in case the user is using old browser. There are many old versions of browsers that do not support WebRTC (Video conferencing), Maps API, etc. In the below example, we are using the Geolocation API; the geolocation property of the Navigator object is used for that purpose. If the browser does not support Maps API, the user is given an option to use Static Maps (as a fallback option).

There are many JavaScript libraries that a developer has to simply import in order to use its functionalities. The good part about the usage is that the developer no longer has to code everything from scratch since the library already supports those functionalities.

JavaScript Transpiling

In case you want to provide support for the old browsers, but do not want to use browser sniffing, feature detection, etc.; a handy option that is available is called ‘Transpiling’. In simple terms, Transpiling helps in converting JavaScript code that might be using the latest ES6/ECMAScript features to a JavaScript code that can work on the older browsers.

You can use a popular JavaScript Transpiling tool like Babel where you simply enter the latest JavaScript code on the ‘left’ and it outputs the transpiled code on the ‘right’.

Polyfills

Similar to third party libraries that enhance the functionalities and reduce the development time, Polyfills also consist of third party JavaScript files that you can use in your project. However, what makes Polyfills different from Libraries is that Polyfills are capable of providing the functionalities that does not exist at all. For example, you can use a Polyfill to support WebRTC/Promise/other ES6 based features by simply using the equivalent Polyfill for that feature.

You can have a look at this list which has details about the Polyfill equivalent for JavaScript features. Let’s have a look at an example. Shown below is a code snippet where we have used a Polyfill to support the startsWith feature that was introduced in ES6.

Solving Common JavaScript Problems

JavaScript Debugger

Breakpoints are commonly used for debugging purpose and when a ‘breakpoint’ is hit, the execution is halted and developer can have a look at various details like call stack, watch variables, memory info, etc. JavaScript has a keyword called ‘Debugger’ and when the keyword is encountered; the execution of the JavaScript code is halted. This is similar to inserting a breakpoint in the code.

var x = 6 * 5; debugger; /* Logic here */

var x = 6 * 5;

debugger;

/* Logic here */

Alternately, you could also use the traditional debugging method of using ‘JavaScript Console’ in Chrome to debug the code. The JavaScript console can be loaded using the option Tools->JavaScript Console.

Browser Developer Tools

Browser Developer Tools can be used for removal warnings & errors in the JavaScript code. It is also useful for debugging the code since developers can insert Breakpoints at specific locations in the code.

In case you are using the Chrome or Firefox, just right click in the window after ‘Loading the code’ and click on ‘Inspect Element’. Browser Developer Tool also has the ‘Debugger tab’ where the developer can insert breakpoints, check the callstack, add variables to watch window, etc.

Below is the snapshot of the Developer Tool of the Firefox browser.

Developers can also use the Console API for printing logs during the development phase. It is recommended that different kinds of console logs are used for different purposes. For example, console.log() can be used for debugging, console.assert() in case you want to issue an assert and console.error() can be used in error scenarios.

Code Editor Plugins

There are many editors that have in-built as well as downloadable linter plugins that can be used to correct the warnings & errors in your JavaScript code. Atom is a popular Open Source IDE that has plugins for linting code. Developers can install lint, jslint, and linter-jshint plugins to lint source code. They issue warnings & errors that are present in the code in a separate panel at the bottom of the development window. Below is the snapshot of Atom IDE where it is displaying the warnings in the source code. Atom IDE can be downloaded from here.

Linters

Linters are used to ensure that code is of better quality, properly aligned, and there are no errors in the code. Just like Linters used for HTML & CSS code, Linters for JavaScript are also instrumental in maintaining code-quality, irrespective of the size of your JavaScript code. Linters can be customized to different levels of error/warning reporting. Some of the widely-used Linters for JavaScript are JSHint and ESLint.

Solving General JavaScript Issues

Apart from the JavaScript issues that we have discussed so far, there are many general issues that developers need to address. Some of the common generic problems are:

Incorrect casing/spelling being used for variables, function names , etc. Many experienced developers accidently make use of built-in functions with wrong casing/spelling. For example, you might use getElementByClassName() instead of getElementsByClassName().

, etc. Many experienced developers accidently make use of built-in functions with wrong casing/spelling. For example, you might use getElementByClassName() instead of getElementsByClassName(). While performing a code-review, the reviewer should make that there is no code after return statement since that code is redundant (or non reachable).

since that code is redundant (or non reachable). Object notation is different from normal assignment and you need to check whether the member names of the object are separated by comma (,) & member names are separated from their values by colon (:).

is different from normal assignment and you need to check whether the member names of the object are separated by comma (,) & member names are separated from their values by colon (:). Though this is a very basic practice, check whether the semicolon (;) is being used at the right place.

Best Practices For JavaScript

Some of the best practices for JavaScript are below:

Always have declarations at the top.

Follow proper naming conventions for variables, functions, etc.

Use ‘comments’ consistently throughout the code.

Declare the local variables using the var keyword.

Always initialize variables.

Do not declare String, Number, or Boolean objects.

Always have ‘default case’ in switch.. case statements.

Have a close look at usage of == and === operators. Ensure that they are being used in the right place.

Place scripts at the bottom of the page.

Javascript Framework For Overcoming Cross Browser Compatibility Issues

It is a known fact that there would be cross browser compatibility issues for your web app or website, irrespective of the size or complexity of the app/website. As we have seen from the points mentioned above, the cross-browser compatibility issue magnifies when JavaScript is being used. But that doesn’t mean that you could avoid using JavaScript!

There exists multiple JS frameworks that facilitates development of cross browser compatible websites. Some of the most renowned ones are:

React JS Angular JS Vue JS Ionic Ember JS

These frameworks help to solves the problem of cross-browser compatibility for JavaScript. They also help developers to create a single-page application that is compatible across different browsers (Google Chrome, Mozilla Firefox, Safari, etc.).

Related Posts

1. Angularjs: A Developer’s First Choice.

2. Write Browser Compatible JavaScript Code using BabelJS.

3. Debugging Memory Leaks in JavaScript.

4. Progressive Enhancement and Cross Browser Compatibility.

5. Web Analytics Tools to Help You Understand Your Users.

Originally published at LambdaTest

Originally Written by Harshit Paul