The Drupal Responsive Background Image module is a nice little module that gives you a preprocess function to display an image field as a, you guessed it, responsive background image. This is useful for hero images, when you want the image to display at different sizes on different-size screens, because you don't want to load an enormous 2000+-pixel-wide image on mobile screens.
The creator of the module made it to work with Paragraphs, and the example in the documentation is for that use. But what if you have a hero image field on a node, and you want to display it as a responsive background image? Here's a preprocess function to do that. It's just modified from the example in the module documentation, nothing fancy. Because we're assuming that there's only one of these images on the page, we need to do a bit less than for Paragraphs. For example, we don't need to add a unique class to the page or node in order to display the correct image.
In my example, I have a content type called Landing Page. It has a single-value field called Hero Image, which is a reference to a Media type called "Fullscreen Image". I am wanting to display the image from that field as a responsive background image using the responsive image style "Fullscreen Hero". Here's the preprocess function to do that.
You'll need to replace "MYTHEME" with the machine name of your theme. I'll indicate with comments in the code the other variables you'll need to change:
/**
* Implements template_preprocess_node().
*/
function MYTHEME_preprocess_node(&$vars) {
$node = $vars['node'];
$type = $node->bundle();
switch ($type) {
// here you will need to replace 'landing_page' with the machine name of your content type
case 'landing_page':
// Make sure the image field is not empty.
// Replace 'field_hero_image' with your content type's image field machine name
if (!empty($node->get('field_hero_image')->getValue()[0]['target_id'])) {
// in your node or page template, you will need to add a div with the class "page-hero". Change this class name if needed to whatever you want to use
$css_selector = ' .page-hero';
// Here we call the method to generate media queries.
// We pass in the CSS selector string as described above.
// We pass in the entity object.
// We pass in the machine name of the image/media image field.
// We pass in the machine name of the Responsive Image Style.
// In this example, I have a Responsive Image Style called 'fullscreen_hero'.
// Replace the field machine name and the responsive image style machine name to whatever you are using.
$style_tag = ResponsiveBackgroundImage::generateMediaQueries($css_selector, $node, 'field_hero_image', 'fullscreen_hero');
// We then check if the media queries were properly generated and attach them to the HTML head.
if ($style_tag) {
$vars['#attached']['html_head'][] = $style_tag;
}
}
break;
}
}
You can also do this in a page_preprocess
function. This sort of makes sense if you're creating a page hero outside of the node content area. Note that if you add the preprocess function to the node and just add the "page-hero" class to a div in the page template, it will still work as the CSS gets loaded in the
/**
* Implements template_preprocess_page().
*/
function MYTHEME_preprocess_page(&$vars) {
$node = $vars['node'];
if($node) {
$type = $node->bundle();
switch ($type) {
case 'landing_page':
// Make sure the image field is not empty.
if (!empty($node->get('field_hero_image')->getValue()[0]['target_id'])) {
$css_selector = ' .page-hero';
$style_tag = ResponsiveBackgroundImage::generateMediaQueries($css_selector, $node, 'field_hero_image', 'fullscreen_hero');
if ($style_tag) {
$vars['#attached']['html_head'][] = $style_tag;
}
}
break;
}
}
}