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.
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`);
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`);
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 asleft + width
.bottom
— the distance of the element's bottom edge from the top edge of the viewport. Effectively the same astop + height
.left
— the distance of the element from the left edge of the viewport.x
— an alias ofleft
.y
— an alias oftop
.
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:
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
is170
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
is8
. - 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:
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 ingetClientRects()
is the value ofleft
forgetBoundingClientRect()
. - 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;
}
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.
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;
}
Invoking getBoundingClientRect()
on the <span>
element returns back the following DOMRect
instance:
var clientRect = document.querySelector('#s1').getBoundingClientRect()
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
.
18
153.234375
17
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.