Jump to content

srcset, sizes and picture support


Gazley
 Share

Recommended Posts

Hi there,

Is there a standard approach in PW to building image markup with (at least) srcset and sizes?

I saw the module by conclurer: Srcset Image Textformatter

However, there are some use-cases that this doesn't cover and I'm not sure whether this module has "ran out of steam" (not much activity on the support thread or Github repo) ?

Maybe PW 3 will provide this support in core?

Any ideas or thoughts would be appreciated.

Many thanks! :)

Link to comment
Share on other sites

On my side i prepared a function for srcset and <picture> tag creation.

Function output look like :

<picture>
     <!--[if IE 9]>
          <video style='display: none;'>
     <![endif]-->
          <source srcset='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-001.404x270.jpg' media='(max-width: 479px)' />  
          <source srcset='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-001.692x462.jpg' media='(max-width: 767px)' />
          <source srcset='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-001.427x285.jpg' media='(max-width: 959px)' />
     <!--[if IE 9]>
          </video>
     <![endif]-->
     <img src='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-001.630x421.jpg' alt='terra-nova-001' class="lazyload uk-width-1-1" />
</picture>
Here are my functions :
/**
/**
 * Generate Attributes Array or String
 *
 * @param $item
 * @return string
 */
function buildAttrs($item) {
    $attributes = "";
    // echo "<pre>Key : " . print_r($item, true) . "</pre>";
    if(array_key_exists('attributes', $item) && is_array($item['attributes'])) {
        foreach($item['attributes'] as $key => $attr) {
            $attributes .= ' ' . $key . '="' . $attr . '"';
        }
    }
    return $attributes;
}

/**
 *
 * @param $image
 * @param $key
 * @param $options
 * @return string
 */
function buildSrcAndSrcset($image, $key, $options) {
    $return = '';
    // echo "<pre>Key : {$key}, " . print_r($options, true) . "</pre>";
    if(!empty($options[$key]) && !empty($options[$key]['sets']) && is_array($options[$key]['sets'])) {
        $x=1;
        $countSets = count($options[$key]['sets']);
        $sets = "";
        foreach($options[$key]['sets'] as $k => $rules) {
            $y=$x++;
            $separator = ($y != $countSets) ? ", " : "";
            if(!is_array($rules) && $rules == 'original') {
                $static_url = static_url($image->url);
                $sets .= "{$static_url} {$key}w{$separator}";
            } elseif(isset($rules['width']) || isset($rules['height'])) {
                $size = imageResize($image, $rules);
                if(!is_null($size)) {
                    $sets .= "{$size['url']} {$size['width']}w{$separator}";
                }
            }
        }
        if($sets != "") $return = " {$key}='{$sets}'";
    } elseif(!empty($options[$key]) && !empty($options[$key]['method']) && is_array($options[$key]['method'])) {
        $img = imageResize($image, $options[$key]['method']);
        if(!is_null($img)) $return = " {$key}='{$img['url']}'";
    } elseif(!empty($options[$key]) && is_string($options[$key])) {
        $return = " {$key}='{$options[$key]}'";
    }
    return $return;
}

/**
 * Image : Create <img /> tag with attributes and responsive lazyload option
 *
 * @param $image
 * @param array $options
 * @return string
 */
function image($image, $options = array(), $lightbox=FALSE) {

    $return = "";

    // Alt attribute
    $alt = ($image->description != '') ? $image->description : pathinfo($image->filename, PATHINFO_FILENAME);
    $alt = " alt='{$alt}'";

    if(array_key_exists('picture', $options) && is_array($options['picture'])) {
        $picture = $options['picture'];
        // Set Attributes
        $attributes = "";
        if(array_key_exists('attributes', $picture)) {
            $attributes = buildAttributes($picture['attributes']);
        }
        $return .= "\n<picture{$attributes}>";
        if(array_key_exists('source', $options['picture']) && is_array($options['picture']['source'])) {
            $return .= "\n\t<!--[if IE 9]><video style='display: none;'><![endif]-->";
            $sources = $options['picture']['source'];
            foreach($sources as $key => $source) {
                $attrSrc = buildSrcAndSrcset($image, 'src', $source);
                $attrSrcset = buildSrcAndSrcset($image, 'srcset', $source);
                $attrDataSrcset = buildSrcAndSrcset($image, 'data-srcset', $source);
                $attributes = buildAttrs($source);
                $attrMedia = " media='{$key}'";
                $return .= "\n\t\t<source{$attrSrc}{$attrSrcset}{$attrDataSrcset}{$attributes}{$attrMedia} />";
            }
            $return .= "\n\t<!--[if IE 9]></video><![endif]-->";
        }
        if(array_key_exists('img', $options['picture']) && is_array($options['picture']['img'])) {
            $img = $options['picture']['img'];
            $attrSrc = buildSrcAndSrcset($image, 'src', $img);
            $attrSrcset = buildSrcAndSrcset($image, 'srcset', $img);
            $attrDataSrcset = buildSrcAndSrcset($image, 'data-srcset', $img);
            $attributes = buildAttrs($img);

            $return .= "\n\t<img{$attrSrc}{$attrSrcset}{$attrDataSrcset}{$alt}{$attributes} />";

        }
        $return .= "\n</picture>";
    } elseif(array_key_exists('img', $options) && is_array($options['img'])) {
        $img = $options['img'];
        $attrSrc = buildSrcAndSrcset($image, 'src', $img);
        $attrSrcset = buildSrcAndSrcset($image, 'srcset', $img);
        $attrDataSrcset = buildSrcAndSrcset($image, 'data-srcset', $img);
        $attributes = buildAttrs($img);

        $return .= "\n<img{$attrSrc}{$attrSrcset}{$attrDataSrcset}{$alt}{$attributes} />";
    } else {
        $src = " src='" . static_url($image->url) . "'";
        $width = " width='{$image->width}'";
        $height = " height='{$image->height}'";
        // Set Attributes
        $attributes = "";
        if(array_key_exists('attributes', $options)) {
            $attributes = buildAttributes($options['attributes']);
        }

        $return .= "\n<img{$src}{$width}{$height}{$alt}{$attributes} />";
    }

    if(isset($lightbox) && $lightbox != FALSE) {
        $page = wire('page');
        $title = ($image->description != "") ? $image->description : $page->title;
        $overlayEffect = (!is_bool($lightbox) && $lightbox != '') ? " " . $lightbox : " uk-overlay-fade";
        $return = "\n<figure class='uk-overlay uk-overlay-hover'>
                   \n\t{$return}
                   \n\t<div class='uk-overlay-panel uk-overlay-background{$overlayEffect}'></div>
                   \n\t<div class='uk-overlay-panel uk-overlay-icon{$overlayEffect}'></div>
                   \n\t<a class='uk-position-cover' href='{$image->url}' title='{$title}' data-uk-lightbox=\"{group:'{$page->name}'}\"><span class='uk-hidden'>{$title}</span></a>
                   \n</figure>";
    }

    return $return;
}

/**
 * Resize Image
 *
 * @param $image
 * @param array $method
 * @return array|null
 */
function imageResize($image, $method=array()) {
    $alt = ($image->description != '') ? $image->description : pathinfo($image->filename, PATHINFO_FILENAME);
    if(isset($method['type']) && isset($method['width']) || isset($method['height'])) {
        // Set Resize Options
        if(isset($method['options'])) $options = $method['options'];
        else $options = wire('config')->imageSizerOptions;

        if($method['type'] === 'size' && isset($method['width']) && isset($method['height'])) {
            $size = $image->size($method['width'], $method['height'], $options);
        } elseif($method['type'] === 'width' && isset($method['width'])) {
            $size = $image->width($method['width'], $options);
        } elseif($method['type'] === 'height' && isset($method['height'])) {
            $size = $image->height($method['height'], $options);
        } else {
            $size = null;
        }

        if(!is_null($size)) {
            return array(
                'url' => static_url($size->url),
                'width' => $size->width,
                'height' => $size->height,
                'alt' => $alt
            );
        }
    } elseif(is_null($method)) {
        return array(
            'url' => static_url($image->url),
            'width' => $image->width,
            'height' => $image->height,
            'alt' => $alt
        );
    }
    return null;
}

/**
 * Return url with static url
 *
 * @param string $url
 * @return string
 */
function static_url($url="") {
    $config = wire('config');
    if($config->debug === false && isset($config->static_url) && $config->static_url != "") {
        $static_url = $config->static_url;
    } else {
        $static_url = "";
    }
    return $static_url . $url;
}
 

I set responsive sizes on my config file :

/**
 * Responsive Image Options
 */
$responsiveSizes = array(
    'small' => '480',
    'medium' => '768',
    'large' => '960',
    'xlarge' => '1220'
);

$config->resSmall = "(max-width: " . ($responsiveSizes['small']-1) . "px)";
$config->resMedium = "(max-width: " . ($responsiveSizes['medium']-1) . "px)";
$config->resLarge = "(max-width: " . ($responsiveSizes['large']-1) . "px)";
$config->resXlarge = "(min-width: {$responsiveSizes['xlarge']}px)";
And I created a file (including this file inside my init.php file) that file have responsive image sizes like :
/**
 * Template --Villa List--
 */
$respImgOptions['villa']['list'] = array(
    'picture' => array(
        'source' => array(
            $config->resSmall => array(
                'srcset' => 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
                'data-srcset' => array(
                    'method' => array(
                        'type' => 'size',
                        'width' => 404,
                        'height' => 270
                    )
                )
            ),
            $config->resMedium => array(
                'srcset' => 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
                'data-srcset' => array(
                    'method' => array(
                        'type' => 'size',
                        'width' => 692,
                        'height' => 462
                    )
                )
            ),
            $config->resLarge => array(
                'srcset' => 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
                'data-srcset' => array(
                    'method' => array(
                        'type' => 'size',
                        'width' => 427,
                        'height' => 285
                    )
                )
            )
        ),
        'img' => array(
            'src' => 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
            'attributes' => array(
                'class' => 'lazyload uk-width-1-1'
            ),
            'data-srcset' => array(
                'method' => array(
                    'type' => 'size',
                    'width' => 630,
                    'height' => 421
                )
            )
        )
    )
);
And after all done calling images from page like :
// on here you need to send single PageImage !
$img = image($page->image->first(), $config->respImgOptions['villa']['list']);
Like this usage if you have https://github.com/aFarkas/lazysizes and https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/respimg every thing will work well ! Edited by ukyo
  • Like 10
Link to comment
Share on other sites

@ukyo: this looks very well. I have bookmarked this post because I allready use lazysizes and respimg in two projects, but I think I haven't it that well organized as you have. Next possibilty I have time for it, I will compare mine with yours and update / reorganize mine where needed. Many thanks for sharing!

Link to comment
Share on other sites

sorry :) also i updated my first reply

/**
 * Generate Attributes Array or String
 *
 * @param $item
 * @return string
 */
function buildAttrs($item) {
    $attributes = "";
    // echo "<pre>Key : " . print_r($item, true) . "</pre>";
    if(array_key_exists('attributes', $item) && is_array($item['attributes'])) {
        foreach($item['attributes'] as $key => $attr) {
            $attributes .= ' ' . $key . '="' . $attr . '"';
        }
    }
    return $attributes;
}

/**
 *
 * @param $image
 * @param $key
 * @param $options
 * @return string
 */
function buildSrcAndSrcset($image, $key, $options) {
    $return = '';
    // echo "<pre>Key : {$key}, " . print_r($options, true) . "</pre>";
    if(!empty($options[$key]) && !empty($options[$key]['sets']) && is_array($options[$key]['sets'])) {
        $x=1;
        $countSets = count($options[$key]['sets']);
        $sets = "";
        foreach($options[$key]['sets'] as $k => $rules) {
            $y=$x++;
            $separator = ($y != $countSets) ? ", " : "";
            if(!is_array($rules) && $rules == 'original') {
                $static_url = static_url($image->url);
                $sets .= "{$static_url} {$key}w{$separator}";
            } elseif(isset($rules['width']) || isset($rules['height'])) {
                $size = imageResize($image, $rules);
                if(!is_null($size)) {
                    $sets .= "{$size['url']} {$size['width']}w{$separator}";
                }
            }
        }
        if($sets != "") $return = " {$key}='{$sets}'";
    } elseif(!empty($options[$key]) && !empty($options[$key]['method']) && is_array($options[$key]['method'])) {
        $img = imageResize($image, $options[$key]['method']);
        if(!is_null($img)) $return = " {$key}='{$img['url']}'";
    } elseif(!empty($options[$key]) && is_string($options[$key])) {
        $return = " {$key}='{$options[$key]}'";
    }
    return $return;
} 
  • Like 2
Link to comment
Share on other sites

@ukyo: this looks very well. I have bookmarked this post because I allready use lazysizes and respimg in two projects, but I think I haven't it that well organized as you have. Next possibilty I have time for it, I will compare mine with yours and update / reorganize mine where needed. Many thanks for sharing!

Thanks @horst, if you see my mistakes and no need things or any useful things let me know please :)

  • Like 1
Link to comment
Share on other sites

It for uikit lightbox component, resizing image and adding lightbox link automatically with overlay effect. If you don't use uikit you can remove these codes from function or you can customize them for your needs.

I dind't modify my code, directly shared them with community and you can take it as example and you can modify codes or you can create a function as your needs.

// Without lightbox
$img = image($page->image->first(), $config->respImgOptions['villa']['list']);

// With lightbox, its enought to send "true" or "overlay" class, after set responsive image settings
$img = image($page->image->first(), $config->respImgOptions['villa']['list'], true);

Lightbox example output :

<figure class='uk-overlay uk-overlay-hover'>
     <picture>
          <!--[if IE 9]>
               <video style='display: none;'>
          <![endif]-->
          <source srcset='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-003.344x212.jpg' media='(max-width: 479px)' />
          <source srcset='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-003.309x190.jpg' media='(max-width: 767px)' />
          <source srcset='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-003.265x164.jpg' media='(max-width: 959px)' />
          <!--[if IE 9]>
               </video>
          <![endif]-->
          <img src='data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' data-srcset='/site/assets/files/1058/terra-nova-003.290x180.jpg' alt='terra-nova-003' class="lazyload uk-responsive-width uk-overlay-spin" />
     </picture>
     <div class='uk-overlay-panel uk-overlay-background uk-overlay-fade'></div>
     <div class='uk-overlay-panel uk-overlay-icon uk-overlay-fade'></div>
     <a class='uk-position-cover' href='/site/assets/files/1058/terra-nova-003.jpg' title='Terra Nova' data-uk-lightbox="{group:'terra-nova'}">
          <span class='uk-hidden'>Terra Nova</span>
     </a>
</figure>
  • Like 3
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...