CASE STUDY • DEBUG • FRONTEND

Tre Bug Sovrapposti:
Diagnosi di un Sito Rotto Solo su Mobile

Un cliente mi scrive uno screenshot dal telefono: la pagina di un articolo tecnico del suo blog è completamente rotta. Testo che esce dai bordi, righe tagliate a metà, bisogna fare zoom out per leggere qualcosa. Su desktop, la stessa identica pagina è perfetta. Succede raramente che un bug si presenti così: pulito su un dispositivo, disastroso sull'altro, e per una volta il colpevole non era uno solo.

Quello che segue è la cronologia della diagnosi, con gli errori di percorso inclusi — perché due delle tre piste che ho seguito erano sbagliate, e capire perché lo erano è più utile della soluzione finale.

1. Il Sospetto Ovvio: un File CSS Mancante

Il sito usa un foglio di stile dedicato per gli articoli del blog, caricato con un semplice <link rel="stylesheet"> nell'head della pagina. Prima ipotesi, la più banale: il file non esisteva ancora sul server. Un <link> che punta a un percorso inesistente non genera nessun errore visibile all'utente — il browser richiede il file, riceve un 404, e va avanti come se niente fosse. Il risultato è un articolo senza nessuno stile specifico, che eredita solo le regole generiche del sito, alcune delle quali bastano per il layout ma non per gestire correttamente i blocchi di codice lunghi.

Verifica confermata: il file non era mai stato caricato in produzione. Ho aggiunto il file, il cliente ha ricaricato, e la pagina è tornata... completamente bianca. Peggio di prima.

2. Il Falso Errore Fatale

Una pagina bianca dopo un upload fa pensare subito a un errore PHP fatale — file corrotto durante il trasferimento FTP, un tag non chiuso, qualcosa del genere. Ho controllato la sintassi di tutti i file toccati con php -l: nessun errore. La pagina si caricava, il DOM era completo (header, contenuto, footer, tutto presente), ma visivamente non c'era nulla.

La differenza tra "il codice non gira" e "il codice gira ma è invisibile" è enorme, e la seconda si scopre solo aprendo DevTools e ispezionando l'elemento invece di fidarsi dell'impressione visiva. L'elemento principale dell'articolo aveva la classe fade-in-on-scroll visible — il JavaScript aveva fatto il suo lavoro, aveva aggiunto la classe che dovrebbe far comparire il contenuto — eppure l'opacità calcolata restava a zero.

Nel foglio di stile appena caricato c'era questa regola:

.fade-in-on-scroll {
    opacity: 0;
    transform: translateY(40px);
    transition: opacity 0.8s ease-out, transform 0.8s var(--ease-out-expo);
}

Sembra innocua, ma manca un pezzo fondamentale: non c'è nessuna regola .fade-in-on-scroll.visible che riporti l'opacità a 1. Il CSS globale del sito gestiva già questa stessa animazione, ma in modo protetto — scoped sotto body.js-fade-in, con tanto di contropartita per la classe .visible. La nuova regola, non scoped, vinceva per specificità e nascondeva tutto in modo permanente, indipendentemente da cosa facesse il JavaScript.

💡 Regola pratica: se in un progetto esiste già un meccanismo di animazione scroll-reveal gestito a livello globale, non ridefinirlo in un file più specifico "tanto per sicurezza". Se proprio serve duplicarlo, va duplicato con tutte le sue condizioni, non solo con la parte che nasconde il contenuto.

3. Il Bug che Vedeva Solo il Telefono

Tolta la regola difettosa, il contenuto è tornato visibile. Ma il problema originale — il testo che esce dai bordi su mobile — era ancora lì, confermato più volte anche in incognito su un browser mai usato prima, quindi cache esclusa lato client in quel momento.

Qui è dove ho perso più tempo per una ragione precisa: i miei primi test non erano rappresentativi. Ridimensionare la finestra di un browser desktop a 390 pixel di larghezza non è la stessa cosa di una vera emulazione mobile. Manca il device pixel ratio corretto, manca il modo in cui il motore di rendering ricalcola il viewport, e alcuni bug di layout semplicemente non si manifestano in quel contesto. Il test giusto è il device toolbar di Chrome DevTools (o strumenti equivalenti), che emula davvero le metriche di un dispositivo — non solo le dimensioni della finestra.

Con l'emulazione corretta, il layout sembrava a posto. Sul telefono reale del cliente, no. La discrepanza puntava dritta verso un sospetto specifico: qualcosa che si comporta diversamente tra motori di rendering, non riproducibile su Chrome desktop ma presente su Safari/WebKit iOS (che è anche il motore sotto il cofano di Chrome su iOS, per via delle policy Apple).

La causa: il contenitore principale dell'articolo è figlio diretto del <body>, che nel CSS del sito è impostato come display: flex. Nei layout flex, un figlio ha di default min-width: auto, che lo blocca al contenuto minimo. La specifica CSS prevede che i motori trattino questo valore come zero quando l'elemento ha overflow non-visibile — ma il supporto a questa regola specifica non è uniforme, e su WebKit/iOS il comportamento può ancora divergere. Il contenitore, inoltre, non aveva mai una width esplicita: si affidava allo stretch automatico del flex container, che su iOS in certi casi non calcola correttamente la larghezza in combinazione con un max-width fisso.

La soluzione è stata dichiarare esplicitamente quello che prima veniva lasciato all'inferenza del browser:

.article-container {
    width: 100%;
    max-width: 800px;
    margin: 0 auto;
    overflow-x: hidden;
    box-sizing: border-box;
    min-width: 0;
}

Nessuna delle quattro proprietà da sola risolveva il problema. overflow-x: hidden senza min-width: 0 lascia il rischio del bug flexbox. min-width: 0 senza width: 100% lascia il contenitore a inferire una larghezza che su iOS a volte sbaglia. Serviva la combinazione.

4. Perché Questi Dettagli Contano Anche per Chi Non Scrive Codice

Nessuno di questi tre bug era visibile guardando il sito da un computer in ufficio. Tutti e tre si manifestavano solo in una combinazione precisa: dispositivo mobile, motore WebKit, e in un caso solo dopo aver risolto gli altri due. È il motivo per cui "il sito funziona, l'ho controllato" detto guardando solo il proprio laptop non basta come garanzia — soprattutto per contenuti tecnici con blocchi di codice, tabelle o elementi che su desktop hanno più spazio per sbagliare senza che si veda.

C'è anche un capitolo di cui non ho parlato sopra ma che vale la pena menzionare: durante la sequenza di aggiornamenti, un problema che sembrava risolto è ricomparso identico dopo un caricamento successivo. La causa, in quel caso, non era nel codice ma nella cache del CDN che continuava a servire una versione precedente del file. Un "purge cache" mirato ha risolto in un minuto quello che sembrava un regresso inspiegabile. Vale la pena ricordarlo perché è un passaggio che si salta facilmente quando si è concentrati sul debug del codice: a volte il codice è già corretto, e il problema è solo che nessuno lo sta ancora servendo.


Le Lezioni Apprese

Quattro cose che mi porto via da questa diagnosi, utili al di là del caso specifico:

Il tuo sito si comporta bene anche fuori dal tuo laptop?

Verifiche cross-browser e cross-device, ottimizzazione frontend e debug di problemi che "sul mio computer funziona" non basta a scovare.

Richiedi una consulenza