Course: JavaScript

Progress (0%)

CSSOM Client

Chapter 56 22 mins

Learning outcomes:

  1. The outerWidth and outerHeight properties
  2. The screenLeft and screenTop properties
  3. The getClientRects() method
  4. The DOMRectList and the DOMRect interfaces
  5. The getBoundingClientRect() method

Introduction

The last chapter expanded upon the idea of the browser's viewport where the underlying web page is actually displayed. Now, it's time to talk about the window containing the viewport.

In this chapter, we'll learn how to get the dimensions of the browser window and its offset relative to the screen using the outerWidth/outerHeight and screenLeft/screenTop global properties, respectively. We'll also take a look over how to get the same kind of values for individual elements using the getBoundingClientRect() and getClientRects() methods of the Element interface.

Getting the window's dimensions

Recall from the previous JavaScript CSSOM Viewport chapter that the viewport's dimensions are represented by the global innerWidth and innerHeight properties.

On the same lines, to get the dimensions of the browser window, we have the global properties outerWidth and outerHeight.

outerWidth returns back a number representing the width of the whole browser window, in CSS pixels. The same goes for outerHeight, but this time for the height of the browser window instead of its width.

To help better understand the behavior of outerWidth and outerHeight, as compared to innerWidth and innerHeight, consider the figure below.

A depiction of innerWidth/innerHeight vs. outerWidth/outerHeight
A depiction of innerWidth/innerHeight vs. outerWidth/outerHeight

Alright, let's now take a look over a very basic example.

In the following code, we alert the window's width and height as soon as the underlying script is executed:

alert(`Width: ${outerWidth}px; Height: ${outerHeight}px`);

Live Example

In the example above, try resizing the browser window if you're on a desktop device. Once you're done with the resizing, refresh the page in order to get alerted with the new dimensions of the browser window.

Getting the window's positions

Besides getting the window's dimensions, we can also obtain its position relative to the top and left edge of the screen. Once again, since this concern is related to the browser window, we have the provision of the properties screenLeft and screenTop on window.

Precisely speaking, screenLeft returns a number representing the distance of the browser window from the left edge of the screen, whereas screenTop returns a number representing the distance from the top edge of the screen.

In older browsers, the screenLeft and screenTop properties aren't available. Instead, we ought to resort back to the same properties screenX and screenY, respectively.

In the following code, we alert the values of screenLeft and screenTop:

alert(`Distance from left: ${screenLeft}px, from top: ${screenTop}px`);

Live Example

In the example above, try resizing the browser window and moving it around as well. Once you're done, refresh the page in order to get alerted with the new offset of the browser window.

The getClientRects() method

Often times when we are working with elements on a web page, we are interested in figuring out their width, height, and their distance from one or more of the four edges of the viewport. In this regard, we can use the following methods of the Element interface.

In this regard, we can use the following methods of the Element interface: getClientRects() and getBoundingClientRect().

We'll start with getClientRects() and then move over to the latter method, i.e. getBoundingClientRect().

The getClientRects() method was first introduced, back in the day, by Internet Explorer. Soon, by virtue of the fact that it turned out to provide useful geometric description for a given element, it was eventually standardized by the W3C and implemented by other browser vendors thereafter.

The idea behind getClientRects() is very simple. It returns back a list of objects, each of which describes the size and position of a border box of the element under inspection.

In particular, getClientRects() returns back a DOMRectList instance containing DOMRect instances.

A DOMRectList is just a basic kind of a list type, similar in many ways to a NodeList. As with all sequence interfaces in JavaScript, it defines a length property and also allows the usage of bracket notation to access individual elements.

A DOMRect object provides us with the size and position of a given border box of an element. It contains the following eight properties:

  • width — the computed width of the element.
  • height — the computed height of the element.
  • top — the distance of the element from the top edge of the viewport.
  • right — the distance of the element's right edge from the left edge of the viewport. Effectively the same as left + width.
  • bottom — the distance of the element's bottom edge from the top edge of the viewport. Effectively the same as top + height.
  • left — the distance of the element from the left edge of the viewport.
  • x — an alias of left.
  • y — an alias of top.

Typically, as elements are rendered on a web page, they have a single border box associated with them. But at time, it happens that an element, displayed inline, is broken down into two or more separate lines on the webpage.

And this is usually when the element consists of text that overflows on a new line. In this case, getClientRects() computes the dimensions of each border box separately and creates a new DOMRect instance for each one.

Simple?

Why is it called 'getClientRects'?

You might be wondering as to why exactly is getClientRects() named this way. In other words, you might be thinking about the meaning of the word 'Client' or 'Rects' in there.

Starting with the easiest thing, the border box of an element is a rectangle in shape, and getClientRects() provides us with that, hence the term 'Rects'. The plural nature of the word implies that the method returns back a list of such 'rectangles', not just a single 'rectangle'.

As for the term 'client', it's simply used to imply the fact that the method getClientRects() takes the client (i.e. the browser window) into consideration when computing the dimensions and the position of a particular element's border box therein.

Now does the name 'getClientRects' make sense?

Let's take a look over some examples.

We'll start with most elementary one and then move over to consider those examples where the element has more than one rendered border box.

Consider the following HTML + CSS code:

<div id="d1">Here we have some text.</div>
#d1 {
   background-color: lightgrey;
   height: 150px;
   width: 150px;
   padding: 10px;
}

Here's the output of this code:

Here we have some text.

Now, let's inspect the geometry of this <div> element with the help of the getClientRects() method:

var divElement = document.querySelector('#d1');
var clientRects = divElement.getClientRects();

console.log(clientRects);
DOMRectList {0: DOMRect, length: 1}

Clearly, as we can see, the <div> element just has one border box and likewise, getClientRects() returns a list containing just a single DOMRect instance.

Let's go ahead and retrieve some of the properties of this DOMRect instance (keeping in mind that the page hasn't been scrolled from its initial position):

clientRects[0].width
170
clientRects[0].height
170
clientRects[0].top
8
clientRects[0].left
8

It's not really difficult to make intuition of each of these values:

  • clientRects[0].width is 170 since the width of <div> is 150px plus the 10px padding on each side, adding up to 170px.
  • The same goes for clientRects[0].height.
  • By default, the <body> element has a margin of around 8px. This gets the <div> element to be slightly far away from the very top-left corner of the viewport. Hence, clientRects[0].top is 8.
  • The same goes for clientRects[0].left.

Time for example number two.

Consider the following HTML + CSS code:

<div id="d1">
   This is some <span id="s1">thing to appreciate about the getClientRects() method.</span>
</div>
#d1 {
   background-color: lightgrey;
   height: 150px;
   width: 150px;
   padding: 10px;
}

#s1 {
   background-color: yellow;
   border: 1px solid red;
}

Here's the output of this code:

This is some thing to appreciate about the getClientRects() method.

See how the <span> element is broken down into multiple lines. Also notice how the border is displayed. The right border is only applied to the third line — the previous two lines being borderless on both their left and right sides.

Now, as before, let's go on and see the return value of getClientRects() as invoked upon this <span> element:

var spanElement = document.querySelector('#s1');
var clientRects = divElement.getClientRects();

console.log(clientRects);
DOMRectList {0: DOMRect, 1: DOMRect, 2: DOMRect, 3: DOMRect, length: 4}

As expected, it returns a list containing 4 elements, for the 4 border boxes shown above.

In the snippet below, we retrieve the width of each of these four border boxes:

clientRects[0].width
50.34375
clientRects[1].width
128.828125
clientRects[2].width
104.859375
clientRects[3].width
53

The first and the last border box are quite similar in length and that's also apparent in the values of clientRects[0].width and clientRects[3].width. The second box is the largest while the third box is the second-largest and likewise, clientRects[1].width returns the largest value and clientRects[2].width returns the second-largest one.

The getBoundingClientRect() method

Besides getClientRects(), the getBoundingClientRect() method of the Element interface is also another handy method to retrieve the geometric description of a given element's bounding box.

If you don't know of it, the bounding box of an element is simply the smallest box that encapsulates all the border boxes of the element.

The getBoundingClientRect() method returns back a single DOMRect instance, describing the bounding box around a given element; hence the word 'Rect' at the end of the method's name instead of 'Rects' (as in getClientRects()).

Internally, getBoundingClientRect() uses the routine of getClientRects() to obtain the dimensions and the position of the bounding box of a given element using the geometry of its individual border boxes.

And the idea used here is really simple:

  • The left-most edge amongst all the border boxes is the left edge of the bounding box. In other words, the minimum value of left amongst all entries in getClientRects() is the value of left for getBoundingClientRect().
  • The right-most edge amongst all the border boxes is the right edge of the bounding box.
  • The top-most edge amongst all the border boxes is the top edge of the bounding box.
  • The bottom-most edge amongst all the border boxes is the bottom edge of the bounding box.

Simple?

Due to the fact that getBoundingClientRect() returns a single DOMRect instance, and not a list of such instances, you'll typically notice it to be used a lot more than getClientRects().

We don't have to worry about multiple boxes, if there are any — getBoundingClientRect() takes all of them into account and provides us with a nice geometric description of a single box, i.e. the bounding box.

Let's consider a couple of examples.

Following, we have the same <div> example that we had at the start of the section above:

<div id="d1">Here we have some text.</div>
#d1 {
   background-color: lightgrey;
   height: 150px;
   width: 150px;
   padding: 10px;
}
Here we have some text.

Let's inspect the geometry of this <div> element as before, but this time with the help of the getBoundingClientRect() method:

var divElement = document.querySelector('#d1');
var clientRect = divElement.getBoundingClientRect();

console.log(clientRect);
DOMRect {x: 8, y: 8, width: 170, height: 170, top: 8, …}

When there is just one border box of an element, the DOMRect instance returned by getBoundingClientRect() and the first (and the only) DOMRect instance in the list returned by getClientRects() are exactly the same in terms of the values of their properties.

Each time getClientRects() or getBoundingClientRect() is called, a completely new object is created and thereby returned. Therefore, two different DOMRect instances for the same element might have the same property values but internally they're always going to be two disparate objects.

Let's now reconsider another example from the section above, specifically the one where we had a <span> element with four border boxes.

<div id="d1">
   This is some <span id="s1">thing to appreciate about the getClientRects() method.</span>
</div>
#d1 {
   background-color: lightgrey;
   height: 150px;
   width: 150px;
   padding: 10px;
}

#s1 {
   background-color: yellow;
   border: 1px solid red;
}
This is some thing to appreciate about the getClientRects() method.

Invoking getBoundingClientRect() on the <span> element returns back the following DOMRect instance:

var clientRect = document.querySelector('#s1').getBoundingClientRect()
undefined
clientRect
DOMRect {x: 18, y: 17, width: 135.234375, height: 73, top: 17, …}

Let's see the values of each of the following properties of clientRect: left, right, top and bottom.

clientRect.left
18
clientRect.right
153.234375
clientRect.top
17
clientRect.bottom
90

Can you use the getClientRects() method on the <span> element and obtain these very values?

Well, it's a really simple task. We get you to accomplish it in the next exercise.

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage