Skip to content
Snippets Groups Projects
Commit 8c06d87f authored by Benni Mack's avatar Benni Mack
Browse files

[FEATURE] Add native browser lazy loading for images

This change adds the browser-native lazy loading option "loading"
HTML attribute for images.

See https://addyosmani.com/blog/lazy-loading/ for more details.

Resolves: #90426
Releases: master
Change-Id: I5c457ed5b72ef81622e5135f182d7b10ededd4df
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/63317


Tested-by: default avatarGeorg Ringer <georg.ringer@gmail.com>
Tested-by: default avatarChristian Eßl <indy.essl@gmail.com>
Tested-by: default avatarTYPO3com <noreply@typo3.com>
Tested-by: default avatarBenni Mack <benni@typo3.org>
Reviewed-by: default avatarGeorg Ringer <georg.ringer@gmail.com>
Reviewed-by: default avatarChristian Eßl <indy.essl@gmail.com>
Reviewed-by: default avatarBenni Mack <benni@typo3.org>
parent e89a057d
Branches
Tags
No related merge requests found
.. include:: ../../Includes.txt
========================================================
Feature: #90426 - Browser-native lazy loading for images
========================================================
See :issue:`90426`
Description
===========
TYPO3 now supports the browser-native `loading` HTML attribute in :html:`<img>` tags.
It is set to "lazy" by default for all images within Content Elements rendered
with Fluid Styled Content. Supported browsers then choose to load these
images at a later point when the image is within the browsers' Viewport.
The configuration option is available via TypoScript constants and
can be easily adjusted via the TypoScript Constant Editor in the Template module.
Please note that not all browsers support this option yet, but adding
this property will just be skipped for unsupported browsers.
Impact
======
TYPO3 Frontend now renders images in content elements with the "loading=lazy"
attribute by default when using TYPO3's templates from Fluid Styled Content.
Using the TypoScript constant `styles.content.image.lazyLoading`,
the behavior can be modified generally to be either set to `eager`,
`auto` or to an empty value, removing the property directly.
The Fluid ImageViewHelper has the possibility to set this option
via `<f:image src="{fileObject}" treatIdAsReference="true" loading="lazy">`
to hint the browser on how the prioritization of image loading should be used.
.. index:: Frontend, ext:fluid_styled_content
\ No newline at end of file
...@@ -114,6 +114,7 @@ class ImageViewHelper extends AbstractTagBasedViewHelper ...@@ -114,6 +114,7 @@ class ImageViewHelper extends AbstractTagBasedViewHelper
$this->registerTagAttribute('ismap', 'string', 'Specifies an image as a server-side image-map. Rarely used. Look at usemap instead', false); $this->registerTagAttribute('ismap', 'string', 'Specifies an image as a server-side image-map. Rarely used. Look at usemap instead', false);
$this->registerTagAttribute('longdesc', 'string', 'Specifies the URL to a document that contains a long description of an image', false); $this->registerTagAttribute('longdesc', 'string', 'Specifies the URL to a document that contains a long description of an image', false);
$this->registerTagAttribute('usemap', 'string', 'Specifies an image as a client-side image-map', false); $this->registerTagAttribute('usemap', 'string', 'Specifies an image as a client-side image-map', false);
$this->registerTagAttribute('loading', 'string', 'Native lazy-loading for images property. Can be "lazy", "eager" or "auto"', false);
$this->registerArgument('src', 'string', 'a path to a file, a combined FAL identifier or an uid (int). If $treatIdAsReference is set, the integer is considered the uid of the sys_file_reference record. If you already got a FAL object, consider using the $image parameter instead', false, ''); $this->registerArgument('src', 'string', 'a path to a file, a combined FAL identifier or an uid (int). If $treatIdAsReference is set, the integer is considered the uid of the sys_file_reference record. If you already got a FAL object, consider using the $image parameter instead', false, '');
$this->registerArgument('treatIdAsReference', 'bool', 'given src argument is a sys_file_reference record', false, false); $this->registerArgument('treatIdAsReference', 'bool', 'given src argument is a sys_file_reference record', false, false);
......
...@@ -86,6 +86,7 @@ class MediaViewHelper extends AbstractTagBasedViewHelper ...@@ -86,6 +86,7 @@ class MediaViewHelper extends AbstractTagBasedViewHelper
$this->registerArgument('height', 'string', 'This can be a numeric value representing the fixed height in pixels. But you can also perform simple calculations by adding "m" or "c" to the value. See imgResource.width for possible options.'); $this->registerArgument('height', 'string', 'This can be a numeric value representing the fixed height in pixels. But you can also perform simple calculations by adding "m" or "c" to the value. See imgResource.width for possible options.');
$this->registerArgument('cropVariant', 'string', 'select a cropping variant, in case multiple croppings have been specified or stored in FileReference', false, 'default'); $this->registerArgument('cropVariant', 'string', 'select a cropping variant, in case multiple croppings have been specified or stored in FileReference', false, 'default');
$this->registerArgument('fileExtension', 'string', 'Custom file extension to use for images'); $this->registerArgument('fileExtension', 'string', 'Custom file extension to use for images');
$this->registerArgument('loading', 'string', 'Native lazy-loading for images property. Can be "lazy", "eager" or "auto". Used on image files only.');
} }
/** /**
...@@ -157,6 +158,9 @@ class MediaViewHelper extends AbstractTagBasedViewHelper ...@@ -157,6 +158,9 @@ class MediaViewHelper extends AbstractTagBasedViewHelper
$this->tag->addAttribute('src', $imageUri); $this->tag->addAttribute('src', $imageUri);
$this->tag->addAttribute('width', $processedImage->getProperty('width')); $this->tag->addAttribute('width', $processedImage->getProperty('width'));
$this->tag->addAttribute('height', $processedImage->getProperty('height')); $this->tag->addAttribute('height', $processedImage->getProperty('height'));
if (in_array($this->arguments['loading'] ?? '', ['lazy', 'eager', 'auto'], true)) {
$this->tag->addAttribute('loading', $this->arguments['loading']);
}
$alt = $image->getProperty('alternative'); $alt = $image->getProperty('alternative');
$title = $image->getProperty('title'); $title = $image->getProperty('title');
......
...@@ -18,6 +18,7 @@ lib.contentElement { ...@@ -18,6 +18,7 @@ lib.contentElement {
settings { settings {
defaultHeaderType = {$styles.content.defaultHeaderType} defaultHeaderType = {$styles.content.defaultHeaderType}
media { media {
lazyLoading = {$styles.content.image.lazyLoading}
popup { popup {
bodyTag = <body style="margin:0; background:#fff;"> bodyTag = <body style="margin:0; background:#fff;">
wrap = <a href="javascript:close();"> | </a> wrap = <a href="javascript:close();"> | </a>
......
...@@ -17,6 +17,9 @@ styles.content { ...@@ -17,6 +17,9 @@ styles.content {
# cat=content/parseFunc/a0; type=string; label=List of allowed HTML tags when rendering RTE content # cat=content/parseFunc/a0; type=string; label=List of allowed HTML tags when rendering RTE content
allowTags = a, abbr, acronym, address, article, aside, b, bdo, big, blockquote, br, caption, center, cite, code, col, colgroup, dd, del, dfn, dl, div, dt, em, font, footer, header, h1, h2, h3, h4, h5, h6, hr, i, img, ins, kbd, label, li, link, meta, nav, ol, p, pre, q, s, samp, sdfield, section, small, span, strike, strong, style, sub, sup, table, thead, tbody, tfoot, td, th, tr, title, tt, u, ul, var allowTags = a, abbr, acronym, address, article, aside, b, bdo, big, blockquote, br, caption, center, cite, code, col, colgroup, dd, del, dfn, dl, div, dt, em, font, footer, header, h1, h2, h3, h4, h5, h6, hr, i, img, ins, kbd, label, li, link, meta, nav, ol, p, pre, q, s, samp, sdfield, section, small, span, strike, strong, style, sub, sup, table, thead, tbody, tfoot, td, th, tr, title, tt, u, ul, var
# cat=content/cImage/a0; type=options[lazy,eager,auto,]; label=Default settings for browser-native image lazy loading: Can be "lazy" (browsers could choose to load images later), "eager" (load images right away) or "auto" (browser will determine whether the image should be lazy loaded or not)
image.lazyLoading = lazy
textmedia { textmedia {
# cat=content/cTextmedia/b1; type=int+; label= Max Image/Media Width: This indicates that maximum number of pixels (width) a block of media elements inserted as content is allowed to consume # cat=content/cTextmedia/b1; type=int+; label= Max Image/Media Width: This indicates that maximum number of pixels (width) a block of media elements inserted as content is allowed to consume
maxW = 600 maxW = 600
......
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true"> <html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:media class="image-embed-item" file="{file}" width="{dimensions.width}" height="{dimensions.height}" alt="{file.alternative}" title="{file.title}" /> <f:media class="image-embed-item" file="{file}" width="{dimensions.width}" height="{dimensions.height}" alt="{file.alternative}" title="{file.title}" loading="{settings.media.lazyLoading}" />
</html> </html>
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment