Scotts Web Dev Banner
Did you notice... every article on this site has an associated video? Consider subscribing to Scotts Web Dev on YouTube! :)

Lazy Load Maps or Videos With Intersection Observer

It doesn’t have to be a map or a video. By detecting when an element, particularly a dynamic or interactive element, comes into the viewport, you can load this element only when it is necessary and being viewed by the website visitor.

This will help improve your pagespeed score, website snappyness, and visitor satisfaction. Not to mention it saves on bandwidth as well. Why load a map when the visitor is at the top of the page and may never scroll down and see it?

Intersection Observer To The Rescue

Luckily, javascript provides us with Intersection Observer. This API can be used to let you know when elements are intersecting another element (or the viewport!).

We can write callback functions to be executed once an element is in view.

So using this API, we can detect when our map, video, or other interactive elment is being shown and swap out a placeholder for the real thing!

Complete Intersection Observer Example With Google Maps

<!DOCTYPE html>
<html lang="en-us">
	<head>
		<title>Scottsweb.dev - Intersection Observer</title>
		<style>
			.map iframe {
				background-color: #aeaeae;
			}
		</style>
	</head>
	<body>
		<p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p>
		<p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p><p>Long body</p>
		<div class="map">
			<iframe data-src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d224444.11301233878!2d-81.50747384832114!3d28.48137564259648!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x88e773d8fecdbc77%3A0xac3b2063ca5bf9e!2sOrlando%2C%20FL!5e0!3m2!1sen!2sus!4v1718831572772!5m2!1sen!2sus" width="600" height="450" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
		</div>

		<script>
			document.addEventListener('DOMContentLoaded', function() {
				let iframe = document.querySelector('.map iframe');

				let observerOptions = {
					root: null,
					rootMargin: '0px',
					threshold: 0.1
				}

				function loadMap(entries, observer) {
					entries.forEach(entry => {
						if (entry.isIntersecting) {
							iframe.setAttribute('src', iframe.getAttribute('data-src'));
							observer.unobserve(entry.target);
						}
					})
				}

				let observer = new IntersectionObserver(loadMap, observerOptions);
				observer.observe(iframe);
			});
		</script>
		
	</body>
</html>

Explaining The Intersection Observer Example

I’ve set up a super simple page with a bunch of paragraphs to create a page that scrolls. I then copied a Google Maps iframe element onto my page. I made sure to replace src= with data-src= so that it does not load on page load. I also gave the iframe a gray background to create a placeholder style.

Then, we use Intersection Observer to detect when the map is coming into view, and give the map a src with the value of the data-src in the map element.

Then, we are done with Intersection Observer so we call observer.unobserve();

What If Someone Has Javascript Disabled?

For the small percentage of users with javascript disabled, we can still take care of them. I didn’t show that in this example, but to do that we would add a noscript tag that included the map as is without changing anything. We would then hide the data-source version of the map. That would look like this:

<div class="map">
			<iframe data-src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d224444.11301233878!2d-81.50747384832114!3d28.48137564259648!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x88e773d8fecdbc77%3A0xac3b2063ca5bf9e!2sOrlando%2C%20FL!5e0!3m2!1sen!2sus!4v1718831572772!5m2!1sen!2sus" width="600" height="450" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
		</div>
<noscript>
      <div class="map-nojs">
      <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d224444.11301233878!2d-81.50747384832114!3d28.48137564259648!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x88e773d8fecdbc77%3A0xac3b2063ca5bf9e!2sOrlando%2C%20FL!5e0!3m2!1sen!2sus!4v1718831572772!5m2!1sen!2sus" width="600" height="450" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
      </div>
      <style>
      .map { display: none; }
      </style>
</noscript>

There you have it!

Be sure to check out other Front End Development articles or tips on improving pagespeed.