All You Need to Know About Resize Observer in 6 Minutes

Akilesh Rao
JavaScript in Plain English
6 min readApr 11, 2023

--

Introduction

When you’re working with responsive design, you’ll come across many use cases where you’d want to respond to changes in an element’s size. You can hack your way through it using media queries when the viewport’s size changes but what if you want to change your layout when a particular element changes in size? You go for the Resize Observer.

You can also watch a video version of this, available on youtube.

Usage

To use the ResizeObserverAPI you simply create a new ResizeObserver object instance using the constructor. This instance will have an observe method that looks for changes to a specific element's size. A callback function set up inside the constructor then runs every time the size changes, providing access to the new dimensions and allowing you to do anything you like in response to those changes.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#box {
background: lightblue;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
const box = document.getElementById("box")
const cb = (entries) => {
console.log(entries);
}
const observer = new ResizeObserver(cb)
observer.observe(box)
</script>
</body>
</html>

So let’s look at this simple example. Inside the HTML file, we create a simple div tag with an id and some styles. Then inside the script, we get a reference to the div. We create a ResizeObserver instance using the constructor and we pass in our callback function to it. This function will have access to each resize entry. You can also access the observer itself using a second argument if you want to but that’s completely optional. For now, we’ll just console.log the resize entries inside this callback.

Finally, we’ll use the observe method on this observer instance and we’ll pass the div block inside this observer. You can also pass in an options object to this observer but for now, let’s run it as it is.

Now if you run this in the browser, you’ll find the div block inside the viewport. Inside the console, you’ll also find an array with a resize entry. So the moment an observer starts observing a target, an entry will be registered at the beginning. Any subsequent entries will originate only from the target element. Now let’s take a look at the resize entry in the console.

Resize entry

Each entry is going to have some properties that’ll provide you with information related to the current size of the element.

  • borderBoxSize and contentBoxSize will give you the latest sizes for borderBox and contentBox. The main difference between these two boxes is that borderBox will contain the padding and the border for the element along with its actual content. The content box will only have the main content.
    This actually comes from the box model. So basically every element that you can think of will appear to be like a box. This box has 4 parts to it separated by their respective edges. There’s the actual content, the padding, the border, and finally the margin. So borderBoxSize will have the combination of these 4 areas. ContentBoxSize will only have the content area.
  • ContentRect will give you the info related to the size and position of your target element. This contentRect is of the type DOMRect just like we saw in the previous blog post on Intersection Observer. It’ll have the position properties like the left, right, top, and bottom values along with size properties like its height and width.
  • Then we have the devicePixelContentSizeBox property which is an array of objects. Each object will have an inlineSize and a blockSize value. So essentially each block has a writing-mode property. To put it simply, the writing mode is the direction in which the text flows inside an element. Just take a look at this example from w3schools and you’ll know what I mean.
    So at any given point, both the blockSize and the inlineSize will either be the height or the width of the block depending upon the writing mode. If the writing mode is horizontal, then the blockSize will be the height and inlineSize will be the width. It kinda makes sense because block elements by default take the entire width of the container. So resizing a block element essentially means changing its height which is also the reason why inlineSize represents the width. Now if we change the writing mode to vertical, the blockSize will be the width and the inlineSize will be the height.
    You can actually try this out in the example. Just double the width of your block and set the writing mode to horizontal. You’ll see that when the writing mode is horizontal, the blockSize acts as the height and the inlineSize as the width. Now if you change the writing mode to vertical, the values will be switched. The blockSize will now become the width and the inlineSize will be the height.
    Now that we have a good understanding of these properties, let’s see why is it more than the original height and width. The reason is that the values inside inlineSize and blockSize deal with device pixels, not CSS pixels. So essentially every screen will have a bunch of pixels. A combination of those pixels forms a CSS pixel. The ratio between these two is called the devicePixelRatio. So if your device has a lot of pixels then the ratio goes up and so does the quality of the picture.
    Now the reason why I bring up this ratio is that that is the differentiating factor between the dimensions that we set vs the inline and blocksize values. So inside the browser console, try to access the devicePixelRatio that’s present on the window object. If you multiply this by the width or the height, you’ll get the corresponding inlineSize or blocksize values.
  • Finally, we have the target property which is the block that we’re observing.

Now that we’ve seen the resize entry let’s also quickly look at the options object that you can pass inside the observe method.

Options object

So when observing an element, you can pass in an options object along with that element. Currently, this object only has 1 option which is the box option. It lets you set the box model which the observer will observe, for your target element. You can pass these values for the box option.

  • content-box, which is also the default option, when set, the observer will observe changes only for the original content of the element. If the padding, margin, or border of the element changes, it’s not going to trigger a callback.
  • border-box when set, the observer will trigger a callback anytime any property inside the border-box changes. So the padding, the content or the border if any one of these 3 values changes, the observer will trigger a callback.
  • device-pixel-content-box is the final option which again is pretty much the same as content-box. The only difference is that any change in margin this time will also trigger a callback. To be honest, even I’m not sure why that’s the case but you’ll be using the first 2 options for the most part anyway. If you’re aware of this behavior and know what’s happening behind the scenes, do let me know in the comments.

Finally, just like any other observer, this one also has ways to disconnect or unsubscribe the observer from its target to avoid memory leaks. If you read the previous blog post on Intersection observers, you’ll find that it’s exactly the same. We have a disconnect method and an unobserve method. The disconnect will unsubscribe from all the target elements. So basically a single observer can observe multiple targets. If I use the disconnect method on the observer, it’ll stop observing all those targets. Unobserve will only stop observing a specific target, so you are supposed to pass in the target element inside this method.

Conclusion

And that should cover a good chunk of this API. In conclusion, the Resize Observer API is a powerful tool for engineers looking to create responsive web apps. With its ability to detect changes in the size of elements on a web page, it provides an efficient and effective way to handle layout and content changes without the need for frequent polling or manual calculations.

You can also watch a video version of this, available on youtube.

Apart from this, if you have any doubts or suggestions, you can put them in the comments or get in touch with me on any one of my socials. Cheers!

YouTube
LinkedIn
Twitter
GitHub

More content at PlainEnglish.io.

Sign up for our free weekly newsletter. Follow us on Twitter, LinkedIn, YouTube, and Discord.

Interested in scaling your software startup? Check out Circuit.

--

--