Is there a way to lazy load an embedded iframe? (Google Maps/youtube video)

I have youtube and google maps iframes on a website, which load immediately and hurt Lighthouse scores a lot. Any ideas?
66 Replies
MarkBoots
MarkBoots6mo ago
<iframe src="..." loading="lazy"> is already there for most browsers. Only FF is a bit behind, but I think they are rolling it out in the next release (december 19th?) https://caniuse.com/loading-lazy-attr
.suhaylmv
.suhaylmv6mo ago
it still loads a lot of js on page load
.suhaylmv
.suhaylmv6mo ago
No description
.suhaylmv
.suhaylmv6mo ago
No description
.suhaylmv
.suhaylmv6mo ago
Here's the website I'm working on if you want to test it out yourself https://www.amigosdelretiro.com/
Tu Lugar Favorito para Jugar al Ajedrez en Madrid - La Cabaña
Unete a cientos de personas que vienen cada dia para disfrutar de nuestras actividades, jugar al ajedrez y participar en torneos
ἔρως
ἔρως6mo ago
how about you only initialize google maps when the container is visible? you can use an intersection observer for this
vince
vince6mo ago
Also it's saying your 3rd party code (google maps) is blocking the main thread, and suggests to only load after your page has finished loading. So try using the defer or async attributes on your google scripts
ἔρως
ἔρως6mo ago
thats also a good solution i would use defer
.suhaylmv
.suhaylmv6mo ago
I'm so sorry for not responding @ἔρως @vince , with the new betterdiscord theme I can't see any changes on posts now I found a way to enable notifications on posts. didn't know about that earlier How can I do that? It's just an iframe, there aren't any google scripts
MarkBoots
MarkBoots6mo ago
remove the iframe src, and add it after the page load
.suhaylmv
.suhaylmv6mo ago
can you elaborate? how do I add it after the page load?
MarkBoots
MarkBoots6mo ago
in your script (with defer) you can select the iframe element and set the src
const iframe = document.querySelector("iframe");
iframe.src = "https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3387.566481098533!2d-3.685281591511207!3d40.413765905744626!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0xd42289ffa59b9c7%3A0x514c9aebb4ecd4d!2sLa%20Caba%C3%B1a.%20Asociaci%C3%B3n%20Amigos%20del%20Retiro!5e0!3m2!1ses-419!2ses!4v1702800521259!5m2!1ses-419!2ses"
const iframe = document.querySelector("iframe");
iframe.src = "https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3387.566481098533!2d-3.685281591511207!3d40.413765905744626!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0xd42289ffa59b9c7%3A0x514c9aebb4ecd4d!2sLa%20Caba%C3%B1a.%20Asociaci%C3%B3n%20Amigos%20del%20Retiro!5e0!3m2!1ses-419!2ses!4v1702800521259!5m2!1ses-419!2ses"
vince
vince6mo ago
very cool, never thought of that what's the benefit of that though when you have loading=lazy? That would defer it, so wouldn't setting the src manually be redundant?
MarkBoots
MarkBoots6mo ago
loading lazy could be useful for other iframe content than googlemaps. don't know what is happening exactly with lazy load, but maps has a lot going on in the url params
vince
vince6mo ago
ah so you're saying that loading=lazy might not be enough to totally defer the maps call, so it's better to defer it manually inside a script essentially?
MarkBoots
MarkBoots6mo ago
i guess so. but I didn't deepdive into it. This just came up to me as a quick solution
.suhaylmv
.suhaylmv6mo ago
it still loads content on every page load for me I also included a console.log in that script, and it executes on page load it doesn't happen to you right?
vince
vince6mo ago
Did you defer the script itself?
.suhaylmv
.suhaylmv6mo ago
<script defer>
const iframe = document.querySelector("iframe");
iframe.src =
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3387.566481098533!2d-3.685281591511207!3d40.413765905744626!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0xd42289ffa59b9c7%3A0x514c9aebb4ecd4d!2sLa%20Caba%C3%B1a.%20Asociaci%C3%B3n%20Amigos%20del%20Retiro!5e0!3m2!1ses-419!2ses!4v1702800521259!5m2!1ses-419!2ses";
console.log("arst");
</script>
<script defer>
const iframe = document.querySelector("iframe");
iframe.src =
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3387.566481098533!2d-3.685281591511207!3d40.413765905744626!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0xd42289ffa59b9c7%3A0x514c9aebb4ecd4d!2sLa%20Caba%C3%B1a.%20Asociaci%C3%B3n%20Amigos%20del%20Retiro!5e0!3m2!1ses-419!2ses!4v1702800521259!5m2!1ses-419!2ses";
console.log("arst");
</script>
like this: in astro
ἔρως
ἔρως6mo ago
no, add it with an intersection observer defer doesn't do anything for inline scripts
vince
vince6mo ago
I was wondering about that, cool ohh that would be good too
ἔρως
ἔρως6mo ago
no no, it would be perfect the iframe doesn't load until the user scrolls to it
vince
vince6mo ago
what if the user has a bad connection and they scroll to it and instead of it popping up quickly it takes 10 seconds to load? I know with google fonts you can preload it; can you do the same with google maps (without the performance hit of loading it all at once on page load)?
ἔρως
ἔρως6mo ago
then it is a google problem, not yours it's just google maps you can preload google fonts, but you also can use display: swap or whatever the property is, for the page to keep going and then swap the text with the newly downloaded font and if you don't host the fonts yourself, you're in violation of the GPDR but seriously, if it takes 30 minutes to load, it's fine just add a spinner or something on top of it or under it
vince
vince6mo ago
if only it was this simple 😂 spinner/loading animation is a good idea though
ἔρως
ἔρως6mo ago
spinner solves the issue
.suhaylmv
.suhaylmv6mo ago
I think it works now!
<script>
let observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
loadGoogleMaps();
console.log("intersecting...");
observer.unobserve(entry.target);
}
});
},
{ rootMargin: "0px", threshold: 1.0 },
);

observer.observe(document.querySelector(".map-container"));

function loadGoogleMaps() {
let mapContainer = document.querySelector(".map-container");
let iframe = document.createElement("iframe");

iframe.src =
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3387.566481098533!2d-3.685281591511207!3d40.413765905744626!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0xd42289ffa59b9c7%3A0x514c9aebb4ecd4d!2sLa%20Caba%C3%B1a.%20Asociaci%C3%B3n%20Amigos%20del%20Retiro!5e0!3m2!1ses-419!2ses!4v1702800521259!5m2!1ses-419!2ses";
iframe.width = "100%";
iframe.height = "100%";
iframe.style.border = "0";
iframe.title = "Mapa de la direccion de la Cabaña";

mapContainer.appendChild(iframe);
}
</script>
<script>
let observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
loadGoogleMaps();
console.log("intersecting...");
observer.unobserve(entry.target);
}
});
},
{ rootMargin: "0px", threshold: 1.0 },
);

observer.observe(document.querySelector(".map-container"));

function loadGoogleMaps() {
let mapContainer = document.querySelector(".map-container");
let iframe = document.createElement("iframe");

iframe.src =
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3387.566481098533!2d-3.685281591511207!3d40.413765905744626!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0xd42289ffa59b9c7%3A0x514c9aebb4ecd4d!2sLa%20Caba%C3%B1a.%20Asociaci%C3%B3n%20Amigos%20del%20Retiro!5e0!3m2!1ses-419!2ses!4v1702800521259!5m2!1ses-419!2ses";
iframe.width = "100%";
iframe.height = "100%";
iframe.style.border = "0";
iframe.title = "Mapa de la direccion de la Cabaña";

mapContainer.appendChild(iframe);
}
</script>
used a bit of help from gpt4 not gonna lie...
ἔρως
ἔρως6mo ago
that looks horrible but yes, that should work
.suhaylmv
.suhaylmv6mo ago
anything to improve?
ἔρως
ἔρως6mo ago
remove these lines:
iframe.width = "100%";
iframe.height = "100%";
iframe.style.border = "0";
iframe.title = "Mapa de la direccion de la Cabaña";
iframe.width = "100%";
iframe.height = "100%";
iframe.style.border = "0";
iframe.title = "Mapa de la direccion de la Cabaña";
.suhaylmv
.suhaylmv6mo ago
why?
ἔρως
ἔρως6mo ago
well, do you have a .map-container? or is it just the iframe thrown there?
.suhaylmv
.suhaylmv6mo ago
yeah
ἔρως
ἔρως6mo ago
well, you can (and should) size the iframe with css, to get the same effect you can add a css to apply the styles there to the iframe instead
.suhaylmv
.suhaylmv6mo ago
I removed the first 3 lines and it works the same I think not sure why I had that inside the iframe before I should leave the iframe title though nope, it broke I'll leave it as it is afaik iframes need width and height specified in attributes
ἔρως
ἔρως6mo ago
the title is absolutely useless for an iframe it breaks if you don't add the css for it but well, leaving the other 3 lines in isn't the end of the world
.suhaylmv
.suhaylmv6mo ago
isn't it useful for accesibility? or maybe SEO
ἔρως
ἔρως6mo ago
seo? no, google can't read the title from it accessibility? eh, never tested it, but i guess doesn't hurt
.suhaylmv
.suhaylmv6mo ago
ok thanks for helping me!
ἔρως
ἔρως6mo ago
you can change the margin to be a little bit on the inside, so the iframe loads when it is actually visible
ἔρως
ἔρως6mo ago
the iframe is loaded by javascript and javascript that detects the browser position for seo, use microdata or some other micro format
.suhaylmv
.suhaylmv6mo ago
Tu Lugar Favorito del Retiro para Jugar al Ajedrez - La Cabaña
Unete a cientos de personas que vienen cada dia para disfrutar de nuestras actividades, jugar al ajedrez y participar en torneos
.suhaylmv
.suhaylmv6mo ago
is there a way to set some margin to the intersection observer?
vince
vince6mo ago
I don't know if crawlers can index based off scroll, but I'm pretty sure they can "wait" for javascript content to load. I'd have to look into that
.suhaylmv
.suhaylmv6mo ago
so it loads the map a little earlier?
vince
vince6mo ago
dude the typography is really clean
.suhaylmv
.suhaylmv6mo ago
no idea
vince
vince6mo ago
great font choice
.suhaylmv
.suhaylmv6mo ago
thankss)
vince
vince6mo ago
yea I think it's the rootMargin property but I could be wrong
ἔρως
ἔρως6mo ago
if it uses an headless instance of chrome for it, it's possible, but very computational expensive yes, it is
vince
vince6mo ago
<script>
let observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
loadGoogleMaps();
console.log("intersecting...");
observer.unobserve(entry.target);
}
});
},
{ rootMargin: "0px", threshold: 1.0 }, // here
);

...
<script>
let observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
loadGoogleMaps();
console.log("intersecting...");
observer.unobserve(entry.target);
}
});
},
{ rootMargin: "0px", threshold: 1.0 }, // here
);

...
ἔρως
ἔρως6mo ago
yup, that's what i was talking about you should optimize your images the cover image is massive in images, you have 1.1mb our of 2.1mb for your website
vince
vince6mo ago
Also your cover image uses .avif which isn't supported in all browsers iirc, be careful with that
ἔρως
ἔρως6mo ago
and the scroll is absolutely horrible on desktop you do have a few bugs with the animations personally? i hate these annoying animations with shit flying all over
vince
vince6mo ago
I like it but I think the site is a little bit too simple and I feel like you're using animations to make up for it. You have really good typography and color scheme going on though. Anyway offtopic lol
ἔρως
ἔρως6mo ago
don't think the typography is the best for this section but the map, well ... it works, but you only have a gaping hole there and you don't put the gps coordinates there by the way, use the more semantically correct <address> element as well: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/address
.suhaylmv
.suhaylmv6mo ago
can you explain more in detail? totally agree, I was thinking a lot about this, but couldn't come up with anything at the end to make the design more rich I hope with time I'll come up with something you mean the beige section?
vince
vince6mo ago
i've been thinking a lot about this site lately. i think they do a really good job of keeping it simple but making it interesting https://grassrootsonline.org/. maybe you can get some inspiration from it
.suhaylmv
.suhaylmv6mo ago
I don't understand thanks, I'll check it out
ἔρως
ἔρως6mo ago
the title yes you have the address, but not the gps coordinates
.suhaylmv
.suhaylmv6mo ago
why gps coordinates? ok.
ἔρως
ἔρως6mo ago
well, gps coordinates are important for people to put it into google maps and find the place and also for old-school people who don't use google maps, but have a perfectly capable gps that's ok-ishly updated
.suhaylmv
.suhaylmv6mo ago
it's a place inside a park in the middle of the city, please tell me how the fuck a person can prefer using a gps instead of a mobile phone
ἔρως
ἔρως6mo ago
old-school people