Blog Technische Notiz

Unser Titelbild verschwand auf iPhones: Ein Werbeblocker hat es versteckt

Wochenlang verschwand unser Titelbild auf iPhones, und kein Labortest konnte es nachstellen. Eine Messung im Feld fand die Ursache: einen Werbeblocker, der jede Klasse versteckt, die mit ad- beginnt.

Das Symptom

Auf drei Seiten dieser Website fehlte der Titelbereich (die Überschrift und das Foto oben auf der Seite), wenn die Seite auf einem iPhone zum ersten Mal gezeichnet wurde. Der Abschnitt darunter stand etwa anderthalb Sekunden oben auf dem Bildschirm, dann erschien der Titelbereich darüber. Beim Neuladen war er sofort da. In einem frischen privaten Tab geöffnet, war er wieder weg.

Es passierte nur auf iPhones. Es passierte in Safari und in jedem anderen iOS-Browser, was logisch ist, weil Apple sie alle zwingt, WebKit zu verwenden. Auf einem Desktop-Rechner oder einem Android-Telefon passierte es nie.

Es hat Wochen gedauert, das zu finden. Unterwegs haben wir mehrere Korrekturen ausgeliefert. Jede beruhte auf einer vernünftigen Theorie zum Laden von Bildern, und keine davon war die Ursache.

Die Theorien, die falsch waren

Alles am Symptom deutete auf das Bild: ein Foto, das spät ankommt, ohne reservierten Platz, und den Inhalt nach unten schiebt, sobald es da ist. Also haben wir den Platz mit Breite, Höhe und Seitenverhältnis reserviert. Wir haben das Foto aus dem Kopf des Dokuments vorgeladen. Wir haben den reservierten Platz mit einem unscharfen Platzhalter gefüllt, damit er nie weiß ist. Jede Änderung hat die Seite messbar verbessert, und keine hat den Fehler berührt.

Wir haben versucht, ihn in Chromium nachzustellen, mit einem auf eine langsame Mobilverbindung gedrosselten Netz. Der Titelbereich war ab dem ersten Frame gesetzt. Wir haben echtes WebKit auf einem Server installiert und jedes Bild und jede Schrift um zweieinhalb Sekunden zurückgehalten. Dasselbe Ergebnis. Im Labor war die Seite in Ordnung.

Messen, wo es passiert

An diesem Punkt haben wir aufgehört zu raten. Wir haben der Seite ein kleines, vorübergehendes Skript hinzugefügt, nur für Telefone, das in den ersten fünf Sekunden alle hundert Millisekunden festhielt, wo der Titelbereich tatsächlich war, und dann eine Zeile an unseren Server zurückschickte. Das Ganze hatte weniger als fünfzig Zeilen.

Code anzeigen Code ausblenden JavaScript, 17 Zeilen
// 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);

Drei Seitenaufrufe von dem Telefon, das das Problem zeigte, und die Antwort stand in den Zahlen.

Was die Messung zeigte

12 Millisekunden nach dem Start des Skripts war der Titelbereich 992 Pixel hoch und saß direkt unter der Navigationsleiste, mit zwei Stylesheets auf der Seite. Nach 114 Millisekunden war er null Pixel hoch an Position null, sein berechnetes display war none, und auf der Seite waren vier Stylesheets. Nach 1.554 Millisekunden war er zurück.

Nichts auf der Seite fügt Stylesheets hinzu. Keine Regel in unserem CSS kann dieses Element auf display none setzen. Kein Skript auf der Seite berührt es. Also hat etwas außerhalb der Seite beim ersten Laden zwei Stylesheets eingefügt, und eines davon hat unseren Titelbereich versteckt.

Der Titelbereich auf diesen drei Seiten hatte die Klassen ad-hero, ad-heroimg und ad-sub. Das Präfix stand kurz für agencies und advocacy, zwei der Märkte, für die diese Seiten gedacht sind. Ein Werbeblocker weiß das nicht.

Kosmetische Filter verstecken Elemente, deren Klassennamen mit ad- beginnen, und Inhaltsblocker unter iOS fügen genau diese Regeln als Stylesheets ein, wenn eine Seite zum ersten Mal lädt. Der zweite Durchgang, anderthalb Sekunden später, stellte das Element wieder her, weshalb es schließlich erschien. Beim Neuladen waren die Regeln des Blockers schon vorhanden, also gab es nichts, was aufblitzen konnte.

Die Korrektur

Drei Klassen umbenennen. Der Titelbereich heißt jetzt mk-hero, mk-heroimg und mk-sub auf den neun Seiten, die sie verwendeten, in allen drei Sprachen, und ein Hinweis oben im Stylesheet sorgt dafür, dass niemand eine Klasse wieder so benennt. Die Korrektur war zwölf Minuten nach dem Eintreffen der Messung live.

Code anzeigen Code ausblenden CSS, 3 Zeilen
/* Class names: never start one with "ad", "ads", "advert", "sponsor",
   "promo", "banner" or "popup". Ad blockers' cosmetic filters hide
   elements by such prefixes. */

Was Sie auf Ihrer eigenen Website prüfen sollten

Öffnen Sie den Quelltext einer beliebigen Seite und suchen Sie nach Werten von class= und id=, die mit ad, ads, advert, sponsor, promo, banner oder popup beginnen. Häufig auf Websites von Verbänden und gemeinnützigen Organisationen sind ad-banner für eine Hinweisleiste, sponsor-logos für diejenigen, die die Konferenz bezahlt haben, und promo für die Mitgliederwerbung. Ein nennenswerter Teil Ihrer Besucher sieht nichts davon, und Sie merken es nicht, weil auf Ihrem Rechner alles gut aussieht.

Wenn einige Besucher einen Fehler melden, den Sie nicht nachstellen können, liefern Sie keine weitere Theorie aus. Bauen Sie für einen Tag eine Messung in die Seite ein. Sie ist kleiner als die Korrektur, und sie zeigt Ihnen, was tatsächlich passiert.