Forum

Responsive Background Images with Perch

Hi all,

I've been developing a site using Perch over the last few weeks and ran into the issue of how to deliver the correctly sized image for each device when using background images.

Perch works well with delivering the right sized image for <img> or <picture> tags but from my understanding background images are a bit trickier.

I've come up with a solution that works for me, which is a little hacky, as it adds an image using the normal tags which generates the images needed, and then suppresses it and removes it from view using suppress="true" and display:none;. It then goes through the array generated and finds the details needed, and then pieces them together to create media queries from that data.

I'm sure there's many ways to improve what I've done, so feel free to contribute if you find a better way of doing it.

I've added this to suggestions and add-on development to provoke some discussion on whether Perch should or could incorporate some way of using responsive background images in Perch

You can find all the code here on GitHub

Fred Rivett

Fred Rivett 0 points

  • 7 years ago
Drew McLellan

Drew McLellan 2638 points
Perch Support

What output are you trying to get? i.e. how do you do this for a static site?

Hi Drew.

I'm sure there's probably a better way of doing this, but none seem obvious to me so I went ahead and did it this way.

The output the above generates (and what I was aiming to get) is the following:

<style>
      .header-block {
        background-image:url(https://newlifecastledouglas.com/perch/resources/hipster-desk-1.jpg);
        background-position:center 40%;
      }
        @media only screen and (max-width: 1920px) {
          .header-block {
            background-image:url(https://newlifecastledouglas.com/perch/resources/hipster-desk-1-w1920.jpg)
          }
        }
        @media only screen and (max-width: 1366px) {
          .header-block {
            background-image:url(https://newlifecastledouglas.com/perch/resources/hipster-desk-1-w1366.jpg)
          }
        }
        @media only screen and (max-width: 640px) {
          .header-block {
            background-image:url(https://newlifecastledouglas.com/perch/resources/hipster-desk-1-w640.jpg)
          }
        }
</style>

The user uploads an image (prompted by the background_image.html content type) and then it grabs all the image data generated from there, processes it through and spits out the above. As I say, it's certainly a bit hacky and isn't the best way of doing it, but I didn't know of another and for this project this worked so I was happy enough.

Does that make sense? Sorry if I'm not being clear. If you know of another way to do this better using Perch I'm more than happy to hear it.

Drew McLellan

Drew McLellan 2638 points
Perch Support

As a Perch template you'd do that like this:

<style>
      .header-block {
        background-image:url(<perch:content id="image" type="image" label="Background image" />);
        background-position:center 40%;
      }
        @media only screen and (max-width: 1920px) {
          .header-block {
            background-image:url(<perch:content id="image" type="image" label="Background image" width="1920" />)
          }
        }
        @media only screen and (max-width: 1366px) {
          .header-block {
            background-image:url(<perch:content id="image" type="image" label="Background image" width="1366" />)
          }
        }
        @media only screen and (max-width: 640px) {
          .header-block {
            background-image:url(<perch:content id="image" type="image" label="Background image" width="640" />)
          }
        }
</style>

Hi Drew,

Thanks for the response. Yeah, that does look a lot easier! I wasn't sure how the image processing works so I tried to stick closely to one of the examples on the Using Responsive Images in Perch (Changing Image Sizes Use Case).

Your example makes a lot more sense now I think about it! Still getting to grips with the flexibility of Perch.

Thanks Drew.

The above example works really well for use in a standalone Perch template. However for using as part of a bigger template (e.g. blog/post.html) it seems a bit more complicated.

The above example works by placing the <?php perch_content('Header Background Image'); ?> in the <head> tags on the page. But for my example below, I don't think I have a way of doing easily, without putting my whole page content into the template tag. This is what I have at the moment:

<article class="h-entry">
  <div>
    <h1 class="post-title">
      <a href="<perch:blog id="postURL" type="hidden" />" rel="bookmark" class="p-name">
        <perch:blog id="postTitle" type="text" label="Title" required="true" size="xl autowidth" order="1" />
      </a>
    </h1>

      <time class="dt-published" datetime="<perch:blog id="postDateTime" type="date" label="Date" time="true" format="Y-m-d H:i:s" divider-before="Meta information" />">
      <perch:blog id="postDateTime" type="date" time="true" format="%d %B %Y" /> 
    </time>
  </div>

    <!-- this :if exists="image" section sets up options for the backend that are
    <--- utilised in post.php to grab this information in other places on the page -->
    <perch:if exists="image">
        <div style="display:none;">

          <picture>
            <source
              sizes='100vw'
              srcset='
                <perch:blog type="image" id="image" label="Image" width="640" suppress="true" /> 640w,
                <perch:blog type="image" id="image" label="Image" width="1366" suppress="true" /> 1366w,
                <perch:blog type="image" id="image" label="Image" width="1920" suppress="true" /> 1920w'>
            <img src='https://www.newlifecastledouglas.com<perch:blog type="image" id="image" label="Image" help="Full size image for large screens" suppress="true" />' alt='<perch:content type="text" id="alt" label="Description" required="true" help="Description of subject of these images." title="true" />' />
          </picture>

          <perch:blog type="select" options="center top, center 10%, center 20%, center 30%, center 40%, center 50%, center 60%, center 70%, center 80%, center 90%, center bottom" allowempty="true" required="false" id="background_position" label="Background Position" suppress="true" />
        </div>
    </perch:if>

    <div class="description e-content">
        <perch:blog id="postDescHTML" type="textarea" label="Post" order="2" editor="markitup" markdown="true" size="xxl autowidth" required="true" />
    </div>
</article>

<perch:blog id="excerpt" type="textarea" label="Excerpt" markdown="true" order="3" suppress="true" size="s" />
<perch:blog id="image" type="image" width="50" height="50" crop="true" suppress="true" />
<perch:blog id="color-picker" type="color" required="false" suppress="true" help="(Optional) If you so wish you can select a colour for the H1 item. This should be a strong colour from the blog image uploaded. It defaults to a dark grey." />

This code works well as it adds an image upload and a background position dropdown to the blog post admin interface. But there's no easy way of getting this information out onto my post.php file below:

<?php
  $root = $_SERVER['DOCUMENT_ROOT'];
  include($root . '/perch/runtime.php');
  $title = perch_blog_post_field(perch_get('s'), 'postTitle', true);
  $color = perch_blog_post_field(perch_get('s'), 'color-picker', true);
  $color_style = "style='color:" . $color . ";'";
?>

<!doctype html>
<html class="no-js" lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title><?php echo isset($title) ? $title : perch_pages_title(true); ?> | New Life Church Castle Douglas</title>
  <link rel="stylesheet" type="text/css" href="/css/foundation.css" />
  <link rel="stylesheet" type="text/css" href="/css/style.css" />
  <script src="/js/vendor/modernizr.js"></script>
  <?php perch_content('Google Analytics'); ?>

  <link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
  <link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
  <link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
  <link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
  <link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
  <link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
  <link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
  <link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
  <link rel="icon" type="image/png" href="/favicon-192x192.png" sizes="192x192">
  <link rel="icon" type="image/png" href="/favicon-160x160.png" sizes="160x160">
  <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
  <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
  <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
  <meta name="msapplication-TileColor" content="#2d89ef">
  <meta name="msapplication-TileImage" content="/mstile-144x144.png">

  <?php // do the processing to get background image values ?>
</head>

<body class="sub-page single-blog-post">

  <?php print_r($image_widths); ?>

  <?php 
    echo "dir_base: " . $dir_base . "<br />";
    echo "dir_ext: " . $dir_ext . "<br />";
  ?>

  <section class="block header-block">

    <?php // perch_blog_post_field(perch_get('s'), 'background_position'); ?>

    <div class="row">
      <div class="large-12 columns">

        <?php include('../inc/header-nav.php'); ?>

        <span class="page-title-outer">
          <aside class="latest-news"><a href="/latest-news/" <?php echo $color_style; ?>>
              Latest News »</a></aside>
          <h1 <?php echo $color_style; ?>>
            <?php echo $title; ?>
          </h1>
        </span>

      </div>
    </div>

  </section>

  <section class="main-cont">

    <div class="row">
      <div class="large-8 columns left-col">

        <?php perch_blog_post(perch_get('s')); ?>

        <div class="meta">

          <div class="cats">
              <?php perch_blog_categories(perch_get('s')); ?>
          </div>

          <div class="tags">
              <?php perch_blog_post_tags(perch_get('s')); ?>
          </div>

        </div>

        <p class="font14"><a href="/latest-news/">« Back to Latest News</a></p>

      </div>

      <div class="large-4 columns right-col">

        <?php include('sidebar.php'); ?>

      </div>
    </div>

  </section>

    <?php include($root . '/inc/footer.php'); ?>

</body>

The page above gets the blog post at <?php perch_blog_post(perch_get('s')); ?>, is there a way to get what I need another way so I can output it in the <head> (as <style> isn't allowed inside <body> tags), or do I either need to put my whole page content into perch/templates/blog/post.html or continue with my slightly hacky way of getting the infromation?

At the moment I'm doing $image = perch_blog_post_field(perch_get('s'), 'image', true); and then process that through, but it returns an array and that's where it starts to get complicated with the processing that though.

Thought I best ask as last time the answer was a lot simpler than I thought. My way works but is a bit hacky.

Thanks.

Drew McLellan

Drew McLellan 2638 points
Perch Support

You can display your post using as many different templates as you like. Just make sure all the fields are in the post.html template (so they are created when the post is edited) and then you can display the post using any number of templates with different markup and a selection of the fields.

Cool, thanks Drew. Gradually getting used to how Perch is supposed to be used.