Responsive Bildausgabe für REDAXO: srcset, sizes und <picture>, ohne für jede Bildbreite einen eigenen Media-Manager-Typ anzulegen.
Das Addon bietet dafür zwei Wege, die sich nicht ausschließen und im selben Projekt nebeneinander laufen können:
Effekt srcset (klassisch) |
Sets | |
|---|---|---|
| Konfiguration liegt in | je einem echten Media-Manager-Typ | einem Set (Code-Array oder Backend-Formular) |
| Zuschnitt/Ratio je Anwendungsfall | eigener Media-Manager-Typ pro Ausschnitt | ein Set pro Ausschnitt, kein DB-Typ nötig |
| Breitenstufen | virtuelle Untertypen hero__400 |
virtuelle Typen is_<set>__<breite> |
| PHP-API | rex_media_srcset::getImgTag() |
ResponsiveImage::forFile() |
| Alt-Text | Medienpool-Titel als Fallback | eigenes Alt-Feld, Titel bewusst nicht |
Kurz: Der klassische Weg automatisiert die Breitenstufen unterhalb bestehender Media-Manager-Typen. Sets ersetzen die Typen selbst durch eine Konfigurationsebene und brauchen in der ganzen Installation nur einen einzigen technischen Typ.
Bestehende Projekte müssen nichts ändern: Der klassische Weg ist unverändert erhalten, inklusive rex_media_srcset und der HTML-Platzhalterersetzung.
Backend: Media Manager › srcset & Sets mit Übersicht, Sets & Builder, Demo & Prüfung, Einstellungen und Hilfe.
- Installation
- Weg 1: Effekt
srcset - Weg 2: Sets
- Vorverarbeitung: Effekte anderer Typen einbinden
- Backend-Seiten
- Welchen Weg wählen?
- Zusammenspiel mit anderen Addons
- Cache und Fehlersuche
- Sicherheit
- Anforderungen
- Release herunterladen, entpacken, Ordner in
media_srcsetumbenennen und nach/redaxo/src/addonslegen. - Im Backend installieren und aktivieren (Abhängigkeit:
media_manager).
Bei der Installation wird der Media-Manager-Typ media_srcset_set angelegt. Er ist rein technisch und wird nie direkt verwendet – alle is_*-Anfragen laufen darüber.
Ein Media-Manager-Typ (z. B. hero) bekommt den Effekt Bild: SRCSET mit einem Konfigurationsstring:
400 480w, 800 480w 2x, 700 768w
Format je Eintrag: <Bildbreite in px> <Viewport-Breite>w [<Pixeldichte>x].
- 400 480w – erzeugt ein 400 px breites Bild, gedacht für einen 480 px breiten Slot.
- 800 480w 2x – 800 px Datei für denselben Slot auf Retina-Displays.
- 700 768w – 700 px Datei für einen 768 px breiten Slot.
Für jede Bildbreite entsteht zur Laufzeit ein virtuelles Unterprofil hero__400, hero__700, hero__800, das alle übrigen Effekte des Basisprofils übernimmt und nur width/height überschreibt. Im Backend muss dafür nichts zusätzlich angelegt werden.
Eine angefragte Breite ohne exakte Entsprechung wird auf die nächstgrößere konfigurierte Breite aufgerundet.
rex_media_srcset::getImgTag(string $fileName, string $mediaType, ?array $attributes = null, ?array $layout = null): string
rex_media_srcset::getPictureTag(string $fileName, string $mediaType, ?array $attributes = null, ?array $mediaQueries = null, ?array $layout = null): string
rex_media_srcset::getSrcSet(string $fileName, string $mediaType): string
rex_media_srcset::getTag(string $fileName, string $mediaType, ?array $attributes = null, int $tagType = rex_media_srcset::IMG, ?array $additionalSources = null, ?array $layout = null): stringEinfaches Bild:
echo rex_media_srcset::getImgTag('teamfoto.jpg', 'hero');Mit eigenen Attributen (alt und sizes haben immer Vorrang vor der automatischen Ermittlung):
echo rex_media_srcset::getImgTag('teamfoto.jpg', 'hero', [
'class' => 'hero-image',
'loading' => 'lazy',
'alt' => 'Das Team bei der Arbeit',
]);Art Direction mit <picture> – je Media Query ein eigener Media-Manager-Typ, der einen anderen Zuschnitt haben darf:
echo rex_media_srcset::getPictureTag('teamfoto.jpg', 'hero_desktop', ['class' => 'hero-image'], [
'(max-width: 719px)' => 'hero_mobile_portrait',
]);Layout-basiertes sizes statt bloßer Wiederholung der Breakpoints:
echo rex_media_srcset::getImgTag('teamfoto.jpg', 'hero', null, [
'containerWidth' => 'uk-container', // Schätzung der Container-Maximalbreite
'columns' => 3, // Spalten ab 1200 px
'columnsTablet' => 2, // Spalten zwischen 640 und 1200 px
'columnsMobile' => 1, // Spalten unter 640 px
'mediaFraction' => 1.0, // Anteil der Spalte (0.05–1.0)
]);
// sizes="(min-width: 1200px) 400px, (min-width: 640px) 50vw, 100vw".svg-Dateien werden erkannt und direkt aus dem Medienpool ausgeliefert – ohne Media-Manager, ohne srcset/sizes. SVGs skalieren im Browser ohnehin verlustfrei.
getSrcSet() liefert bewusst einen unescapten Rohwert; beim direkten Einbau in eigenes Markup selbst rex_escape() anwenden.
Alternativ kann srcset="rex_media_type=ProfilName" direkt im Template stehen; das Addon ersetzt den Platzhalter beim Rendern:
<img src="index.php?rex_media_type=hero&rex_media_file=bild.jpg" srcset="rex_media_type=hero" />Das funktioniert auch für <picture> mit mehreren <source srcset="rex_media_type=…">.
Altlast. Dieser Weg durchsucht jede Seitenausgabe per regulärem Ausdruck und bietet weniger Kontrolle als die PHP-API (kein
alt-Fallback, keinsizes, keine SVG-Sonderbehandlung). Für neuen CodegetImgTag()/getPictureTag()oder Sets verwenden.
Abschaltbar unter Media Manager › srcset & Sets › Einstellungen. Standard:
- Neuinstallation: aus – neue Projekte nutzen die PHP-API, der Regex-Lauf wäre unnötige Last.
- Update einer bestehenden Installation: an – dort können Templates den Platzhalter verwenden, der sonst still aufhören würde zu funktionieren.
Eine einmal getroffene Entscheidung wird von späteren Updates nie überschrieben.
Wird das Attribut als data-srcset ausgegeben und
<script src="assets/addons/media_srcset/srcset.js"></script>eingebunden, prüft ein Skript beim Laden und nach jedem Resize die tatsächliche Anzeigebreite jedes Elements und lädt bei Bedarf eine passendere Datei nach. Die Auswahl orientiert sich damit an der gerenderten Elementbreite statt nur am Viewport. Dafür nötig:
img[data-srcset] { width: 100%; height: auto; }Ein Set bündelt Seitenverhältnis, Zuschnittsmodus und die erlaubten Breitenstufen in einer Konfigurationseinheit – als PHP-Array im Code oder als Eintrag im Backend-Builder. Ein Bild wird als is_<set>__<breite> angefragt, z. B. /media/is_ratio_4_3__800/bild.jpg.
Ein neues Bildformat für ein einzelnes Modul heißt damit: ein Set registrieren (eine Codezeile oder ein Formular) – nicht: einen Media-Manager-Typ anlegen, konfigurieren und pflegen.
- Sets definieren Ratio, Modus und Breitenstufen, z. B.
ratio_4_3mit400, 800, 1200, 1600, 2000. - Ein Bild wird als
is_<set>__<breite>angefragt.MEDIA_MANAGER_FILTERSETsetzt dafür dynamisch den Effektmedia_srcset_setein; in der Datenbank existiert nur der Basistypmedia_srcset_set. - Der Effekt wendet optional die Vorverarbeitung an, schneidet dann auf das Seitenverhältnis (Fokuspunkt, sonst zentriert) und skaliert danach breitenbegrenzt. Vergrößert wird nie.
ResponsiveImagebaut daraussrc,srcsetundsizes.
Angefragte Breiten werden auf die nächste Stufe aufgerundet: is_ratio_4_3__900 liefert die 1200er-Stufe. So bleibt die Zahl der Cache-Varianten begrenzt.
Zwei Quellen, beide landen in derselben Registry:
| Quelle | Wo | Wer |
|---|---|---|
| Code | boot.php des Addons oder eines Projekt-Addons via MediaTypeRegistry::registerPreset() bzw. Extension Point MEDIA_SRCSET_PRESETS |
Entwickler |
| Builder | Backend › Sets & Builder, gespeichert in der Addon-Konfiguration | Redaktion und Entwickler |
Grundausstattung:
| Set | Ratio | Modus | Breiten | Standard |
|---|---|---|---|---|
ratio_16_9 |
16:9 | focuspoint | 400, 800, 1200, 1600, 2000 | 1200 |
ratio_21_9 |
21:9 | focuspoint | 400, 800, 1200, 1600, 2000 | 1200 |
ratio_4_3 |
4:3 | focuspoint | 400, 800, 1200, 1600, 2000 | 1200 |
ratio_1_1 |
1:1 | focuspoint | 400, 800, 1200, 1600 | 1200 |
ratio_original |
Quelle | resize | 400 … 2400 | 1600 |
Code-Sets sind im Backend schreibgeschützt; Builder-Sets dürfen deren Namen nicht verwenden.
use FriendsOfRedaxo\MediaSrcset\Config\MediaTypeRegistry;
MediaTypeRegistry::registerPreset('teaser_3_2', [
'ratio' => '3_2', // Breite_Höhe oder 'original'
'mode' => 'focuspoint', // focuspoint | resize
'widths' => [400, 800, 1200, 1600],
'default_width' => 1200,
'chain' => '', // optional, siehe Vorverarbeitung
]);Eine feste Breite:
echo '<img src="' . rex_media_manager::getUrl('is_ratio_16_9__1200', $file) . '" alt="…">';Responsive Ausgabe:
use FriendsOfRedaxo\MediaSrcset\Media\ResponsiveImage;
echo ResponsiveImage::forFile($file)
->withDesktopPreset('ratio_4_3') // Set für srcset
->withMobilePreset('ratio_1_1') // optional: eigenes Ratio unter dem Mobile-Breakpoint
->withWidths([400, 800, 1200, 1600]) // gewünschte Stufen (werden auf Set-Stufen gerundet)
->withContainerWidth('uk-container') // uk-container(-xsmall|-small|-large|-xlarge) oder 'expand'
->withColumns(3, 2, 1) // Spalten Desktop / Tablet / Mobil
->withMediaFraction(0.5) // Anteil des Bildes an der Spalte
->withBreakpoints(960, 1200) // Breakpoints des eigenen Layouts (Standard 640/1200)
->toImageTag(['alt' => $alt, 'class' => 'uk-width-1-1']);Weitere Ausgaben: toImage(), toPicture(), toPictureTag(), getSrcsetEntries(), getEffectiveWidths(), getSourceMaxWidth(), getDimensions(), withCapToSource(false), withSizes().
toImageTag() setzt automatisch:
widthundheightdersrc-Variante, damit der Browser den Platz vor dem Laden reserviert. Eigene Werte haben Vorrang.altnach der Regel: übergeben (['alt' => …]oderwithAlt()) > MediaPlace-Alt-Feld (inkl. Sprachvariante) > klassischesmed_alt> leer. Der Medienpool-Titel ist kein Alt-Text und wird nie verwendet. Ohne Alt-Text oder bei Markierung als dekorativ wirdalt="" role="presentation"ausgegeben.loading="lazy" decoding="async";withPriority()liefert stattdessenloading="eager" fetchpriority="high"für das LCP-Bild.
Die Alt-Regel steht auch eigenem Code zur Verfügung: AltText::resolve($media, $clangId).
Für Logos, Avatare oder Icons mit fester Darstellungsbreite ersetzt withDensities() das sizes-Attribut durch 1x/2x/3x:
echo ResponsiveImage::forFile($logo)
->withDesktopPreset('logo_1_1')
->withWidths([200])
->withDensities([1, 2, 3])
->toImageTag(['alt' => 'Firmenlogo']);Wird die Quelle vorher erreicht, sinkt der Descriptor entsprechend (z. B. 1.5x), damit er der gelieferten Datei entspricht.
- Bildausschnitt je Bild (Fokuspunkt): Jeder Ratio-Zuschnitt wird um den im Medienpool gesetzten Fokuspunkt gelegt – ohne Code, pro Bild, durch die Redaktion.
- Anderes Seitenverhältnis je Bildschirmbreite:
withSource()fügt beliebig viele<source>mit eigener Media Query hinzu (Aufrufreihenfolge = Reihenfolge im Markup).
echo ResponsiveImage::forFile($file)
->withDesktopPreset('ratio_21_9')
->withSource('(max-width: 639px)', 'ratio_1_1', ['widths' => [400, 800], 'sizes' => '100vw'])
->withSource('(max-width: 1199px)', 'ratio_4_3')
->toPictureTag(['loading' => 'lazy']);Beide Zuschnitte folgen demselben Fokuspunkt. Nicht vorgesehen ist ein komplett anderes Bild je Breakpoint; dafür zwei Medienfelder anlegen.
Ein srcset-Descriptor (800w) muss der Pixelbreite der Datei entsprechen, sonst wählt der Browser falsch. ResponsiveImage sorgt dafür durch:
- Runden der gewünschten Breiten auf Set-Stufen (nur diese Dateien existieren).
- Kappen an der Quelle: Stufen oberhalb der erreichbaren Breite entfallen; als größte Variante wird die Quellbreite mit korrektem Descriptor angehängt.
- Die Reihenfolge Vorverarbeitung → Zuschnitt → Skalierung, damit auch Hochformat-Quellen die volle Zielbreite erreichen.
Ein Set kann die Effekte bestehender Media-Manager-Typen als Bausteine wiederverwenden – etwa ein Wasserzeichen oder einen Farbfilter, der bereits als Typ gepflegt wird:
MediaTypeRegistry::registerPreset('teaser_sw', [
'ratio' => '4_3',
'mode' => 'focuspoint',
'widths' => [400, 800, 1200],
'chain' => 'watermark,make_greyscale', // kommagetrennte Media-Manager-Typen
]);Im Builder steht dafür das Feld Vorverarbeitung zur Verfügung.
Die Kette läuft vor dem Zuschnitt, also in voller Quellauflösung, und vollständig im Arbeitsspeicher – ohne Zwischendateien und ohne erneutes Encodieren je Schritt.
Regeln:
- Größen-Effekte werden übersprungen (
resize,srcset,media_srcset_set). Die Zielbreite bestimmt allein das Set, sonst wäre dersrcset-Descriptor nicht mehr die tatsächliche Dateibreite. - Nicht vorhandene Typen werden übersprungen.
- Selbstreferenzen und Zyklen werden erkannt, die Verschachtelung ist auf fünf Ebenen begrenzt.
- Ein Fehler in einem Kettenglied wird protokolliert und übersprungen, statt die Bildauslieferung zu verhindern.
Das Konzept stammt aus dem Addon media_chain und wird hier auf dem bereits geladenen Bildobjekt ausgeführt.
Media Manager › srcset & Sets
- Übersicht – alle registrierten Sets mit Ratio, Modus, Stufen, Standardbreite, Quelle und Beispiel-Typ.
- Sets & Builder – Sets anlegen, bearbeiten, aktivieren/deaktivieren, löschen und deren Cache leeren. Dazu:
- Assistent, der Breitenstufen aus Container-Breite, Spaltenzahl, Bildanteil, Retina und Breakpoints ableitet, auf 100 px rundet und zu dichte Stufen ausdünnt.
- Nutzung & Bestand – welche Sets und Breiten Module und Templates tatsächlich anfordern und wie breit die Originalbilder im Medienpool sind, mit Hinweisen auf überflüssige oder fehlende Stufen.
- Vorschau & Test – erzeugtes Markup, alle Varianten mit tatsächlicher Pixelbreite und Dateigröße, Descriptor-Check und eine Simulation der Browser-Auswahl.
- Demo & Prüfung – dieselbe Prüfung für frei wählbare Layout-Parameter, inklusive Live-Anzeige, welche Variante der Browser gerade geladen hat.
- Einstellungen – Schalter für die HTML-Platzhalterersetzung.
- Hilfe – diese Datei.
- Bestandsprojekt mit eingerichteten Media-Manager-Typen: beim Effekt
srcsetbleiben. Es besteht kein Migrationsdruck. - Neues Projekt oder viele ähnliche Bildformate: Sets verwenden. Weniger DB-Typen, Breitenstufen entstehen bei Bedarf,
sizeswird aus dem Layout berechnet und der Alt-Text kommt aus dem dafür vorgesehenen Feld. - Beides gleichzeitig ist ausdrücklich vorgesehen:
hero__400undis_ratio_4_3__800stören sich nicht.
- focuspoint – Ratio-Zuschnitte folgen dem im Medienpool gesetzten Fokuspunkt (
med_focuspoint); ohne das Addon wird zentriert geschnitten. - media_negotiator – liefert WebP/AVIF nach
Accept-Header; der Cache-Pfad wird pro Format getrennt. Ohne das Addon werden JPG/PNG ausgeliefert. - MediaPlace / metainfo_lang_fields – Quellen für den Alt-Text der Sets.
- SVG und GIF werden unverändert ausgeliefert.
- Nach Änderungen an Sets oder Effekten: Media Manager › Cache löschen, oder auf Sets & Builder den Cache des betroffenen Sets leeren.
- Ein Typ wie
is_ratio_4_3__700liefert die nächsthöhere Stufe (800); unbekannte Sets fallen auf das Original zurück. - Sehr große Originale brauchen beim ersten Aufruf spürbar Rechenzeit; danach kommt alles aus dem Cache.
- Bricht die Erzeugung ab (leeres Bild), fehlt meist Speicher (
memory_limit) oder das Original ist beschädigt.
Alle erzeugten Attributwerte werden HTML-escaped (rex_escape()), inklusive des alt-Fallbacks. Attributnamen werden gegen /^[a-zA-Z_:][-a-zA-Z0-9_:.]*$/ validiert, was Attribut-Injection über $attributes-Keys verhindert. getSrcSet() liefert bewusst einen unescapten Rohwert für eigene Verwendungszwecke.
- REDAXO
^5.18.0 - Addon
media_manager^2.5.6 - PHP
>= 8.1(getestet bis PHP 8.4)
Vollständige Referenz beider APIs: API.md · English
Siehe CHANGELOG.md.
MIT · GitHub-Repository