
Lazy Loading Avanzato: Immagini, Componenti e Moduli in Astro
Quando parliamo di ottimizzazione delle performance web, la prima regola che impariamo è: “Non caricare ciò che l’utente non sta guardando”.
Per le immagini, il web ci ha regalato una soluzione facilissima: basta aggiungere loading="lazy" al tag <img> e il browser fa il resto.
Ma cosa succede quando ad appesantire la pagina non è un’immagine, ma un componente interattivo, una libreria JavaScript enorme o un’animazione complessa situata nel footer? Il semplice attributo HTML non basta più.
In questo articolo vedremo come Astro e le API moderne del browser ci permettono di implementare un Lazy Loading avanzato per immagini, componenti e moduli, mantenendo il nostro bundle JavaScript leggero e le metriche Core Web Vitals impeccabili — un tassello che si aggiunge a quanto già raccontato nel mio articolo su Core Web Vitals nel 2026.
0. Le Immagini: loading="lazy" Non Basta (e a Volte è Dannoso)
Partiamo dalla base, perché qui si nascondono due errori comuni. Il primo: applicare loading="lazy" a tutte le immagini indiscriminatamente, inclusa quella dell’Hero in cima alla pagina. Quell’immagine è quasi sempre il tuo Largest Contentful Paint (LCP): ritardarne il caricamento con lazy peggiora proprio la metrica che vorresti migliorare. Per l’immagine principale sopra la piega usa invece loading="eager" (o ometti l’attributo) insieme a fetchpriority="high", per dire al browser “scarica subito questa, ha priorità”.
Il secondo errore è ignorare il componente <Image /> di Astro (astro:assets), che fa gran parte del lavoro pesante al posto tuo: genera automaticamente formati moderni (WebP/AVIF), calcola width/height per evitare Cumulative Layout Shift, e applica loading="lazy" e decoding="async" di default su tutte le immagini tranne quella marcata priority.
---
import { Image } from 'astro:assets';
import heroImg from '../assets/hero.jpg';
---
<!-- Immagine LCP: niente lazy, priorità massima -->
<Image src={heroImg} alt="Hero" loading="eager" fetchpriority="high" />
<!-- Immagine più in basso nella pagina: lazy è corretto qui -->
<Image src={heroImg} alt="Galleria" loading="lazy" />
1. Il “Superpotere” di Astro: Le Client Directives
Il vantaggio più grande dell’architettura a Isole di Astro è il controllo totale sull’idratazione (hydration) dei componenti. Se hai un componente interattivo pesante (es. un carosello di recensioni o un calcolatore di preventivi) che si trova a metà pagina, non ha senso eseguirne il JavaScript al caricamento iniziale.
Astro offre diverse Client Directives per controllare questo processo. Le più utili sono:
client:load: Idrata il componente immediatamente, appena la pagina finisce di caricare. Da riservare solo a componenti davvero critici sopra la piega (es. un menu di navigazione interattivo).client:idle: Dice ad Astro di caricare e idratare il componente solo quando il Main Thread del browser è libero. Perfetto per elementi visibili subito, ma non critici.client:visible: La vera magia. Astro utilizza l’Intersection Observer dietro le quinte per caricare il JavaScript del componente solo quando questo entra nella viewport dell’utente.client:media={query}: Idrata il componente solo se una media query CSS è verificata — utilissima per un componente che serve solo su mobile (es. il menu hamburger) e che su desktop non ha motivo di scaricare nemmeno un byte di JavaScript.
---
// Importiamo un componente React/Svelte/Vue pesante
import CalcolatorePreventivo from '../components/CalcolatorePreventivo.jsx';
---
<!-- Il codice JS verrà scaricato ed eseguito solo quando l'utente farà scroll fino a qui -->
<div class="mt-96">
<CalcolatorePreventivo client:visible/>
</div>
2. Dynamic Import (Moduli On-Demand)
A volte non hai un intero componente da ritardare, ma una libreria JavaScript massiccia. Pensa a librerie per grafici (Chart.js), per la validazione di form complessi o per la crittografia.
Invece di importarle in cima al file (il che le includerebbe nel bundle iniziale), puoi usare l’istruzione import() per caricarle dinamicamente solo quando un evento specifico si verifica, come il click di un pulsante.
<button id="btn-grafico">Mostra le Statistiche</button>
<div id="container-grafico"></div>
<script>
const btn = document.getElementById('btn-grafico');
btn.addEventListener('click', async () => {
// Cambia stato del bottone
btn.textContent = 'Caricamento...';
// Dynamic Import: il browser scarica la libreria SOLO ORA
const { default: Chart } = await import('chart.js/auto');
// Inizializza il grafico
const ctx = document.createElement('canvas');
document.getElementById('container-grafico').appendChild(ctx);
new Chart(ctx, { /* config */ });
btn.style.display = 'none';
});
</script>
Questo approccio salva centinaia di Kilobyte al caricamento iniziale, abbattendo drasticamente la metrica INP (Interaction to Next Paint) — la stessa logica “carica solo ciò che serve, solo quando serve” che ho applicato in prima persona quando ho raccontato la migrazione di un progetto da React ad Astro: spesso il problema non è il framework in sé, ma le centinaia di KB di JavaScript spediti al browser senza reale necessità.
3. L’Intersection Observer per Logiche Custom
Se stai lavorando con HTML puro in Astro e non stai usando framework UI esterni, potresti aver bisogno di attivare animazioni CSS, caricare video o immagini di background solo allo scroll. Per questo, l’API nativa IntersectionObserver è lo strumento definitivo.
Ecco un esempio di come attivare una classe di animazione solo quando un elemento appare sullo schermo, ottimizzato per girare nei tag <script> di Astro:
<div class="fade-in-element opacity-0 transition-opacity duration-1000">
Contenuto che appare dolcemente...
</div>
<script>
// Funzione che gestisce le intersezioni
const setupObserver = () => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Quando l'elemento è visibile, rimuovi l'opacità zero
entry.target.classList.remove('opacity-0');
// Smetti di osservarlo per risparmiare risorse
observer.unobserve(entry.target);
}
});
}, { rootMargin: '50px' }); // Inizia 50px prima che appaia
// Applica l'observer a tutti gli elementi target
document.querySelectorAll('.fade-in-element').forEach(el => observer.observe(el));
};
// Esegui al caricamento del DOM
document.addEventListener('DOMContentLoaded', setupObserver);
</script>
Conclusione
Affidarsi unicamente a loading="lazy" non è più sufficiente per costruire esperienze web di fascia alta. Gestire chirurgicamente quando e come il browser scarica JavaScript e media è ciò che differenzia un sito lento e goffo da un’applicazione scattante, capace di convertire gli utenti senza frustrarli. Sfruttando le direttive di Astro e i Dynamic Imports, ottieni il massimo risultato col minimo sforzo ingegneristico. E i millisecondi guadagnati non sono un esercizio accademico: come racconto nell’articolo su come la velocità del sito influenza le vendite, ogni secondo di attesa in meno si traduce direttamente in meno abbandoni e più conversioni.
Domande Frequenti
Cos'è il lazy loading avanzato e come impatta la SEO?
Il lazy loading avanzato ritarda il caricamento di JavaScript, moduli e componenti pesanti finché non entrano nella viewport. Questo riduce il Time to Interactive (TTI), abbatte la metrica INP dei Core Web Vitals e migliora sensibilmente il posizionamento SEO.
Come gestisce Astro il lazy loading dei componenti interattivi?
Astro utilizza le 'Client Directives' (come client:visible). Grazie alla sua Architettura a Isole, carica il codice JavaScript solo quando l'utente scorre fino a quel componente, mantenendo il resto della pagina in puro HTML statico e super performante.
Sviluppi siti web ad alte prestazioni (Core Web Vitals) nelle Marche?
Sì. Dal mio studio di Civitanova Marche sviluppo e ottimizzo piattaforme web ed e-commerce aziendali in Astro, garantendo caricamenti istantanei e metriche Lighthouse perfette per scalare le ricerche locali e nazionali.
Hai un progetto simile in mente?
Se questo articolo ti ha dato spunti utili, posso aiutarti a metterli in pratica sul tuo sito o progetto.
Richiedi un preventivo gratuito

