Cover-Spielerfoto: Varianten statt 12-MB-Original (iOS Safari)
Das Cover blieb am iPhone leer, während Chrome am Desktop es zeigte. Ursache war kein fehlendes Bild: das freigestellte Spielerfoto hatte 2584x5093 Pixel und 12,3 MB. iOS Safari verwirft Bilder, deren dekodierte Größe sein Budget übersteigt — hier gut 53 MB, und auf einer Ausgabe liegen 86 Bilder. Dargestellt wird das Foto mit 98cqi Höhe, bei 480px Seitenbreite also etwa 238x470 CSS-Pixel. Es gibt jetzt 320/640/1000 als PNG mit erhaltener Transparenz (0,2 / 0,8 / 1,9 MB); sizes nennt die echte Breite, sonst zöge ein Handy mit DPR 3 die größte Variante. Das Original ist gelöscht. Dafür kann resize_image_variants() nun Alpha erhalten ($alpha = true schreibt PNG statt JPG) und die img-Komponente eine Endung ($image['ext']). Der Default bleibt JPG, weil bestehende Aufrufer PNG-Quellen absichtlich zu JPG verkleinern. bin/stadionzeitung-add.php erzeugt die Varianten künftig selbst. Dort stand "unverändert kopieren, Felix liefert bereits ein web-taugliches Foto" — genau diese Annahme ist gerissen. Außerdem: smtp.password stand in der Produktiv-Config noch auf dem Platzhalter POSTFACH_PASSWORT (von preflight auf dem Server gefunden, einziger harter Fehler). Übernommen wurde das Passwort aus der Dev-Config, mit dem der Versand am 27.07.2026 verifiziert wurde; Host, Postfach und Empfänger sind identisch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NzeVVgMCrzCDJAKeLEdKr7
This commit is contained in:
@@ -4,7 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Responsives Bild aus Varianten-Set ODER Einzeldatei. Props:
|
||||
* $image array{base: string, widths: int[], alt: string} — Varianten <base>-<w>.jpg
|
||||
* $image array{base: string, widths: int[], alt: string, ext?: string} — Varianten
|
||||
* <base>-<w>.<ext>, Default-Endung jpg. ext: 'png' für freigestellte Motive,
|
||||
* deren Transparenz JPG zerstören würde (Spielerfoto auf dem Cover).
|
||||
* ODER array{src: string, width: int, height: int, alt: string} — Originaldatei 1:1
|
||||
* $sizes string (optional, default '100vw')
|
||||
* $eager bool (optional) — above the fold: eager + fetchpriority high
|
||||
@@ -24,15 +26,16 @@ if (!empty($image['src'])): ?>
|
||||
|
||||
$widths = $image['widths'];
|
||||
$largest = max($widths);
|
||||
$ext = strtolower((string) ($image['ext'] ?? 'jpg'));
|
||||
$srcset = implode(', ', array_map(
|
||||
static fn (int $w): string => asset("{$image['base']}-{$w}.jpg") . " {$w}w",
|
||||
static fn (int $w): string => asset("{$image['base']}-{$w}.{$ext}") . " {$w}w",
|
||||
$widths
|
||||
));
|
||||
|
||||
// Maße der größten Variante für width/height (CLS-Vermeidung).
|
||||
[$w, $h] = (function () use ($image, $largest): array {
|
||||
[$w, $h] = (function () use ($image, $largest, $ext): array {
|
||||
static $dims = [];
|
||||
$file = PUBLIC_PATH . "/assets/{$image['base']}-{$largest}.jpg";
|
||||
$file = PUBLIC_PATH . "/assets/{$image['base']}-{$largest}.{$ext}";
|
||||
$key = $file;
|
||||
if (!isset($dims[$key])) {
|
||||
$size = is_file($file) ? (getimagesize($file) ?: [0, 0]) : [0, 0];
|
||||
@@ -42,7 +45,7 @@ $srcset = implode(', ', array_map(
|
||||
})();
|
||||
?>
|
||||
<img<?= $class !== '' ? ' class="' . e($class) . '"' : '' ?>
|
||||
src="<?= e(asset("{$image['base']}-{$largest}.jpg")) ?>"
|
||||
src="<?= e(asset("{$image['base']}-{$largest}.{$ext}")) ?>"
|
||||
srcset="<?= e($srcset) ?>"
|
||||
sizes="<?= e($sizes) ?>"
|
||||
alt="<?= e($image['alt']) ?>"
|
||||
|
||||
@@ -81,7 +81,24 @@ $teaser = trim((string) ($issue['interview']['teaser'] ?? ''));
|
||||
<?php component('img', ['image' => $heroImage, 'sizes' => '480px', 'class' => 'stadionzeitung-cover__bg']); ?>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($playerImage)): ?>
|
||||
<img class="stadionzeitung-cover__player" src="<?= e(asset($playerImage)) ?>" alt="" loading="lazy">
|
||||
<?php
|
||||
/* Varianten-Set (base/widths/ext=png) statt der Originaldatei. Das Original ist
|
||||
ein Freisteller mit 2584x5093 Pixeln und 12 MB: iOS Safari verwirft Bilder,
|
||||
deren dekodierte Größe sein Budget übersteigt (hier gut 53 MB), und auf einer
|
||||
Ausgabe liegen rund 86 Bilder — das Cover blieb am iPhone leer, während Chrome
|
||||
am Desktop es zeigte (31.07.2026). Dargestellt wird es mit 98cqi Höhe, bei
|
||||
480px Seitenbreite also etwa 238x470 CSS-Pixel; die 1000er Variante deckt
|
||||
damit auch Druck und dreifache Pixeldichte ab.
|
||||
sizes nennt die echte Breite, sonst zöge ein Handy mit DPR 3 die größte. */
|
||||
$playerBild = is_array($playerImage)
|
||||
? $playerImage
|
||||
: ['src' => $playerImage, 'width' => 0, 'height' => 0, 'alt' => ''];
|
||||
?>
|
||||
<?php component('img', [
|
||||
'image' => $playerBild,
|
||||
'class' => 'stadionzeitung-cover__player',
|
||||
'sizes' => '(max-width: 600px) 50vw, 240px',
|
||||
]); ?>
|
||||
<?php endif; ?>
|
||||
<div class="stadionzeitung-cover__inner">
|
||||
<header class="stadionzeitung-cover__masthead">
|
||||
|
||||
Reference in New Issue
Block a user