Navigation

A Dive Into Plain JavaScript

While I’ve worked over a decade building various websites, it has only been the past 3 years that I’ve started learning more on how to work with plain JavaScript, instead of using jQuery always as the starting point. The fact that I’m learning a dozen new things every day now, has made working on Adtile’s JavaScript SDK feel more like building an open source project than “actual work,” and I have to say I like that a lot.

Today, I’m going to share some of the basic things I’ve learned during the past years, which will hopefully also help you to dive into the world of plain JavaScript, making it easier to decide whether or not you will need jQuery in your next project.

Progressive Enhancement

While libraries like jQuery help to forget most of the browser inconsistencies, you really become familiar with them once you start using plain JavaScript for everything. To avoid writing JavaScript that’s full of browser hacks and code which only solves browser compatibility issues, I recommend building a progressively enhanced experience using feature detection to only target the more modern browsers. This doesn’t mean that browsers like IE7 don’t see anything at all, it just means that they get a more basic experience without JavaScript enhancements.

Here’s How We’re Doing It

We have a separate JavaScript partial called “feature.js” which has all the feature tests. The actual list of tests is much longer, but let’s get back to this a bit later. To rule out some of the older browsers we use these two tests:

Then, in the main application partial, we detect if these features are supported by using this simple "if" statement below. If they aren’t supported, the browser won’t execute any of this code:

if(feature.addEventListener&&feature.querySelectorAll){this.init();}

These two tests make sure that we have a native way of using CSS selectors in our JavaScript (querySelectorAll), a way to easily add and remove events (addEventListener) and also that the browser’s standards support is better than what IE8 has. Read more about this technique called “Cutting the mustard” from BBC’s blog.

Browser Support

Here’s a rough list of the browsers which support the features we are testing, and will hence keep executing the JavaScript:

IE9+

Firefox 3.5+

Opera 9+

Safari 4+

Chrome 1+

iPhone and iPad iOS1+

Android phone and tablets 2.1+

Blackberry OS6+

Windows 7.5+

Mobile Firefox

Opera Mobile

The Basics, Plain JavaSript Way

Let’s start looking how the most basic and often needed functionalities work in plain JavaScript, compared to jQuery. For each example, I’m going to provide both the jQuery and plain JavaScript approach.

Document Ready

With jQuery, many of you are probably used to using document.ready like so:

$(document).ready(function(){// Code});

But did you know that you can just put all of your JavaScript at the bottom of your page and that does basically the same thing? JavaScript has also an event listener for the DOM content loaded event which you can use instead of jQuery’s document.ready:

Quite straightforward, easy to understand, and doesn’t really require much more writing now does it? To go a little further, we could even build a tiny JavaScript library for ourselves for simple DOM querying. Here’s something that Andrew Lunny has came up with:

// This gives us simple dollar function and event bindingvar$=document.querySelectorAll.bind(document);Element.prototype.on=Element.prototype.addEventListener;// This is how you use it$(".element")[0].on("touchstart",handleTouch,false);

Traversing the DOM

Traversing the DOM with plain JavaScript is a bit harder than it is with jQuery. But not too hard. Here are some simple examples:

// Getting the parent nodevarparent=document.querySelector("div").parentNode;// Getting the next nodevarnext=document.querySelector("div").nextSibling;// Getting the previous nodevarnext=document.querySelector("div").previousSibling;// Getting the first child elementvarchild=document.querySelector("div").children[0];// Getting the last childvarlast=document.querySelector("div").lastElementChild;

Adding and Removing Classes

With jQuery, adding, removing and checking if an element has certain classes is really simple. It’s a bit more complex with plain JavaScript, but not too much so. Giving element a class called "foo" and replacing all the current classes:

// Select an elementvarelement=document.querySelector(".some-class");// Give class "foo" to the elementelement.className="foo";

That was quite straightforward, right? Next step, removing only certain classes, is a bit more complex. I’ve been using this small helper function in a separate partial called util.js. It takes 2 parameters: element and the class you want to remove:

// Check if an element has class "foo"if(hasClass(element,"foo")){// Show an alert message if it doesalert("Element has the class!");}

Introducing HTML5 classList API

If you only need to support more modern browsers like IE10+, Chrome, Firefox, Opera and Safari, you could also start using HTML5’s classList functionality which makes adding and removing classes even easier.

This is something, that I ended up doing with our latest Developer Docs, as the functionality I was developing, was more like an enhancement to the UI and not really something that would break the experience if it wasn’t present.

You can feature detect if the browser supports it by using this simple "if" statement:

if("classList"indocument.documentElement){// classList is supported, now do something with it}

Adding, removing and toggling classes with classList:

// Adding a classelement.classList.add("bar");// Removing a classelement.classList.remove("foo");// Checking if has a classelement.classList.contains("foo");// Toggle a classelement.classList.toggle("active");

One other benefit of using classList is that it will perform much better than using the raw className property. If you had an element like this:

With classList the underlying className is only altered when necessary. Given that we are adding a class that is already present and removing a class that isn’t, the className is never touched, meaning we’ve just avoided two repaints!

Event Listeners

Adding and removing event listeners from elements is almost as simple in plain JavaScript as it’s in jQuery. Things get a bit more complex when you have to add multiple event listeners, but I’ll explain that in a bit. The simplest example, which will just pop out an alert message when an element is clicked, is as follows:

One of JavaScript’s greatest features related to event listeners is the fact that "addEventListener" can take an object as a second argument that will automatically look for a method called "handleEvent" and call it. Ryan Seddon has covered this technique thoroughly in his article, so I’m just gonna give a fast example and you can read more about it from his blog:

Manipulating the DOM

Manipulating the DOM with plain JavaScript might sound like a horrible idea at first, but it really isn’t much more complex that using jQuery. Below, we have an example that selects an element from the DOM, clones it, manipulates the clone’s styles with JavaScript and then replaces the original element with the manipulated one.

// Select an elementvarelement=document.querySelector(".class");// Clone itvarclone=element.cloneNode(true);// Do some manipulation off the DOMclone.style.background="#000";// Replaces the original element with the new cloned oneelement.parentNode.replaceChild(clone,element);

If you don’t want to replace anything in the DOM, but instead append the newly created div inside the <body>, you could do it like this:

document.body.appendChild(clone);

If you feel like you’d want to read even more about different DOM methods, I’d suggest you to head over to Peter-Paul Koch’s DOM Core tables.

Diving Deeper

I’m going to share two bit more advanced techniques here, which I’ve recently discovered. These are both functionalities we have needed while building Adtile, so you might find these useful too.

Determining Max-Width of Responsive Images in JS

This is one of my own favorites, and it’s very useful if you ever need to manipulate fluid images with JavaScript. As browsers return the current resized dimensions of an image by default, we have to come up with some other solution. Luckily, modern browsers now have a way of doing this:

varmaxWidth=img.naturalWidth;

This will give us image’s max-width: 100% value in pixels and it’s supported in IE9, Chrome, Firefox, Safari and Opera. We can also take this further and add support for older browsers by loading the image into an in-memory object:

// Get image's max-width:100%; in pixelsfunctiongetMaxWidth(img){varmaxWidth;// Check if naturalWidth is supportedif(img.naturalWidth!==undefined){maxWidth=img.naturalWidth;// Not supported, use in-memory solution as fallback}else{varimage=newImage();image.src=img.src;maxWidth=image.width;}// Return the max-widthreturnmaxWidth;}

You should note that the images must be fully loaded before checking for the width. This is what we’ve been using to make sure they have dimensions:

Determining if an Element is in the Viewport

You can get the position of any element on the page using getBoundingClientRect method. Below is a simple function showing how simple and powerful it can be. This function takes one parameter, which is the element you want to check. It will return true when the element is visible:

// Determine if an element is in the visible viewportfunctionisInViewport(element){varrect=element.getBoundingClientRect();varhtml=document.documentElement;return(rect.top>=0&&rect.left>=0&&rect.bottom<=(window.innerHeight||html.clientHeight)&&rect.right<=(window.innerWidth||html.clientWidth));}

The above function could be used by adding a “scroll” event listener to the window and then calling isInViewport().

Conclusion

Whether or not you should use jQuery in your next project depends a lot on what you are building. If it’s something that requires large amounts of front-end code, you should probably use it. However, if you’re building a JavaScript plugin or a library, you might want to consider sticking with just plain JavaScript. Using plain JavaScript means fewer requests and less data to load. It also means that you aren’t forcing developers to add jQuery to their project just because of that dependency.

About the Author

Viljami is the Lead Front-End Designer at Adtile. He’s passionate about responsive design, CSS, JavaScript and web typography, and both tweets and writes actively about these subject. Viljami has been designing web sites for over a decade.