Drupal Theme bauen, wenn der Designer eine Abneigung gegen rechteckige Bilder hat
Jürgen Haas - @jurgenhaas
20. Mai 2021
Lasst uns das ohne JavaScript lösen. Wir verwenden SVG Masken. Das bringt uns folgende Vorteile:
<svg width="0" height="0" viewBox="0 0 1920 900">
<defs>
<mask id="mask1">
<polygon points="0,100 580,100 680,0 1920,0 1920,860 1200,860 400,900 0,800 0,80" fill="#FFFFFF"></polygon>
</mask>
</defs>
</svg>
<div class="container">
<img src="balloons.jpg" alt="Balloons">
</div>
.container img {
height: 100%;
width: 100%;
object-fit: cover;
-webkit-mask-image: url(#mask1);
mask-image: url(#mask1);
}
<svg width="0" height="0" viewBox="0 0 1920 900">
<defs>
<mask id="mask1">
<polygon points="0,100 580,100 680,0 1920,0 1920,860 1200,860 400,900 0,800 0,80" fill="#FFFFFF"></polygon>
</mask>
</defs>
<image mask="url(#mask1)"
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="/sites/default/files/styles/xl/public/2021-04/Strasse_23nacht.jpg?itok=D37vUPps"></image>
</svg>
<svg width="0" height="0" viewBox="0 0 1920 900">
<defs>
<mask id="mask1"><polygon points="0,100 580,100 680,0 1920,0 1920,860 1200,860 400,900 0,800 0,80" fill="#FFFFFF"></polygon></mask>
<mask id="mask2"><polygon points="0,100 580,100 680,0 1920,0 1920,860 1200,860 400,900 0,800 0,80" fill="#FFFFFF"></polygon></mask>
<mask id="mask3"><polygon points="0,100 580,100 680,0 1920,0 1920,860 1200,860 400,900 0,800 0,80" fill="#FFFFFF"></polygon></mask>
<mask id="mask4"><polygon points="0,100 580,100 680,0 1920,0 1920,860 1200,860 400,900 0,800 0,80" fill="#FFFFFF"></polygon></mask>
<mask id="mask5"><polygon points="0,100 580,100 680,0 1920,0 1920,860 1200,860 400,900 0,800 0,80" fill="#FFFFFF"></polygon></mask>
</defs>
<image mask="url(#mask1)" xlink:href="/sites/default/files/styles/xl/public/2021-04/Strasse_23nacht.jpg?itok=D37vUPps" class="breakpoint-1" xmlns:xlink="http://www.w3.org/1999/xlink"></image>
<image mask="url(#mask2)" xlink:href="/sites/default/files/styles/default/public/2021-04/Strasse_23nacht.jpg?itok=rT2I0qvO" class="breakpoint-2" xmlns:xlink="http://www.w3.org/1999/xlink"></image>
<image mask="url(#mask3)" xlink:href="/sites/default/files/styles/desktop/public/2021-04/Strasse_23nacht.jpg?itok=lrRjIri9" class="breakpoint-3" xmlns:xlink="http://www.w3.org/1999/xlink"></image>
<image mask="url(#mask4)" xlink:href="/sites/default/files/styles/tablet/public/2021-04/Strasse_23nacht.jpg?itok=ggDSxihV" class="breakpoint-4" xmlns:xlink="http://www.w3.org/1999/xlink"></image>
<image mask="url(#mask5)" xlink:href="/sites/default/files/styles/mobile/public/2021-04/Strasse_23nacht.jpg?itok=I0dPkMTc" class="breakpoint-5" xmlns:xlink="http://www.w3.org/1999/xlink"></image>
</svg>
… und per CSS anhand @media Query und display:none;
oder visibility:hidden;
die nicht benötigten Bilder ausblenden.
Optisch werden die nicht benötigten Bild-Varianten ausgeblendet.
Aber ein Blick in die Browser Dev-Tools zeigt, dass die restlichen Bilder trotzdem geladen werden.
Diese Beobachtung wird hier bestätigt und die einzige Chance für wirklich responsive Performance wird mit dem Picture Element unterstützt.
<picture>
<source srcset="/sites/default/files/styles/xl/public/2021-04/Strasse_23nacht.svg" media="all and (min-width: 1921px)" type="image/svg+xml">
<source srcset="/sites/default/files/styles/default/public/2021-04/Strasse_23nacht.svg" media="all and (min-width: 1281px) and (max-width: 1920px)" type="image/svg+xml">
<source srcset="/sites/default/files/styles/desktop/public/2021-04/Strasse_23nacht.svg" media="all and (min-width: 801px) and (max-width: 1280px)" type="image/svg+xml">
<source srcset="/sites/default/files/styles/tablet/public/2021-04/Strasse_23nacht.svg" media="all and (min-width: 481px) and (max-width: 800px)" type="image/svg+xml">
<source srcset="/sites/default/files/styles/mobile/public/2021-04/Strasse_23nacht.svg" media="all and (max-width: 480px)" type="image/svg+xml">
<img src="/sites/default/files/styles/default/public/2021-04/Strasse_23nacht.jpg?itok=OMpJGJ81" alt="Dummy" typeof="foaf:Image">
</picture>
Und die SVGs so:
<svg width="0" height="0" viewBox="0 0 1920 900">
<defs>
<mask id="mask1"><polygon points="0,100 580,100 680,0 1920,0 1920,860 1200,860 400,900 0,800 0,80" fill="#FFFFFF"></polygon></mask>
</defs>
<image mask="url(#mask1)" xlink:href="/sites/default/files/styles/xl/public/2021-04/Strasse_23nacht.jpg?itok=D37vUPps" xmlns:xlink="http://www.w3.org/1999/xlink"></image>
</svg>
Wenn SVG als Bilder (und nicht inline) eingebunden werden, dann können diese keine externen Images enthalten
<svg xmlns="http://www.w3.org/2000/svg" width="1100" height="800" viewBox="0 0 1100 800">
<defs>
<mask id="mask1">
<polygon points="0,0 300,100 1100,50 1100,750 300,800 0,700 0,0" fill="#FFFFFF" />
</mask>
</defs>
<image mask="url(#mask1)" href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBxdWFsaXR5ID0gNzUK......" />
</svg>
function mytheme_preprocess_responsive_image(&$variables) {
$responsive_image_style = ResponsiveImageStyle::load($variables['responsive_image_style_id']);
if (!$responsive_image_style) {
return;
}
foreach ($responsive_image_style->getKeyedImageStyleMappings() as $keyedImageStyleMapping) {
foreach ($keyedImageStyleMapping as $multiplier) {
if ($multiplier['image_mapping_type'] === 'image_style') {
if ($image_style = ImageStyle::load($multiplier['image_mapping'])) {
$derivative_uri = $image_style->buildUri($variables['uri']);
if (!file_exists($derivative_uri)) {
$image_style->createDerivative($variables['uri'], $derivative_uri);
}
}
}
}
}
$map = new ThemeResponsiveSvgMaskMapping();
/** @var \Drupal\Core\Template\Attribute $source */
foreach ($variables['sources'] as $source) {
if ($source->hasAttribute('srcset') && $def = $map->getDefinition($source->storage()['media']->value(), $variables['responsive_image_style_id'])) {
$id = Html::getUniqueId('mask');
$imagefile = trim(parse_url($source->storage()['srcset']->value(), PHP_URL_PATH), '/');
if (!file_exists($imagefile)) {
continue;
}
$svgfile = $imagefile . $def['suffix'] . '.svg';
if (!file_exists($svgfile) || filemtime($svgfile) < filemtime($imagefile)) {
$image = base64_encode(file_get_contents($imagefile));
$svg = '<svg xmlns="http://www.w3.org/2000/svg" width="' . $def['width'] . '" height="' . $def['height'] . '" viewBox="0 0 ' . $def['width'] . ' ' . $def['height'] . '">';
$svg .= '<defs><mask id="' . $id . '"><polygon points="' . $def['mask'] . '" fill="#FFFFFF" /></mask></defs>';
$svg .= '<image mask="url(#' . $id . ')" href="data:image/jpeg;base64,' . $image . '" />';
$svg .= '</svg>';
file_put_contents($svgfile, $svg);
}
$source->setAttribute('srcset', '/' . $svgfile);
$source->setAttribute('type', 'image/svg+xml');
}
}
}