Thinking Inside The Box With Vanilla JavaScript
During the past four or five years of blogging regularly and doing research for other writing projects, I’ve come across probably thousands of articles on JavaScript.
To me, it seems that a big chunk of these articles can be divided into two very general categories:
Yes, I’ve likely stumbled upon a ton of other articles that don’t fall into either of these categories or that are more specific. But somehow it feels that most of the ones that really get pushed in the community fall under one of the two categories above.
I think those articles are great, and I hope we see more of them. But sometimes the simplest JavaScript features are sitting right under our noses and we just haven’t had a lot of exposure to them. I’m talking about native, more-or-less cross-browser features that have been in the language for some time.
So, in this article, I won’t be talking about jQuery, and I won’t be looking at structural code concepts or patterns. Instead, I’m going to introduce you to some pure JavaScript features that you can use today and that you might not have ever considered before.
insertAdjacentHTML()
Years ago, Microsoft introduced a method called insertAdjacentHTML()
as a way to insert a specified string of text as HTML or XML into a specific place in the DOM. This feature has been available in Internet Explorer (IE) since version 4. Let’s see how it works.
Suppose you have the following HTML:
<div id="box1">
<p>Some example text</p>
</div>
<div id="box2">
<p>Some example text</p>
</div>
And suppose you want to insert another snippet of HTML between #box1
and #box2
. You can do this quite easily using insertAdjacentHTML()
:
var box2 = document.getElementById("box2");
box2.insertAdjacentHTML('beforebegin', '<div><p>This gets inserted.</p></div>');
With that, the generated DOM ends up like this:
<div id="box1">
<p>Some example text</p>
</div>
<div><p>This gets inserted.</p></div>
<div id="box2">
<p>Some example text</p>
</div>
The insertAdjacentHTML()
method takes two parameters. The first defines where you want to place the HTML, relative to the targeted element (in this case, the #box2
element). This may be one of the following four string values:
beforebegin
The HTML would be placed immediately before the element, as a sibling.afterbegin
The HTML would be placed inside the element, before its first child.beforeend
The HTML would be placed inside the element, after its last child.afterend
The HTML would be placed immediately after the element, as a sibling.
Again, these are string values, not keywords, so they must be placed inside of single or double quotes.
The second parameter is the string you want to insert, also placed in quotes (or else it would be a variable holding a string that was previously defined). Note that it should be a string, not a DOM element or element collection; so, it could just be text, with no actual markup.
insertAdjacentHTML()
has, as outlined in a post on Mozilla Hacks, a couple of advantages over something more conventional, like innerHTML()
: It does not corrupt the existing DOM elements, and it performs better.
And if you’re wondering why this one hasn’t received a lot of attention so far, despite being well supported in all in-use versions of IE, the reason is probably that, as mentioned in the Mozilla Hacks article, it was not added to Firefox until version 8. Because all other major browsers support this, and Firefox users have been auto-updating since version 5, it’s quite safe to use.
For more on this method:
- “insertAdjacentHTML(),” in the “DOM Parsing and Serialization” specification, WHATWG
- “Element.insertAdjacentHTML,” Mozilla Developer Network
getBoundingClientRect()
You can obtain the coordinates and, by extension, the dimensions of any element on the page using another lesser-known method, the getBoundingClientRect()
method.
Here’s an example of how it might be used:
var box = document.getElementById('box'),
x, y, w;
x = box.getBoundingClientRect().left;
y = box.getBoundingClientRect().top;
if (box.getBoundingClientRect().width) {
w = box.getBoundingClientRect().width; // for modern browsers
} else {
w = box.offsetWidth; // for oldIE
}
console.log(x, y, w);
Here, we’ve targeted an element with an ID of box
, and we’re accessing three properties of the getBoundingClientRect()
method for the #box
element. Here’s a summary of six fairly self-explanatory properties that this method exposes:
top
How many pixels the top edge of the element is from the topmost edge of the viewportleft
How many pixels the left edge of the element is from the leftmost edge of the viewportright
How many pixels the right edge of the element is from the leftmost edge of the viewportbottom
How many pixels the bottom edge of the element is from the topmost edge of the viewportwidth
The width of the elementheight
The height of the element
All of these properties are read-only. And notice that the coordinate properties (top
, left
, right
and bottom
) are all relative to the top-left of the viewport.
What about the if/else
in the example from above? IE 6 to 8 don’t support the width
and height
properties; so, if you want full cross-browser support for those, you’ll have to use offsetWidth
and/or offsetHeight
.
As with insertAdjacentHTML()
, despite the lack of support for width
and height
, this method has been supported in IE since ancient times, and it has support everywhere else that’s relevant, so it’s pretty safe to use.
I will concede something here: Getting the coordinates of an element using offset-based values (such as offsetWidth
) is actually faster than using getBoundingClientRect()
. Note, however, that offset-based values will always round to the nearest integer, whereas getBoundingClientRect()
’s properties will return fractional values.
For more info:
- “Element.getBoundingClientRect,” Mozilla Developer Network
- “getBoundingClientRect Is Awesome,” John Resig