Jump to content

Adaptive images for different screens


SamC
 Share

Recommended Posts

So I've been searching around the forum and read a number of posts for some kind of better way of serving up different images when on different width screens (not too bothered about height).

I have some code like this:

//main.php
<div class='<?php if ($page->fullWidthImage) {
    echo "full-width-image";} else {echo "no-full-width-image";} ?> mobile-top'
    
    style='background-image:url("<?php if ($page->fullWidthImage) {
        getImage($page, 'fullWidthImage', 'desktop');
    } ?>");'>
  

I put a few breaks in so it makes more sense. Probably a bit clunky, but anyway, it works when I pass the fieldname and the size I want as strings. It calls a function getImage() in _func.php:
 

//func.php
/**
 *
 * @param object Page
 * @param string $fieldName (fullWidthImage, mainImage etc.)
 * @param string $img (mobile, tablet, desktop, xlDesktop)
 * @return string $imgUrl
 *
 */
function getImage($page, $fieldName, $img) {

    if ($page->$fieldName) {

        switch ($img) {
            case 'mobile':
                $img = $page->$fieldName->size(400, 200, 'center');
                break;           
            case 'tablet':
                $img = $page->$fieldName->size(750, 375, 'center');
                break;
            case 'desktop':
                $img = $page->$fieldName->size(1500, 750, 'center');
                break;
            case 'xlDesktop':
                $img = $page->$fieldName->size(2400, 1200, 'center');
                break;
            }

            $imgUrl = $img->url;
            echo $imgUrl;
    }
}

So, my images get created when the page loads in the browser. I'm ok with this because I usually view a page once it's published on the big screen so the largest image is created already for subsequent loads.

I used some CSS media queries in the past to show different images on different screens, but I think there must be a better way. I read about adaptive images and saw that the obvious problem is PHP can't work out the screen width, and even if you do work this out via JS, you can't pass the value to PHP BEFORE running this function because the page has already been sent back to the browser before the JS runs (is this right?).

My initial thoughts were that I could pass a screen width (integer) into the function, then just return the correct image depending on this number, instead of passing 'desktop', 'tablet' etc.. something like this:
 

getImage($page, 'fullWidthImage', $screenWidth);

So I set a cookie in the head section:

<script>(document.cookie='screenWidth='+Math.round(screen.width))</script>

...which I can see in the developer tools, an integer with value 1440. Getting somewhere! Then I realise I don't know how to get this number into my function. I noticed adaptive images ( http://adaptive-images.com/ )  creates images etc... at a certain path and uses an additional php script before the image is loaded. However, PW already has a way of easily creating different sized images on the fly, they're right there, I only need to serve up the right one. Seems unnecessary creating the images into a different folder for this, the PW structure is fine as it is.

The 'srcset' attribute ( https://css-tricks.com/responsive-images-youre-just-changing-resolutions-use-srcset/ ) is something that interests me, but the lack of support worries me.

I'm not really after a copy/paste solution so any additional ideas are more than welcome. Thanks.

Link to comment
Share on other sites

I'd suggest you to not waste your time and use srcset/picture element. If you really need to worry about browser support add picturefil to your page as well. Selection of best image size is simply best left to the browser and anything else probably isn't better than the picturefil polyfill.

  • Like 3
Link to comment
Share on other sites

18 minutes ago, LostKobrakai said:

I'd suggest you to not waste your time and use srcset/picture element. If you really need to worry about browser support add picturefil to your page as well. Selection of best image size is simply best left to the browser and anything else probably isn't better than the picturefil polyfill.

Ok, you sound confident, I'll look into how to implement this on background images.

Link to comment
Share on other sites

11 minutes ago, LostKobrakai said:

Background images do not need anything new. Just use media queries to target viewport sizes.

That's what I did the first time round.

The problem I encountered was when there was more than one large/full width image on the same page. I ended up having similar inline CSS multiple times with different classnames. Like on this one page site, I used the page ID to get unique classnames or every image would be the same, regardless of having different images on the child pages:
 

        <!-- start main content -->
        <?php $childPages = $page->children; ?>

        <?php foreach($childPages as $item): ?>

                <?php if ($item->mainImage): ?>

                    <style type="text/css">
                        @media screen and (max-width: 849px) {
                            .image-<?php echo "$item->id"; ?> {
                                background-image: url('<?php echo getImage($item, 'medium'); ?>');
                            }

                        @media screen and (min-width: 850px) and (max-width: 1499px) {
                            .image-<?php echo "$item->id"; ?> {
                                background-image: url('<?php echo getImage($item, 'large'); ?>');
                            }
                        }

                        @media screen and (min-width: 1500px) {
                            .image-<?php echo "$item->id"; ?> {
                                background-image: url('<?php echo getImage($item, 'xLarge'); ?>');
                            }
                        }
                    </style>

                <?php endif; ?>

                <?php echo $item->render(); ?>

        <?php endforeach; ?>
        <!-- end main content -->

Saying that, it worked ok so I guess it wasn't a 'problem' as such.

Edited by SamC
Pasted updated CSS
Link to comment
Share on other sites

I'd evaluate if the image really should be a background image in the first place. Otherwise this is the only way to have dynamic css backgrounds. I've added a bit more flexible version of yours below.

<style type="text/css">
  <?php
  // Selectors overwrite each other (by order) so no need for different mq selectors
  // Eg. xlarge (true) -> large (false by mq) -> medium (false by mq) => xlarge image
  // Eg. xlarte (true) -> large (true by mq) -> medium (true by mq) => medium image
  // Reverse order (default still first) when using min-width mqs
  foreach (['xlarge' => "", 'large' => "1499px", 'medium' => "849px"] as $imgSize => $mq) {
    if(strlen($mq)) echo "@media screen and (max-width: $mq) {";
    echo ".image-$item->id { background-image: url('" . getImage($item, $imgSize) . "'); }";;
    if(strlen($mq)) echo "}";
  }
  ?>
</style>

 

  • Like 2
Link to comment
Share on other sites

20 minutes ago, LostKobrakai said:

I'd evaluate if the image really should be a background image in the first place. Otherwise this is the only way to have dynamic css backgrounds. I've added a bit more flexible version of yours below.


<style type="text/css">
  <?php
  // Selectors overwrite each other (by order) so no need for different mq selectors
  // Eg. xlarge (true) -> large (false by mq) -> medium (false by mq) => xlarge image
  // Eg. xlarte (true) -> large (true by mq) -> medium (true by mq) => medium image
  // Reverse order (default still first) when using min-width mqs
  foreach (['xlarge' => "", 'large' => "1499px", 'medium' => "849px"] as $imgSize => $mq) {
    if(strlen($mq)) echo "@media screen and (max-width: $mq) {";
    echo ".image-$item->id { background-image: url('" . getImage($item, $imgSize) . "'); }";;
    if(strlen($mq)) echo "}";
  }
  ?>
</style>

 

Nice! You're totally right though, I'm going back to the drawing board on this and using an inline image with absolutely positioned overlay text.

My PHP is basic but came up with this which outputs the correct HTML:
 

//main.php
<?php getAvailableImages($page, 'fullWidthImage'); ?>

//_func.php
function getAvailableImages($page, $fieldName) {
    if ($page->$fieldName) {

        $str = '';

        $mobileWidth = 400;
        $tabletWidth = 750;
        $desktopWidth = 1500;
        $xlDesktopWidth = 2400; 

        $mobile = $page->$fieldName->size($mobileWidth, 200, 'center');
        $tablet = $page->$fieldName->size($tabletWidth, 375, 'center');
        $desktop = $page->$fieldName->size($desktopWidth, 750, 'center');
        $xlDesktop = $page->$fieldName->size($xlDesktopWidth, 1200, 'center');

        $str = "<img src='$mobile->url' srcset='$tablet->url {$tabletWidth}w, $desktop->url {$desktopWidth}w, $xlDesktop->url {$xlDesktopWidth}w' alt='adaptive image'>";

        echo $str;
    }
}

//OUTPUTS
<img src='/site/assets/files/1069/desk-duotone-1.400x200.jpg' srcset='/site/assets/files/1069/desk-duotone-1.750x375.jpg 750w, /site/assets/files/1069/desk-duotone-1.1500x750.jpg 1500w, /site/assets/files/1069/desk-duotone-1.2400x1200.jpg 2400w' alt='adaptive image'>

Actually works quite well, never used srcset before.

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...