home: hero image as <img referrerpolicy=no-referrer> (privacy consistency, Codex)

The homepage hero was a CSS background-image, the one image on the site that couldn't
carry referrerpolicy — so a remote hero leaked the referrer to the publisher CDN while
article cards + share pages suppressed it. Replace with a real <img referrerpolicy=
"no-referrer">; the retry probe now sets probe.referrerPolicy='no-referrer' too. object-fit
cover/contain replaces background-size (contain keeps the matted framed-plate look via
padding), fixed 5/4 footprint, fade-in and typographic fallback preserved; img onerror
falls back to the typo cover post-reveal. (Suppresses the referrer, not the IP — zero
third-party requests still requires policy 'none' or local caching.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-30 14:38:05 -04:00
parent 35aa8ff544
commit 4d2f5e3703
+8 -4
View File
@@ -132,6 +132,7 @@
newsImgOk = true; newsImgOk = true;
}; };
probe.onerror = () => { if (++tries <= 2) setTimeout(load, 500 * tries); }; probe.onerror = () => { if (++tries <= 2) setTimeout(load, 500 * tries); };
probe.referrerPolicy = 'no-referrer'; // match the <img> below: don't leak the referrer to the publisher CDN
probe.src = url; probe.src = url;
}; };
load(); load();
@@ -195,7 +196,8 @@
<a class="news-photo-a" href={news?.id ? `/a/${news.id}` : '/'} aria-label="Read this article"> <a class="news-photo-a" href={news?.id ? `/a/${news.id}` : '/'} aria-label="Read this article">
{#if news?.image && newsImgOk} {#if news?.image && newsImgOk}
<div class="news-photo {newsFit}"> <div class="news-photo {newsFit}">
<div class="news-plate" style={`background-image:url(${news.image})`}></div> <img class="news-plate" src={news.image} alt="" referrerpolicy="no-referrer"
onerror={() => (newsImgOk = false)} />
</div> </div>
{:else} {:else}
<!-- pictureless: typographic category cover --> <!-- pictureless: typographic category cover -->
@@ -401,8 +403,10 @@
.news-photo { aspect-ratio: 5/4; animation: news-photo-in 0.45s ease both; } .news-photo { aspect-ratio: 5/4; animation: news-photo-in 0.45s ease both; }
@keyframes news-photo-in { from { opacity: 0; } to { opacity: 1; } } @keyframes news-photo-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .news-photo { animation: none; } } @media (prefers-reduced-motion: reduce) { .news-photo { animation: none; } }
.news-plate { background-position: center; background-repeat: no-repeat; } /* real <img> (referrerpolicy=no-referrer) rather than a CSS background, so the homepage
.news-photo.cover .news-plate { width: 100%; height: 100%; background-size: cover; } hero behaves like every other image request. object-fit replaces background-size. */
.news-plate { display: block; }
.news-photo.cover .news-plate { width: 100%; height: 100%; object-fit: cover; }
.news-photo.contain { .news-photo.contain {
/* silvery at top, fading down into the card's white so the matte isn't a hard band */ /* silvery at top, fading down into the card's white so the matte isn't a hard band */
background: linear-gradient(180deg, #e6edef 0%, #f3f6f5 55%, #ffffff 100%); background: linear-gradient(180deg, #e6edef 0%, #f3f6f5 55%, #ffffff 100%);
@@ -412,7 +416,7 @@
width: 100%; height: 100%; box-sizing: border-box; padding: 12px; width: 100%; height: 100%; box-sizing: border-box; padding: 12px;
background-color: #fff; border: 1px solid #e7edee; border-radius: 8px; background-color: #fff; border: 1px solid #e7edee; border-radius: 8px;
box-shadow: 0 6px 18px -10px rgba(30, 60, 70, 0.28); box-shadow: 0 6px 18px -10px rgba(30, 60, 70, 0.28);
background-size: contain; background-origin: content-box; object-fit: contain; /* contained within the content box → the padding reads as a mat */
} }
/* pictureless fallback: topic word on a soft topic-tinted field, same footprint as the photo */ /* pictureless fallback: topic word on a soft topic-tinted field, same footprint as the photo */
.news-typo { aspect-ratio: 5/4; display: flex; align-items: center; justify-content: center; padding: 16px; box-sizing: border-box; } .news-typo { aspect-ratio: 5/4; display: flex; align-items: center; justify-content: center; padding: 16px; box-sizing: border-box; }