
📱 JavaScript: come rilevare la larghezza dello schermo, l'equivalente della @media query nel codice
A volte il layout è già pronto, le media query CSS sono al lavoro, ma serve rilevare un comportamento a un breakpoint specifico direttamente in JavaScript. Mostrare un popup solo su dispositivi mobili, riorganizzare una griglia al resize, attivare un’animazione quando lo schermo è «stretto»: tutto questo richiede che lo script conosca la larghezza corrente della finestra.
Il problema è che spesso gli sviluppatori scelgono la strada più complicata: leggono window.innerWidth, aggiungono un throttle al resize, confrontano con numeri magici e finiscono con codice fragile che vive separato dai breakpoint CSS. Eppure i browser hanno da tempo un metodo che lavora con le stesse espressioni media dei CSS.
Ecco tre approcci pratici: dal moderno matchMedia (funziona come @media nei CSS) a una variante jQuery per progetti legacy. Con esempi live che puoi copiare ed eseguire subito.
💡 Panoramica rapida:
matchMedia: un metodo nativo che accetta un’espressione media CSS e indica se al momento corrisponde; ideale per sincronizzare la logica JS con i breakpoint CSSresize+matchMedia: una combinazione che reagisce ai cambiamenti della finestra del browser; lo script viene a sapere del superamento di un breakpoint all’istante, senza interrogare periodicamenteinnerWidth- variante jQuery: per progetti in cui jQuery è già presente nella pagina; lo stesso
resize, ma senzamatchMedianativo; il confronto avviene tramite$(window).width()
MatchMedia: la fonte unica di verità per la larghezza dello schermo
Il principale difetto di window.innerWidth è che non sa nulla dei tuoi breakpoint CSS. Imposti 768px nelle media query, poi scrivi if (window.innerWidth < 768) in JS, e alla fine l’arrotondamento o la barra di scorrimento rompono la sincronizzazione.
window.matchMedia() risolve questo problema alla radice: accetta la stessa stringa di espressione media della regola CSS @media. Il risultato è un oggetto MediaQueryList con una proprietà .matches (true / false). Niente numeri magici, nessuna discrepanza con il layout.
Sintassi di base:
1 const mq = window.matchMedia("(min-width: 768px)"); 2 3 if (mq.matches) { 4 console.log("Tablet or wider — 768px+"); 5 } else { 6 console.log("Mobile resolution — less than 768px"); 7 }
La stessa chiamata matchMedia("(min-width: 768px)") viene valutata dal browser usando le stesse regole di @media (min-width: 768px) nei CSS. Se la sidebar è nascosta a questo breakpoint nei CSS, JS «vede» la stessa cosa e può, per esempio, nascondere il menu mobile.
Oltre a .matches, l’oggetto MediaQueryList fornisce una proprietà .media (la stringa di query originale) e un metodo addEventListener per sottoscriversi ai cambiamenti. Questo significa che una volta dichiarato un breakpoint in una configurazione, puoi usarlo sia nei CSS sia in JS senza duplicare numeri magici: basta estrarre 768 in una costante e inserirla in entrambi i punti.
Reagire al resize senza throttle e workaround
Verificare «adesso» è solo metà della sfida. La vera magia inizia quando lo script viene a sapere del superamento di un breakpoint nel momento in cui la finestra cambia.
MediaQueryList ha un evento change che si attiva esattamente quando il valore .matches commuta. Non a ogni pixel di resize, ma solo quando si attraversa il confine:
1 const mq = window.matchMedia("(min-width: 500px)"); 2 3 mq.addEventListener("change", function (e) { 4 if (e.matches) { 5 console.log("Screen expanded to 500px or more"); 6 } else { 7 console.log("Screen narrowed to less than 500px"); 8 } 9 });
Per retrocompatibilità con browser più vecchi, puoi ottenere lo stesso risultato tramite un gestore resize generico su window:
1 window.addEventListener("resize", function () { 2 if (window.matchMedia("(min-width: 500px)").matches) { 3 console.log("Screen width — at least 500px"); 4 } else { 5 console.log("Less than 500px"); 6 } 7 });

La differenza è semplice: change su MediaQueryList è un approccio guidato dagli eventi (nessuna chiamata extra durante il resize all’interno di un intervallo), mentre resize su window è un fallback familiare a qualsiasi sviluppatore.
Intervallo di larghezza: tra due breakpoint
Un’esigenza comune è «da 769px a 1024px». Anche qui matchMedia funziona come i CSS: combina min-width e max-width in un’unica espressione:
1 window.addEventListener("resize", function () { 2 if ( 3 window.matchMedia("(min-width: 769px)").matches && 4 window.matchMedia("(max-width: 1024px)").matches 5 ) { 6 console.log("Tablet range: 769px – 1024px"); 7 } else { 8 console.log("Outside the tablet range"); 9 } 10 });
Oppure come espressione singola (i browser comprendono le media query composte esattamente come nei CSS):
1 const tablet = window.matchMedia("(min-width: 769px) and (max-width: 1024px)"); 2 3 tablet.addEventListener("change", function (e) { 4 console.log(e.matches ? "Entered tablet range" : "Left tablet range"); 5 });
Quale variante scegliere? change su MediaQueryList quando devi catturare il momento esatto del superamento del confine (per esempio, per ristrutturare l’albero DOM). resize + matchMedia quando la logica è più semplice e ti basta «verificare adesso» senza sottoscriverti a transizioni future.
Variante jQuery: quando matchMedia non è disponibile
Se il progetto usa jQuery e i polyfill non sono un’opzione, lo stesso risultato si ottiene confrontando $(window).width() con un valore soglia:
1 jQuery(document).ready(function ($) { 2 if ($(window).width() > 1000) { 3 console.log("Screen width greater than 1000px"); 4 } else { 5 console.log("Screen width 1000px or less"); 6 } 7 });
Questo codice viene eseguito una volta al caricamento della pagina. Per tracciare il resize, avvolgi il controllo in un gestore:
1 jQuery(document).ready(function ($) { 2 function checkWidth() { 3 if ($(window).width() > 1000) { 4 console.log("Width > 1000px"); 5 } else { 6 console.log("Width ≤ 1000px"); 7 } 8 } 9 10 checkWidth(); // initial run 11 $(window).on("resize", checkWidth); 12 });
Ma ricorda: $(window).width() e matchMedia possono differire di qualche pixel a causa della barra di scorrimento. matchMedia lavora con il viewport, proprio come le regole CSS. Ecco perché consiglio il metodo nativo per tutto il codice nuovo.
MatchMedia vs innerWidth: un confronto sintetico
Criterio |
|
|
|---|---|---|
Sincronizzazione con i CSS | Completa (stesse espressioni) | Regolazione manuale dei numeri |
Evento al superamento del breakpoint |
| Solo |
Gestione della barra di scorrimento | Come i CSS (viewport) | Dipende dal browser |
Rilevazione tema scuro / | Sì (qualsiasi espressione media) | No |
⁉️🤔 Domande frequenti
Cosa è meglio: matchMedia o window.innerWidth?
matchMediaè sempre preferibile quando la logica è legata ai breakpoint CSS. Usa le stesse regole di@media, eliminando discrepanze di uno o due pixel dovute alla barra di scorrimento o allo zoom.innerWidthè appropriato solo quando serve il valore numerico esatto (per esempio, per calcolare quanti elementi ci stanno), non il fatto «schermo più largo di N pixel».
matchMedia funziona nei browser più vecchi?**
Sì, il supporto è ampio: tutti i browser moderni, inclusi quelli mobile, e Internet Explorer 10+. IE9 e versioni precedenti restano esclusi; per loro dovrai usare
window.innerWidtho la variante jQuery di questo articolo. In pratica, la quota di IE9 nel 2026 tende a zero.
matchMedia può verificare più della sola larghezza?**
Sì, il metodo accetta qualsiasi espressione media CSS valida. Per esempio:
(orientation: portrait)per l’orientamento del dispositivo;(prefers-color-scheme: dark)per il tema scuro nel sistema operativo;(prefers-reduced-motion: reduce)per la richiesta di disabilitare le animazioni. Funziona esattamente come nei CSS:window.matchMedia("(prefers-color-scheme: dark)").matchesrestituiscetruese l’utente ha il tema scuro attivo.
Devo rimuovere il gestore change quando lascio la pagina?
Nel codice moderno, no. Il browser libera la memoria automaticamente allo scaricamento della pagina. Nelle SPA (React, Vue), dove un componente viene montato e smontato senza ricaricare la pagina, devi conservare un riferimento al gestore e rimuoverlo tramite
removeEventListenerincomponentWillUnmount/onUnmounted; altrimenti avrai memory leak e attivazioni ripetute su componenti «morti».
Perché $(window).width() e matchMedia a volte mostrano larghezze diverse?
Perché misurano cose diverse.
matchMedialavora con la larghezza del viewport (l’area di visualizzazione CSS), la stessa usata dalle media query.$(window).width()/window.innerWidthinclude la larghezza della barra di scorrimento verticale, se presente. La differenza è di solito 15-17 px, esattamente la larghezza della barra di scorrimento. Da qui la regola: se leghi la logica ai breakpoint CSS, usamatchMedia; se ti serve la larghezza «reale» della finestra in pixel, usainnerWidth.
Quindi cosa usare: la conclusione finale
Per il codice nuovo la risposta è chiara: window.matchMedia(). Vive nello stesso contratto dei tuoi CSS, non richiede regolazioni manuali dei numeri per ogni breakpoint e fornisce un modello a eventi del tipo «è scattato, lo sai» invece di un polling continuo della larghezza.
Uno scenario tipico in cui la differenza si nota subito: stai costruendo una scheda prodotto che mostra una galleria di quattro immagini su desktop, ma una singola immagine sfogliabile su mobile. Nei CSS hai @media (max-width: 768px) che cambia il layout. In JS, invece di if (window.innerWidth <= 768) scrivi matchMedia("(max-width: 768px)"), e il browser garantisce che la condizione JS si attivi esattamente quando il layout cambia. Niente «quasi funzionava», niente bug a 767px a causa della barra di scorrimento.
Lascia l’approccio jQuery con $(window).width() per la manutenzione di progetti vecchi: funziona, ma ti costringe a duplicare i breakpoint nel codice e diverge silenziosamente dai CSS per la larghezza della barra di scorrimento.
E se vuoi vedere tutto ciò che è stato descritto sopra in azione, ecco un tutorial di 10 minuti in cui matchMedia viene spiegato dall’invocazione al modello a eventi:
Prova a sostituire il più vicino if (innerWidth < 768) con matchMedia("(min-width: 768px)") e sentirai subito quanto il codice diventa più pulito.



