-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lazy load background images added via inline style attributes #1708
Changes from 5 commits
6191153
41fe3c3
e29cb55
5b8b109
3a50808
ce351c2
66e9404
7943980
a21dec4
12a268d
6608a4e
c9eb29f
e466d58
d02fc27
d9b3b66
2b75add
4d70ad0
c1491ad
8ca87d3
4cd8a5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,30 @@ | |
*/ | ||
final class Image_Prioritizer_Background_Image_Styled_Tag_Visitor extends Image_Prioritizer_Tag_Visitor { | ||
|
||
/** | ||
* Class name used to indicate a background image which is lazy-loaded. | ||
* | ||
* @since n.e.x.t | ||
* @var string | ||
*/ | ||
const LAZY_BG_IMAGE_CLASS_NAME = 'od-lazy-bg-image'; | ||
|
||
/** | ||
* Whether the lazy-loading styles have been added to the head. | ||
* | ||
* @since n.e.x.t | ||
* @var bool | ||
*/ | ||
private $added_lazy_styles = false; | ||
|
||
/** | ||
* Whether the lazy-loading script was added to the body. | ||
* | ||
* @since n.e.x.t | ||
* @var bool | ||
*/ | ||
private $added_lazy_script = false; | ||
|
||
/** | ||
* Visits a tag. | ||
* | ||
|
@@ -71,6 +95,57 @@ public function __invoke( OD_Tag_Visitor_Context $context ): bool { | |
); | ||
} | ||
|
||
$this->lazy_load_bg_images( $context ); | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Optimizes an element with a background image based on whether it is displayed in any initial viewport. | ||
* | ||
* @since n.e.x.t | ||
* | ||
* @param OD_Tag_Visitor_Context $context Tag visitor context, with the cursor currently at block with a background image. | ||
*/ | ||
private function lazy_load_bg_images( OD_Tag_Visitor_Context $context ): void { | ||
$processor = $context->processor; | ||
|
||
// Lazy-loading can only be done once there are URL Metrics collected for both mobile and desktop. | ||
if ( | ||
$context->url_metric_group_collection->get_first_group()->count() === 0 | ||
|| | ||
$context->url_metric_group_collection->get_last_group()->count() === 0 | ||
) { | ||
return; | ||
} | ||
|
||
$xpath = $processor->get_xpath(); | ||
|
||
$in_any_initial_viewport = $context->url_metric_group_collection->is_element_positioned_in_any_initial_viewport( $xpath ); | ||
|
||
// If the element is in the initial viewport, do not lazy load its background image. | ||
if ( true === $in_any_initial_viewport || null === $in_any_initial_viewport ) { | ||
return; | ||
} | ||
|
||
$processor->add_class( self::LAZY_BG_IMAGE_CLASS_NAME ); | ||
|
||
if ( ! $this->added_lazy_styles ) { | ||
$processor->append_head_html( | ||
'<style> | ||
@media (scripting: enabled) { | ||
.has-background.od-lazy-bg-image { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Gutenberg, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in ce351c2. |
||
background-image: none !important; | ||
} | ||
} | ||
</style>' | ||
); | ||
$this->added_lazy_styles = true; | ||
} | ||
|
||
if ( ! $this->added_lazy_script ) { | ||
$processor->append_body_html( wp_get_inline_script_tag( image_prioritizer_get_lazy_load_bg_image_script(), array( 'type' => 'module' ) ) ); | ||
$this->added_lazy_script = true; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const lazyBgImageObserver = new IntersectionObserver( | ||
( entries ) => { | ||
for ( const entry of entries ) { | ||
if ( entry.isIntersecting ) { | ||
const bgImageElement = /** @type {HTMLElement} */ entry.target; | ||
|
||
bgImageElement.classList.remove( 'od-lazy-bg-image' ); | ||
|
||
lazyBgImageObserver.unobserve( bgImageElement ); | ||
} | ||
} | ||
}, | ||
{ | ||
rootMargin: '100% 0% 100% 0%', | ||
threshold: 0, | ||
} | ||
); | ||
|
||
const bgImageElements = document.querySelectorAll( | ||
'.has-background.od-lazy-bg-image' | ||
); | ||
for ( const bgImageElement of bgImageElements ) { | ||
lazyBgImageObserver.observe( bgImageElement ); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should be pulled in from a CSS file like we're doing for the lazy script? In this way we can use the minified version when not in
SCRIPT_DEBUG
mode.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, the Webpack setup doesn't minify CSS files the same way it handles JavaScript, as the TerserPlugin (used by CopyWebpackPlugin) is specifically for JavaScript minification. I'll explore other approaches to address this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess
wp-scripts
should have some way of doing this? I don't have a lot of experience with setting this up.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While
wp-scripts
does handle CSS minification as part of its default build pipeline when importing CSS in JavaScript, it doesn't offer a direct solution for standalone CSS files like these, especially when the goal is to output them in the same directory as the source files.I think it would be better to use a minifier like
cssnano
—which is also used by thepostcss-loader
in the Webpack configuration provided bywp-scripts
—through a Webpack plugin likeCssMinimizerPlugin
, with identicalminimizerOptions
as inwp-scripts
to ensure consistency with thewp-scripts
build process.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in a21dec4.