marionnewlevant / picture
Generate responsive <picture> and <img> elements based on configuration.
Installs: 13 570
Dependents: 0
Suggesters: 0
Security: 0
Stars: 12
Watchers: 2
Forks: 1
Type:craft-plugin
pkg:composer/marionnewlevant/picture
Requires
- craftcms/cms: ^5.0
Requires (Dev)
- craftcms/phpstan: dev-main
README
Generate <picture> elements.
See v1 branch for the Craft 2 version, see v2 branch for Craft 3 and 4 versions
Installation
- Install with Composer via
composer require marionnewlevant/picturefrom your project directory - Install plugin in the Craft Control Panel under Settings > Plugins
or
- Install via the Plugin Store
picture Overview
Creates the transforms for an asset, and generates a <picture> or <img> element, or simply returns the transformed image url. Most of the work is in writing the configuration that describes the different image styles.
The plugin provides four variables: craft.picture.element generates
<picture> and <img> elements, which contain multiple urls for
transformations of a single image. craft.picture.url generates a single url,
useful when the image is a background-image. Additionally,
craft.picture.imageStyles returns an array of the names of the defined image
styles, and craft.picture.urlTransforms returns an array of the names of the
defined urlTransforms.
Configuring picture
You need a config file, craft/config/picture.php. That file defines the
different image styles for your project.
Here is a sample configuration file:
<?php
return [
// array of image styles. The name of the style will be the key,
// and the configuration of the style will be the value.
// These styles are used to generate picture and img elements
// with craft.picture.element
'imageStyles' => [
// this is the 'thumb' style. It will generate an img like:
// <img
// srcset="transform75pxUrl 75w, transform150pxUrl 150w"
// sizes="75px"
// src="transform75pxUrl"
// />
'thumb' => [
// since the 'thumb' style has no sources, it will generate
// an img element, not a picture element
'img' => [
// optional aspect ratio, width / height. Will use the
// native aspect ratio of the asset if not specified
// This will be square
'aspectRatio' => 1,
// the 'sizes' attribute of the element
'sizes' => '75px',
// pixel widths for the generated images. The first
// element in the array will be the width of the default
// src
'widths' => [75, 150]
]
],
// the 'art' style will generate a picture element with two
// nested source elements and a nested img element
'art' => [
// since there is a sources array, this will generate a
// picture element. sources is an array of source
// configurations
'sources' => [
// on narrow screens, we are going to have a 4x3
// small image. This source element will look like:
// <source
// media="(max-sidth: 600px)"
// srcset="t100pxUrl 100w, t200pxUrl 200w"
// sizes="100px"
// />
[
// optional 'media' attribute for this source
// (the 'media' attribute is required on all but
// the last source)
'media' => '(max-width: 600px)',
// optional aspect ratio
'aspectRatio' => 4/3,
'sizes' => '100px',
'widths' => [100, 200],
],
// on other screens we are going to use the native aspect
// ratio. The image will be 1/2 the screen width up to
// 1000px, and 500px after that. The source element:
// <source
// srcset="t500pxUrl 500w, t1000pxUrl 1000w"
// sizes="(max-width: 1000px) 50vw, 500px"
// />
[
// sizes is just a string, but we can use php to make it
// easier to construct
'sizes' => implode(', ', [
'(max-width: 1000px) 50vw',
'500px'
]),
'widths' => [500, 1000]
]
],
// the img element is required. We just need a fallback src,
// this will be 500px wide (no srcset when there is only one
// width).
// <img src="t500pxUrl" />
'img' => [
'widths' => [500]
],
// transform is optional, and specifies parameters for
// the Craft transforms for the style
'transform' => [
'format' => 'jpg'
]
],
// the 'lazyLoaded' style for elements that use lazysizes for lazyloading.
// See also lazysizesTrigger config value
// <img
// class="lazyload"
// data-srcset="transform500pxUrl 500w, transform1000pxUrl 1000w"
// data-sizes="25vw"
// data-src="transform500pxUrl"
// />
'lazyLoaded' => [
// optional lazysizes. Can be boolean (true = lazysizes, false = no lazysizes) or
// string (uses string value for src attribute value)
'lazysizes' => true,
'img' => [
'sizes' => '25vw',
'widths' => [500, 1000]
]
],
// the default style will be used when none is specified.
'default' => [
'img' => [
'widths' => [500],
]
]
],
// the urlTransforms are used to specify individual urls for
// craft.picture.url
'urlTransforms' => [
// the 'hero' transform - these image will be 7:3, and 1000px wide
'hero' => [
'aspectRatio' => 7/3,
'width' => 1000
]
],
// lazysizesTrigger is an optional override for elements loaded with
// lazysizes. It changes the class value from 'lazyload'
'lazysizesTrigger' => 'js-lazyload'
];
To recap, the config file specifies the imageStyles for generating
<picture> and <img> elements, urlTransforms for
generating single image urls, and lazysizesTrigger if you want to
use lazyload with a different triggering classname.
Each individual element in imageStyles has an optional array of sources and
an img. The img can have:
- sizes: optional sizes attribute
- widths: array of pixel widths. Must have at least one
- aspectRatio: optional aspect ratio, width / height. Values < 1 for portrait, values > 1 for landscape.
- transform: additional craft transform parameters (width is set by the plugin, and so is height if the aspect ratio is specified)
Each source can have all of those, plus
- media: optional media attribute
Additionally, the style as a whole can have:
- transform: optional Craft transform parameters
- lazysizes: optional value which determines whether the element will be
lazyloaded with lazysizes.
Will generate
data-srcset,data-sizesanddata-srcattributes instead ofsrcset,sizes, andsrc. Will add aclassattribute with valueclass="lazyload", or addlazyloadto any existingclassattribute. Values are:- false - not lazyloaded (the default)
- true - lazyloaded, no fallback
srcattribute - string - lazyloaded, value will be the
srcattribute value.
Each individual element in urlTransforms can have:
- width: single pixel width. This is required.
- aspectRatio: optional aspect ratio
- transform: additional craft transform parameters
Whenever possible, Picture avoids generating transforms that will up-scale the original image.
Using craft.picture.element
Use craft.picture.element in your templates like this:
{{ craft.picture.element(asset, style, options) }}
assetis an Asset element - a regular Craft asset ORassetis an array of Craft assets, in which case the first asset is used for the first source, the second asset for the second source, etc., repeating the cycle of assets if there are more sources than assets.styleis the name of the image style. It is optional, and if missing, the default style will be used.optionsis an optional hash of options.transform- additional Craft transform parameterslazysizes- overrides anylazysizesvalue on the image style in the config file.- anything else will be attributes on the <img> element.
Example for a thumb style image with alt text of thumbAlt, and the crop position bottom-right and quality of 80:
{{ craft.picture.element(
entry.image.one,
'thumb',
{
alt: 'thumbAlt',
transform: {
position: 'bottom-right',
quality: 80
}
}
) }}
Example for an art style image with different images for the different sizes:
{{ craft.picture.element([
entry.mobileImage.one, entry.desktopImage.one
], 'art') }}
using craft.picture.url
For a hero image used as a background image:
<div
class="hero"
style="background-image: url({{ craft.picture.url(entry.hero.one, 'hero') }})"
></div>
integration with ImageOptimize
The ImageOptimize plugin will automatically run image optimizers such as jpegoptim on your transformed images. It works well with this plugin, and no additional changes are required.
integration with lazysizes
A lazysizes value can be set in either the style configuration in
config/picture.php or in the options passed to craft.picture.element.
By specifying lazysizes in the options, you can:
- turn off lazyloading for images that are "above the fold"
- use ImageOptimize placeholder images
for the
srcattribute
Additionally, if you want to use a different class than lazyload for the
lazyloaded images, you can change that class with the lazysizesTrigger
config value.
Tips
I use a twig macro which handles missing images before calling craft.picture.element.
I define a style preparse which includes all the different transforms, and generate that style in a Preparse field when the asset is saved to pre-build the transforms.
Brought to you by Marion Newlevant. Icon insides by Setyo Ari Wibowo