Observe

As I’ve found applicability to use the trifecta of JavaScript observers in my projects, I’ve tried to blog about them. So far, I’ve written about MutationObserver and IntersectionObserver. On a recent project, I had the opportunity to use ResizeObserver.

Oftentimes, I re-use a styling technique for the <figure> element where the figure is relatively positioned, and the <figcaption> is absolutely positioned on top of the image. It’s a nice, accessible approach for header images.

The figure's caption is absolutely positioned on top of the image.
The figure’s caption is absolutely positioned on top of the image.

However, if the caption is very long on narrow viewports, the bounds of the caption exceed the height the image.

The caption exceeds the height of the image on narrow viewports.
The caption exceeds the height of the image on narrow viewports.

I needed a listener that actively compared the height of the caption against the height of the image. If the height of the caption exceeded the height of the image, dynamically set the height of the image to the height of the caption.

// check if ResizeObserver is supported
if( 'ResizeObserver' in window ){
var figcaption = document.querySelector( 'figcaption > h1.entry-title' );
var figure = document.querySelector( 'figure > div.post-thumbnail' );
// check if the elements exist
if( ( typeof( figcaption ) !== 'undefined' && figcaption !== null ) &&
( typeof( figure ) !== 'undefined' && figure !== null ) ){
var ro = new ResizeObserver( entries => {
for( let entry of entries ){
// get the height, including padding, of .entry-title
if( entry.target.tagName === 'H1' ){
var h1 = entry.target;
var h1cr = entry.contentRect;
var h1height = h1cr.height + h1cr.top;
}
// get the height, including padding, of .post-thumbnail
if( entry.target.tagName === 'DIV' ){
var div = entry.target;
var divcr = entry.contentRect;
var divheight = divcr.height + divcr.top;
}
// if .entry-title is taller than .post-thumbnail
if( h1height > divheight ){
// set the height of the image to the height of .entry-title
div.querySelector( 'img' ).style.height = h1height + 'px';
}
}
});
ro.observe( figcaption );
ro.observe( figure );
}
}
ResizeObserver dynamically adjusts the height of the image to match the height of the caption.
ResizeObserver dynamically adjusts the height of the image to match the height of the caption.

After a specific breakpoint, there was ample room for a caption regardless of its length. At that point, a stylesheet declaration takes care of setting the height of the image. I had to use !important to override the inline style set by my ResizeObserver. I try to avoid using !important at all costs, but it was simpler than complicating the JavaScript in order to unobserve the elements based on viewport width.