Responsive Images im Eigenbau

Bei den Performance-Messungen im Zuge meines Wechsels von Yoko zu Catch Evolution bekam ich immer wieder den Optimierungshinweis, auch im Header doch angepasste Grafiken („responsive images“) auszuliefern, statt standardmäßig immer das gleiche Bild mit 1600×400 Pixeln in voller Größe auch auf die kleinsten Endgeräte zu schicken.

Die Idee ist nicht schlecht, auch wenn sich der Effekt durch Smartphones mit immer höheren Auflösungen wahrscheinlich immer weniger auswirken wird. Aber egal, es ist eine nette kleine Fingerübung und bringt wieder ein paar zusätzliche Punkte in der Bewertung – die kann man ja en passant mitnehmen. Auch auf einer so wenig besuchten Website wie dieser hier.

Falls es mal jemand nachbauen möchte steht hier mein Lösungsansatz. Bilder innerhalb der Beiträge habe ich mit Responsify WP umgestellt, nur beim Header musste ich selbst Hand anlegen.

Schritt 1:
Media Breakpoints festlegen bzw. finden

Das Catch Evolution Theme ist ja schon responsive ausgelegt und reagiert auf unterschiedliche Bildschirmauflösungen. Also werfen wir mal einen Blick ins css, genauer gesagt in die wp-content/themes/catch-evolution/css/responsive.css und suchen nach @media, um die „Umschaltpunkte“ zu finden:

@media screen and (max-width: 960px) {
@media screen and (max-width: 767px) {
@media screen and (max-width: 479px) {
@media screen and (max-width: 320px) {
@media screen and (max-width: 1224px) {
@media screen and (max-width: 1060px) {

Und schon wissen wir, ab welcher Auflösung sich das Layout ändert und wir ein kleineres Titelbild ausliefern lassen könnten. Der Einfachheit halber geben wir jedesmal ein anderes Bild aus.
WordPress kennt standardmäßig nur drei Bildgrößen (festgelegt unter Einstellungen – Medien): Thumbnail, Mittel, Groß. Das ist schonmal ein Anfang, diese Größen legen wir wie folgt fest: Thumbnail 150, Mittel 468, Groß 680px breit, jeweils mit proportionaler Höhe.
media_settings
Da wir hier noch ein paar Zwischengrößen brauchen, definieren wir uns einfach welche mit add_image_size(). Das Titelbild wird immer in voller Breite ohne irgendwelche Ränder ausgegeben, deswegen übernehmen wir einfach die Umschaltpunkte von oben. Konkret fügen wir in die functions.php unseres Child Themes folgende Zeilen ein:

// headers are 1600x400 or a fraction thereof, so all must be hard cropped
add_image_size('resp-head-full', 1600, 400, true); //this is the maximum size we want for header images
add_image_size('resp-head-xlarge', 1224, 306, true);
add_image_size('resp-head-large', 1059, 264, true);
add_image_size('resp-head-medium', 960, 240, true);
add_image_size('resp-head-small', 767, 191, true);
add_image_size('resp-head-xsmall', 467, 116, true);
add_image_size('resp-head-mini', 320, 80, true);

// others are just restricted in width
add_image_size('resp-large', 592, 9999);
add_image_size('resp-small', 320, 9999);
add_image_size('resp-mini', 278, 9999);

So ist sichergestellt, dass die Titelbilder alle auf jeden Fall im richtigen Seitenverhältnis vorliegen, auch wenn das Artikelbild („featured image“) automatisch in den Titel übernommen wird. Diese Funktionalität ist im Catch Evoltion schon enthalten (in Yoko übrigens auch). Die Funktion hat vier Parameter: add_image_size( $name, $width, $height, $crop )

  • $name ist der Name, unter dem das Format gezielt angesprochen werden kann
  • $width, $height sind die Abmessungen; ein Wert muss angegeben werden, wenn das Bild proportional verkleinert werden soll, wird der andere mit 9999 angegeben
  • $crop legt fest, ob proportional verkleinert oder absolut beschnitten werden soll.

Für das Format „resp-header-full“ wird ein Bild also immer auf 1600x400px beschnitten, für „resp-mini“ wird das Bild proportional auf eine Breite von 278px verkleinert. (Die drei proportionalen Breiten 278, 320 und 592px verwende ich mit Responsify-WP im Textteil, für die Titelbilder werden sie nicht genutzt)

Alternativ kann man sich natürlich auch an den gängigsten Bildschirmauflösungen seiner Besucher orientieren und die Bildgrößen darauf optimieren

// headers are 1600x400 or a fraction thereof, so all must be hard cropped
add_image_size('resp-head-full', 1600, 400, true); //this is the maximum size we want for header images
add_image_size('resp-head-1440', 1440, 360, true);
add_image_size('resp-head-1366', 1366, 341, true);
add_image_size('resp-head-sxga', 1280, 320, true);
add_image_size('resp-head-xga', 1024, 256, true);
add_image_size('resp-head-medium', 960, 240, true);
add_image_size('resp-head-720', 720, 180, true);
add_image_size('resp-head-xsmall', 467, 116, true);
add_image_size('resp-head-mini', 320, 80, true);

Mit dem Plugin Regenerate Thumbnails können dann für alle Bilder in der Mediathek die neuen Bildgrößen mit ein paar Klicks automatisch erzeugt werden; neu hochgeladene Bilder werden sofort automatisch in alle Größen konvertiert.

Schritt 2:
picturefill.js einbinden

Eine Anmerkung vorab: solange das Plugin Responsify WP aktiv ist, kann dieser Schritt übersprungen werden; das Plugin bindet die picturefill.js selbst ein.

Ich habe mich für die alte Version 1.2 entschieden, da sie auf jeden Fall auch mit älteren Browsern kompatibel ist, die das neue picture Element noch nicht verstehen. Runterladen kann man das Skript direkt bei Github; Archiv entpacken und die picturefill.js aus dem Verzeichnis dist in den (Child-)Theme Ordner hochladen. Wenn man es ganz elegant machen will, erzeugt man sich vorher noch einen Unterordner /js und lädt die Datei dort hoch.

Damit die Datei auch geladen wird und verwendet werden kann, muss sie in WordPress eingehängt werden. Das ist ebenfalls wieder mit ein paar Zeilen Code in der functions.php erledigt (ggf. den Pfad anpassen!):

function add_picturefill(){
	wp_enqueue_script( 'picturefill_header', get_stylesheet_directory_uri() . '/js/picturefill.js', array(), '1' );
}

add_action('wp_enqueue_scripts', 'add_picturefill');

Schritt 3:
statische Titelbilder austauschen

Zuerst die alles entscheidende Frage: Wo und wie genau wird das Titelbild eingebunden? Meistens passiert das in der header.php, bei Catch Evolution passiert es über die Funktion catchevolution_featured_header(), die sich in wp-content/themes/catch-evolution/inc/custom_header.php versteckt:

/**
 * Header Image
 *
 * Uses Custom Header and Featued Images
 * @Hooked in catchevolution_headercontent
 * @since Catch Evolution 1.0
 */
function catchevolution_featured_header() {
	global $wp_query, $post, $paged, $_wp_default_headers;

	// Header Image
	$header_image_path = get_header_image();

	// Check if this is a post or page, if it has a thumbnail, and if it's a big one
	if ( is_singular() && current_theme_supports( 'post-thumbnails' ) &&
			has_post_thumbnail( $post->ID ) &&
			( /* $src, $width, $height */ $image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'post-thumbnail' ) ) &&
			$image[1] >= HEADER_IMAGE_WIDTH ) :
		// Houston, we have a new header image!
		echo '<div id="header-image">';
			echo get_the_post_thumbnail( $post->ID );
		echo '</div>';
	elseif ( get_header_image() ) : ?>
		<div id="header-image">
			<img src="<?php header_image(); ?>" width="<?php echo get_custom_header()->width; ?>" height="<?php echo get_custom_header()->height; ?>" alt="" />
		</div>
	<?php endif; 

} // catchevolution_featured_header

Wie oben schon angesprochen verwendet das Theme automatisch das Artikelbild, wenn dieses mindestens 1600 Pixel breit ist – deswegen müssen wir an zwei Stellen eingreifen.

Picturefill.js funktioniert nur mit der post_id des angehängten Bildes, header_image() liefert aber die URL – also brauchen wir zuerst noch eine kleine Funktion, die uns aus der URL die ID liefert. Auch diese Funktion kommt in die functions.php:

function get_attachment_id_from_src($url) {
  global $wpdb;
  $prefix = $wpdb->prefix;
  $attachment = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $url ));
    return $attachment[0];
}

Zu guter Letzt wird die umgebaute Funktion catchevolution_featured_header() eingebaut, ebenfalls wieder in functions.php. Mehr Varianten dazu hat Stefan Ledin mit Responsify-WP auf Github beschrieben.

function catchevolution_featured_header() {
	global $wp_query, $post, $paged, $_wp_default_headers;

	// Header Image
	$header_image_path = get_header_image();

	// Check if this is a post or page, if it has a thumbnail, and if it's a big one
	if ( is_singular() && current_theme_supports( 'post-thumbnails' ) &&
			has_post_thumbnail( $post->ID ) &&
			( /* $src, $width, $height */ $image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'post-thumbnail' ) ) &&
			$image[1] >= HEADER_IMAGE_WIDTH ) :
		// Houston, we have a new header image!
		echo '<div id="header-image">';
			$thumbnail_id = get_post_thumbnail_id( $post->ID );
			echo Picture::create( 'element', $thumbnail_id, array('sizes' => array( 'resp-head-mini', 'resp-head-xsmall', 'resp-head-small', 'resp-head-medium', 'resp-head-large', 'resp-head-xlarge', 'resp-head-full' )
			) );
		echo '</div>';
	elseif ( get_header_image() ) : ?>
		<div id="header-image">
			<?php
				$header_id = get_attachment_id_from_src($header_image_path);
				echo Picture::create( 'element', $header_id, array(
					'sizes' => array( 'resp-head-mini', 'resp-head-xsmall', 'resp-head-small', 'resp-head-medium', 'resp-head-large', 'resp-head-xlarge', 'resp-head-full', 'full' )
					)
				);
			?>
		</div>
	<?php endif;
} // catchevolution_featured_header

Wer nicht automatisch das Artikelbild auch als Titelbild verwenden möchte, lässt einfach ein paar Zeilen weg:

function catchevolution_featured_header() {
	global $wp_query, $post, $paged, $_wp_default_headers;

	// Header Image
	$header_image_path = get_header_image(); ?>
		<div id="header-image">
			<?php
				$header_id = get_attachment_id_from_src($header_image_path);
				echo Picture::create( 'element', $header_id, array(
					'sizes' => array( 'resp-head-mini', 'resp-head-xsmall', 'resp-head-small', 'resp-head-medium', 'resp-head-large', 'resp-head-xlarge', 'resp-head-full', 'full' )
					)
				);
			?>
		</div>
	<?php
} // catchevolution_featured_header

Schritt 4:
Erfolgskontrolle

Kontrollieren lässt sich das Ergebnis im Browser: in der Quellcode-Ansicht steht statt

[code lang=“html“]<div id="header-image">
<img src="http://domain.tld/wp-content/uploads/headerimage.jpg" …>
</div>[/code]

jetzt ein ganzer Satz von möglichen Bildern, die vom Browser intelligent passend zur aktuellen Auflösung geladen werden:

[code lang=“html“]<div id="header-image">
<span data-picture data-alt="">
<span data-src="http://domain.tld/wp-content/uploads/headerimage-320×80.jpg" ></span>
<span data-src="http://domain.tld/wp-content/uploads/headerimage-467×116.jpg" data-media="(min-width: 320px)" ></span>
<span data-src="http://domain.tld/wp-content/uploads/headerimage-767×191.jpg" data-media="(min-width: 467px)" ></span>
<span data-src="http://domain.tld/wp-content/uploads/headerimage-960×240.jpg" data-media="(min-width: 767px)" ></span>
<span data-src="http://domain.tld/wp-content/uploads/headerimage-1059×264.jpg" data-media="(min-width: 960px)" ></span>
<span data-src="http://domain.tld/wp-content/uploads/headerimage-1224×306.jpg" data-media="(min-width: 1059px)" ></span>
<span data-src="http://domain.tld/wp-content/uploads/headerimage.jpg" data-media="(min-width: 1224px)" ></span>
<noscript><img src="domain.tld/wp-content/uploads/headerimage-320×80.jpg" alt=""></noscript>
</span>
</div>[/code]

Wenn man die Größe des Browserfensters ändert, ändert sich auch die URL des Titelbilds.

Achtung: picturefill.js hat bei mir nicht mehr funktioniert, als ich es asynchron mit defer='defer' geladen habe; auch die Zusammenfassung mit anderen eingebundenen js-Dateien hat zu Problemen geführt – ggf. muss man beim Einsatz eines Caching-Plugins also darauf achten. Laden im Footer hat keinen negativen Einfluss.

Bei der Umsetzung geholfen haben mir die Erläuterungen zu Responsify-WP, dieser Artikel von wpmudev und ein paar Tassen Kaffee ;)

W·

Gelegenheitsblogger, bekennender Unterstützer der deutschen Bark Alexander von Humboldt II (ab und an in der Bierwerbung einer norddeutschen Brauerei zu sehen) mit einem Faible für Ju-52 und Meer, reist, liest, arbeitet - alles in allem also ziemlich normal.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.

https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_smilenew.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_biggrin2.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_sadnew.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_eek.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_shocked.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_confusednew.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_coolnew.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_lol.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_madnew.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_seb_zunge.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_blushnew.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_frown.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_twistedevil1.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_twistedevil2.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_rolleyesnew.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_wink2.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_idea2.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_neutral_new.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_biggrin.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_xd.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_xd2.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_ugly.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_freu.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_freu2.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_motz.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_lachtot.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_irre.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_helpnew.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_wallbash.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_gott.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_hurra3.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_skeptisch.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_bravo2.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_pfeif2.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_nicken.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_no_sad.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_aufsmaul.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_doh.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_smilina.gif 
https://the.mnbvcx.net/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_winken4.gif