Quick guide to Resize Observer
Makar Murashov
Posted on July 4, 2022
We all try to make our apps and pages to be responsive: this is one of the main web-development standards for years. We strive to support all possible screen sizes while maintaining a friendly user interface. Everyone nowadays used to respond to viewport changes:
- either use Media queries in CSS
@media (mediaQueryString) {...}
[MDN] or in JSwindow.matchMedia(mediaQueryString)
[MDN] - or listen to window resize via
window.addEventListener('resize', ()=>{...})
But what if we need to watch the element size independent of the viewport? Say we have a web-component or autonomous block and want to update it whenever its width or height changes for any reason, something like Element.onResize(doSomething)
.
Today we are going to learn how to use the Resize Observer API by example.
API
The ResizeObserver interface reports changes to the dimensions of an Element's content or border box, or the bounding box of an SVGElement.
Observation will respond to every change of Element's size and fires if Element is rendered and itβs size is not 0,0
as well as when:
- Element is inserted/removed from DOM,
- Element display gets set to
none
.
Observation will do not fire for:
- non-replaced inline Elements (
span
,strong
,i
,b
,em
, etc), - changes to Element by CSS transforms.
The API provides us two instruments to work with: ResizeObserver
and ResizeObserverEntry
. Let's talk about them in specific.
ResizeObserver
ResizeObserver is used to observe changes to Element's size. All we need is to create our own instance and pass a callback function that will be fired every time, when the size changes:
(Here and below I will use TypeScript to show the exact types)
const myObserver = new ResizeObserver(
(entries: ResizeObserverEntry[], observer: ResizeObserver) => {
for (let entry of entries) {
// Do something with an entry (see in next section)
}
});
And then start to observe the desired element:
const myElement = document.getElementById('my-element');
myObserver.observe(myElement);
To stop watching the element we call unobserve()
method:
myObserver.unobserve(myElement);
To end observing all elements that were observed before by this instance:
myObserver.disconnect();
Options (optional)
ResizeObserver can observe different kinds of CSS sizes:
- content-box (default value): size of element's content area,
- border-box: size of element's box border area (content + padding + border),
-
device-pixel-content-box: size of element's content area in device pixels. Easier to understand it as
window.devicePixelRatio * contentSize
. Note that due to browser-specific subpixel calculations it's only approximately.
What size to watch can be passed as an option when starting to observe:
interface ResizeObserverOptions {
box?: 'content-box' | 'border-box' | 'device-pixel-content-box' | undefined;
}
const myOptions: ResizeObserverOptions = {
box: 'border-box'
};
myObserver.observe(myElement, myOptions);
However it will not affect the value returned by observer's callback, so use it only if you have a reason to.
ResizeObserverEntry
ResizeObserverEntry contains information about the element whose size has changed:
- target: the Element itself,
- contentBoxSize: size of content area,
- borderBoxSize: size of box border area,
- devicePixelContentBoxSize: size of content area in device pixels,
-
contentRect: the Element's DOMRect, same as if we call
Element.getBoundingClientRect()
directly.
Note that contentRect was added only due to current compatibility issues, it may be deprecated in next versions of ResizeObserver API. Consider not to use it in production.
Size
Every ...BoxSize
property of an Entry represents an array with ResizeObserverSize
object with 2 readonly sizes:
interface ResizeObserverSize {
readonly inlineSize: number;
readonly blockSize: number;
}
Think about it as width/height
element properties, so inlineSize
becomes width
and blockSize
becomes height
.
How to use
Usage is pretty easy, say we have a box of strawberries and getting them bigger make us really happy (and vice versa):
<h1>Mood: <span id="mood">π</span></h1>
<div id="box">
πππ
πππ
πππ
</div>
<form>
<label>
Love amount β€οΈ: <input id="grower" type="range" value="16" min="8" max="32" step="1">
</label>
</form>
Let's write some logic to grow our strawberries:
const mood = document.getElementById('mood')
const box = document.getElementById('box')
const grower = document.getElementById('grower')
grower.addEventListener('input', () => {
box.style.fontSize = grower.value + 'px'; // Give them some love to grow!
})
Now we can use ResizeObserver to change our mood depending on the box size:
const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
const { inlineSize: width } = entry.contentBoxSize[0];
mood.textContent = width > 90 ? "π" : width < 50 ? "π’" : "π";
}
});
resizeObserver.observe(box);
You can check how it works all together:
Another great example of the ResizeObserver API is scrolling down the chat window when a new message is added. An example can be seen here.
Browser support
Despite the fact that ResizeObserver API is still in Editorβs Draft(still in progress), according to Can I use its global 94.13%
support is pretty impressive. There is also a nice and powerful polyfill that allows you to use it in older browsers (even IE 9-10 π).
Hope you enjoyed this guide, stay tuned for more.
Posted on July 4, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.