marionnewlevant / picture
Generate responsive <picture> and <img> elements based on configuration.
Installs: 12 869
Dependents: 0
Suggesters: 0
Security: 0
Stars: 12
Watchers: 3
Forks: 1
Type:craft-plugin
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/picture
from 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-sizes
anddata-src
attributes instead ofsrcset
,sizes
, andsrc
. Will add aclass
attribute with valueclass="lazyload"
, or addlazyload
to any existingclass
attribute. Values are:- false - not lazyloaded (the default)
- true - lazyloaded, no fallback
src
attribute - string - lazyloaded, value will be the
src
attribute 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) }}
asset
is an Asset element - a regular Craft asset ORasset
is 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.style
is the name of the image style. It is optional, and if missing, the default style will be used.options
is an optional hash of options.transform
- additional Craft transform parameterslazysizes
- overrides anylazysizes
value 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
src
attribute
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