Blog Nota tecnica

La nostra immagine principale spariva su iPhone: un blocco della pubblicità la nascondeva

Per settimane la nostra immagine principale è sparita su iPhone senza che il laboratorio lo riproducesse. La causa: un blocco della pubblicità che nascondeva ogni classe che inizia con ad-.

Il sintomo

Su tre pagine di questo sito, il blocco principale (il titolo e la fotografia in cima alla pagina) mancava quando la pagina veniva disegnata per la prima volta su un iPhone. La sezione sottostante restava in cima allo schermo per circa un secondo e mezzo, poi il blocco compariva sopra. Ricaricando la pagina c’era subito. Aprendola da capo in una scheda privata spariva di nuovo.

Succedeva solo su iPhone. Succedeva in Safari e in tutti gli altri browser per iOS, il che è logico perché Apple li obbliga tutti a usare WebKit. Non è mai successo su un computer né su un telefono Android.

Ci sono volute settimane per trovarlo. Nel frattempo abbiamo pubblicato diverse correzioni. Ognuna partiva da un’ipotesi ragionevole sul caricamento delle immagini, e nessuna era la causa.

Le teorie sbagliate

Tutto nel sintomo indicava l’immagine: una fotografia che arrivava tardi, senza spazio riservato, e che spingeva in basso il contenuto caricandosi. Così abbiamo riservato lo spazio con larghezza, altezza e proporzioni. Abbiamo precaricato la fotografia dall’intestazione del documento. Abbiamo riempito lo spazio riservato con un sostituto sfocato perché non fosse mai bianco. Ogni modifica ha migliorato la pagina in modo misurabile, e nessuna ha toccato il bug.

Abbiamo provato a riprodurlo in Chromium con la rete limitata a una connessione mobile lenta. Il blocco principale era impaginato fin dal primo fotogramma. Abbiamo installato un vero WebKit su un server e trattenuto ogni immagine e ogni font per due secondi e mezzo. Stesso risultato. In laboratorio, la pagina andava bene.

Misurare dove succede

A quel punto abbiamo smesso di tirare a indovinare. Abbiamo aggiunto alla pagina un piccolo script temporaneo, solo per i telefoni, che registrava dove si trovava davvero il blocco principale ogni cento millisecondi per i primi cinque secondi, poi inviava una riga al nostro server. In tutto, meno di cinquanta righe.

Mostra il codice Nascondi il codice JavaScript, 17 righe
// Sample the hero's position for five seconds, then send one beacon.
const hero = document.querySelector("header.pagehead");
const samples = [];
const t0 = performance.now();
const tick = setInterval(() => {
  const r = hero.getBoundingClientRect();
  samples.push([
    Math.round(performance.now() - t0),
    Math.round(r.top), Math.round(r.height),
    getComputedStyle(hero).display,
    document.styleSheets.length,
  ]);
  if (samples.length >= 50) {
    clearInterval(tick);
    navigator.sendBeacon("/api/hero-trace.json", JSON.stringify(samples));
  }
}, 100);

Tre caricamenti di pagina dal telefono che mostrava il problema, e la risposta era nei numeri.

Che cosa diceva la misurazione

A 12 millisecondi dall’avvio dello script, il blocco principale era alto 992 pixel, subito sotto la barra di navigazione, con due fogli di stile nella pagina. A 114 millisecondi era alto zero pixel in posizione zero, il suo display calcolato era none, e nella pagina c’erano quattro fogli di stile. A 1.554 millisecondi era tornato.

Nulla nella pagina aggiunge fogli di stile. Nessuna regola del nostro CSS può mettere quell’elemento in display none. Nessuno script della pagina lo tocca. Qualcosa di esterno alla pagina iniettava quindi due fogli di stile al primo caricamento, e uno di essi nascondeva il nostro blocco principale.

Il blocco principale di quelle tre pagine aveva le classi ad-hero, ad-heroimg e ad-sub. Il prefisso abbreviava agencies e advocacy, due dei mercati a cui si rivolgono quelle pagine. Un blocco della pubblicità non lo sa.

I filtri cosmetici nascondono gli elementi il cui nome di classe comincia con ad-, e i blocchi dei contenuti su iOS iniettano esattamente queste regole sotto forma di fogli di stile al primo caricamento di una pagina. Il secondo passaggio, un secondo e mezzo dopo, ripristinava l’elemento, il che spiega perché alla fine compariva. Al ricaricamento, le regole del blocco erano già al loro posto, quindi non c’era nulla da far lampeggiare.

La correzione

Rinominare tre classi. Il blocco principale ora si chiama mk-hero, mk-heroimg e mk-sub sulle nove pagine che le usavano, nelle tre lingue, e una nota in cima al foglio di stile impedisce a chiunque di nominare così una classe in futuro. La correzione era online dodici minuti dopo il ritorno della misurazione.

Mostra il codice Nascondi il codice CSS, 3 righe
/* Class names: never start one with "ad", "ads", "advert", "sponsor",
   "promo", "banner" or "popup". Ad blockers' cosmetic filters hide
   elements by such prefixes. */

Che cosa controllare sul suo sito

Apra il codice sorgente di una pagina qualsiasi e cerchi valori di class= e id= che cominciano con ad, ads, advert, sponsor, promo, banner o popup. Quelli che vediamo più spesso sui siti di associazioni e organizzazioni non profit sono ad-banner per una barra degli avvisi, sponsor-logos per chi ha pagato il congresso, e promo per la campagna di iscrizione. Una parte significativa dei suoi visitatori non vede nessuno di questi elementi, e lei non se ne accorgerà, perché sul suo computer tutto si vede bene.

Se alcuni visitatori segnalano un bug che lei non riesce a riprodurre, non pubblichi un’altra teoria. Metta una misurazione sulla pagina per un giorno. È più piccola della correzione, e le mostra che cosa succede davvero.