umanit / twig-image-extension
An extension to facilitate the integration of responsive images' markup in Twig templates.
Installs: 28 600
Dependents: 0
Suggesters: 0
Security: 0
Stars: 10
Watchers: 7
Forks: 5
Open Issues: 2
Requires
- php: ^7.4|^8.0
- ext-mbstring: *
- liip/imagine-bundle: ^2.3
- twig/twig: ^2.12|^3.0
README
This Twig extension facilitates the integration of responsive images markup in Twig templates.
It uses LiipImagineBundle and its filters to generate HTML markup with all you need to handle responsive images.
It also provides a JavaScript module to automatically instantiate yall.js on rendered images.
Installation
Use the package manager composer to install the extension.
composer require umanit/twig-image-extension
Load the bundle into your Symfony project.
<?php # config/bundles.php return [ // ... Umanit\TwigImage\UmanitTwigImageBundle::class => ['all' => true], ];
(Optional) Install bundle assets if you want to use the javascript module for yall.js:
bin/console assets:install --symlink
Configuration
umanit_twig_image: allow_fallback: false use_liip_default_image: false class_selector: lazy placeholder_class_selector: lazy-placeholder blur_class_selector: lazy-blur
Some functions render HTML markup with the ability to use lazy loading on images. It's possible to customize the classes
used with the 3 options class_selector
, placeholder_class_selector
and blur_class_selector
.
Fallback images
By default, if the image path given in functions calls is null, empty or points to a missing file on the server, an exception is thrown. You have two options to avoid this:
- setting
twig_image_extension.allow_fallback
totrue
- setting
twig_image_extension.use_liip_default_image
totrue
twig_image_extension.allow_fallback
If the path given points to a missing file, a default image will be rendered instead. The default images are available in four sizes:
- small: 320px wide
- medium: 640 wide
- large: 1280px wide
- extra large: 2560px wide (for Retina screens mostly)
If a default image needs to be rendered, the size will be guessed using the given Liip filter:
- a filter ending with
2x
will give you an extra large default image - a filter ending with
xl
orxxl
will give you a large default image - a filter ending with
xs
orxxs
will give you a small default image - any other filter name will default to the medium size
twig_image_extension.use_liip_default_image
This parameter will only be used as a backup if allow_fallback
is set to false
and requires you to use the default
image mecanism of Liip (
see Liip configuration)
Usage
The following Twig functions are available in your templates.
- umanit_image_figure_lazy_load
- umanit_image_figure
- umanit_image_picture_lazy_load
- umanit_image_picture
- umanit_image_img
- umanit_image_srcset
- (Optional) Javascript module to instantiate yall.js
- (Optional) Import CSS files for blur effect on yall.js lazy images
When a LiipImagine filter is used, the extension will read its configuration and automatically guess the right width or height to apply in the markup. If it's not possible, the extension will try to get the original image dimensions instead. In both case, the result is saved in cache to avoid multiple process for the same image.
When the used function is for lazy load, lazy
and lazy-placeholder
classes are used but can be customized as
explained in the Configuration part.
width
and height
attributes are added in the <img />
tag, based on the size calculated by the src
filter
(except for downscale
and upscale
filters, which fallback to the original image size). By doing this, sudden layout
shifts are avoided for a better user experience.
To use htmlAlt
, the css file umanit-alt-text.css
must be loaded. It hides the div
used to display the html alt
content.
umanit_image_figure_lazy_load
Generates a figure
tag with an img
inside and his noscript
version. The lazy
,
lazy-placeholder
and lazy-blur
classes are add to facilitate the integration with
yall.js for example.
Parameters
Example
Click to show
Without htmlAlt
umanit_image_figure_lazy_load( image.path, 'small_thumbnail', 'tiny_thumbnail', ['thumbnail', 'large_thumbnail'], 'image alt', 'img img--cover img--zoom', '(min-width: 768px) 33.3vw, 100vw', 'class-figure', 'Figcaption text', 'class-figcaption', 'high', 'data-container="a"', 'data-image="b" data-test' )
HTML generated:
<figure class="class-figure" data-container="a"> <img alt="image alt" class="lazy lazy-placeholder lazy-blur img img--cover img--zoom" src="https://domain.tld/media/cache/tiny_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" data-src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" sizes="(min-width: 768px) 33.3vw, 100vw" data-srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" importance="high" data-image="b" data-test > <noscript> <img class="img img--cover img--zoom" alt="home" src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" sizes="(min-width: 768px) 33.3vw, 100vw" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" importance="high" data-image="b" data-test > </noscript> <figcaption class="class-figcaption">Figcaption text</figcaption> </figure>
With htmlAlt
umanit_image_figure_lazy_load( image.path, 'small_thumbnail', 'tiny_thumbnail', ['thumbnail', 'large_thumbnail'], 'image alt', 'img img--cover img--zoom', '(min-width: 768px) 33.3vw, 100vw', 'class-figure', 'Figcaption text', 'class-figcaption', '<p>Html to describe content</p>' )
HTML generated
<figure class="class-figure"> <img alt="" aria-describedby="1234567890" class="lazy lazy-placeholder lazy-blur img img--cover img--zoom" src="https://domain.tld/media/cache/tiny_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" data-src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" sizes="(min-width: 768px) 33.3vw, 100vw" data-srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" > <noscript> <img class="img img--cover img--zoom" alt="" aria-describedby="1234567890" src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" sizes="(min-width: 768px) 33.3vw, 100vw" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" > </noscript> <figcaption class="class-figcaption">Figcaption text</figcaption> </figure> <div id="1234567890"><p>Html to describe content</p></div>
The id used for aria-describedby
is a random dynamically generated value.
umanit_image_figure
Generates a figure
tag with an img
inside.
Parameters
Example
Click to show
Without htmlAlt
umanit_image_figure( image.path, 'small_thumbnail', ['thumbnail', 'large_thumbnail'], 'image alt', 'img img--cover img--zoom', '(min-width: 768px) 33.3vw, 100vw', 'class-figure', 'Figcaption text', 'class-figcaption', 'low', 'data-container="a"', 'data-image="b" data-test' )
HTML generated:
<figure class="class-figure" data-container="a"> <img alt="image alt" class="img img--cover img--zoom" src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" sizes="(min-width: 768px) 33.3vw, 100vw" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" importance="low" importance="high" data-image="b" data-test > <figcaption class="class-figcaption">Figcaption text</figcaption> </figure>
With htmlAlt
umanit_image_figure( image.path, 'small_thumbnail', ['thumbnail', 'large_thumbnail'], 'image alt', 'img img--cover img--zoom', '(min-width: 768px) 33.3vw, 100vw', 'class-figure', 'Figcaption text', 'class-figcaption', '<p>Html to describe content</p>' )
HTML generated
<figure class="class-figure"> <img alt="" aria-describedby="1234567890" class="lazy lazy-placeholder lazy-blur img img--cover img--zoom" src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" sizes="(min-width: 768px) 33.3vw, 100vw" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" > <figcaption class="class-figcaption">Figcaption text</figcaption> </figure> <div id="1234567890"><p>Html to describe content</p></div>
The id used for aria-describedby
is a random dynamically generated value.
umanit_image_picture_lazy_load
Generates a picture
tag with an img
inside and X source
. Each source
can have a media
and sizes
attribute if
needed. The lazy
and lazy-placeholder
classes are add to facilitate the integration with
yall.js for example.
Parameters
Example
Click to show
Without htmlAlt
umanit_image_picture_lazy_load( image.path, 'small_thumbnail', 'tiny_thumbnail', ['thumbnail', 'large_thumbnail'], { (image.path): { 'media': '(min-width: 768px)', 'sizes': '(min-width: 1400px) 25vw, 50vw', 'filters': ['thumbnail', 'large_thumbnail'] }, (image2.path): ['thumbnail', 'large_thumbnail'] }, 'alt img', 'img img-fluid', 'class-picture', 'high', 'data-picture data-markup="c"', 'data-image="d" )
HTML generated
<picture class="class-picture" data-picture data-markup="c"> <source media="(min-width: 768px)" sizes="(min-width: 1400px) 25vw, 50vw" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400"> <source srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="300" height="200"> <img class="img img-fluid" alt="alt img" src="https://domain.tld/media/cache/tiny_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" data-src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" data-srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" importance="high" data-image="d" > </picture>
With htmlAlt
umanit_image_picture_lazy_load( image.path, 'small_thumbnail', 'tiny_thumbnail', ['thumbnail', 'large_thumbnail'], { (image.path): { 'media': '(min-width: 768px)', 'sizes': '(min-width: 1400px) 25vw, 50vw', 'filters': ['thumbnail', 'large_thumbnail'] }, (image2.path): ['thumbnail', 'large_thumbnail'] }, 'alt img', 'img img-fluid', 'class-picture', '<p>Html to describe content</p>' )
HTML generated
<picture class="class-picture"> <source media="(min-width: 768px)" sizes="(min-width: 1400px) 25vw, 50vw" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400"> <source srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg2 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg2 2880w" width="300" height="200"> <img class="img img-fluid" alt="" aria-describedby="1234567890" src="https://domain.tld/media/cache/tiny_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" data-src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" data-srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" > </picture> <div id="1234567890"><p>Html to describe content</p></div>
The id used for aria-describedby
is a random dynamically generated value.
umanit_image_picture
Generates a picture
tag with an img
inside and X source
. Each source
can have a media
and sizes
attribute if
needed.
Parameters
Example
Click to show
Without htmlAlt
umanit_image_picture( image.path, 'small_thumbnail', ['thumbnail', 'large_thumbnail'], { (image.path): { 'media': '(min-width: 768px)', 'sizes': '(min-width: 1400px) 25vw, 50vw', 'filters': ['thumbnail', 'large_thumbnail'] }, (image2.path): ['thumbnail', 'large_thumbnail'] }, 'alt img', 'img img-fluid', 'class-picture', 'low', 'data-picture data-markup="c"', 'data-image="d" )
HTML generated
<picture class="class-picture" data-picture data-markup="c"> <source media="(min-width: 768px)" sizes="(min-width: 1400px) 25vw, 50vw" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400"> <source srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="300" height="200"> <img class="img img-fluid" alt="alt img" src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" importance="low" data-image="d" > </picture>
With htmlAlt
umanit_image_picture( image.path, 'small_thumbnail', ['thumbnail', 'large_thumbnail'], { (image.path): { 'media': '(min-width: 768px)', 'sizes': '(min-width: 1400px) 25vw, 50vw', 'filters': ['thumbnail', 'large_thumbnail'] }, (image2.path): ['thumbnail', 'large_thumbnail'] }, 'alt img', 'img img-fluid', 'class-picture', '<p>Html to describe content</p>' )
HTML generated
<picture class="class-picture"> <source media="(min-width: 768px)" sizes="(min-width: 1400px) 25vw, 50vw" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400"> <source srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg2 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg2 2880w" width="300" height="200"> <img class="img img-fluid" alt="" aria-describedby="1234567890" src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" > </picture> <div id="1234567890"><p>Html to describe content</p></div>
umanit_image_img
Generates an img
tag.
Parameters
Example
Click to show
umanit_image_img( image.path, 'small_thumbnail', ['thumbnail', 'large_thumbnail'], 'image alt', 'img img--cover img--zoom', '(min-width: 768px) 33.3vw, 100vw', 'low', 'data-image="b" data-test' )
HTML generated:
<img alt="image alt" class="img img--cover img--zoom" src="https://domain.tld/media/cache/resolve/small_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg" sizes="(min-width: 768px) 33.3vw, 100vw" srcset="https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w" width="600" height="400" importance="low" data-image="b" data-test >
umanit_image_srcset
Generates the content of a srcset
attribute if you wan to use it in your own markup.
Parameters
Example
Click to show
umanit_image_srcset(image.path, ['thumbnail', 'large_thumbnail'])
HTML generated
https://domain.tld/media/cache/resolve/thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 260w, https://domain.tld/media/cache/resolve/large_thumbnail/99/30/c1f268bbf1487fb88734f2ba826b.jpeg 2880w
(Optional) Javascript module to instantiate yall.js
If you want to use yall.js to manage the lazy load of your images, the bundle provides a javascript module that can be called in your application.
yall.js needs to be installed manually: yarn add yall-js
Then you need to import the module and instantiate it by passing the yall library. An optional argument
loadEventCallback
is available if you want to add more customization. It will be called in the load
event of
yall.js.
import yall from 'yall-js'; import umanitImageLazyLoad from '../../public/bundles/umanittwigimage/js/umanit-image-lazy-loading'; umanitImageLazyLoad(yall);
(Optional) Import CSS files for blur effect on yall.js lazy images
You can import the CSS file for adding a blur effect on lazy images.
<link rel="stylesheet" href="{{ asset('css/umanit-image-lazy-loading.css', 'twig_image_bundle') }}">
Example in webpack
import '../../public/bundles/umanittwigimage/css/umanit-image-lazy-loading.css';
⚠ For a best usage for the users without javascript you should add a no-js
class on the html
element
<html class="no-js">
Finally, add this one line <script>
before any <link>
or <style>
elements in the document <head>
<!-- Remove the no-js class on the <html> element if JavaScript is on --> <script>document.documentElement.classList.remove("no-js");</script>
See https://github.com/malchata/yall.js/#what-about-users-without-javascript for more details.
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.