Problem/Motivation
Preload to optimize the loading of late-discovered resources. Normally large or hero images below the fold. By preloading a resource, you tell the browser to fetch it sooner than the browser would otherwise discover it before lazy loader kicks in. The browser caches preloaded resources so they are available immediately when needed. Nothing is loaded or executed at the preloading stage.
The idea is based on #3262804: Add preload option to help boost actual and perceived performance
More details:
- https://web.dev/preload-critical-assets/
- https://caniuse.com/?search=preload
- https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload
- https://developer.chrome.com/blog/new-in-chrome-73/#more
Examples of the implementation:
- https://www.bronco.co.uk/our-ideas/using-relpreload-for-responsive-images/
- https://html.spec.whatwg.org/multipage/semantics.html#attr-link-imagesrcset
Proposed resolution
Add a new option name Preload at field formatter level to better help decide based on their placement and asset criticality level.
Useful to optimize the loading of late-discovered resources. Normally large or hero images below the fold. This option will put link tags into the HEAD with rel preload so that browsers can prioritize resources to discover before lazy loader kicks in, or starts its own preload or decoding.
Just a friendly heads up: do not overuse this option, because not everything is critical.
Remaining tasks
Write patch, review.
User interface changes
A new option is added at field formatter level:
Before

After

API changes
None, just enhancement.
Data model changes
Yes, a new preload schema is added.

| Comment | File | Size | Author |
|---|---|---|---|
| #35 | drupal-image-formatter-preload.png | 45.65 KB | andrew_b |
| #35 | drupal-default-image-formatter.png | 42.83 KB | andrew_b |
| #14 | reroll_diff_12-14.txt | 53.01 KB | sahil.goyal |
| #14 | 3309016-14.patch | 19.42 KB | sahil.goyal |
| #13 | 3309016-nr-bot.txt | 173 bytes | needs-review-queue-bot |
Issue fork drupal-3309016
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
hitchshockComment #3
hitchshockI made a quick solution to provide Preload option.
But we still need to do tests for my patch, and of course review it.
Comment #4
hitchshockComment #5
hitchshockComment #8
Manoj Raj.R commentedVitalii Podoba
We can see a MR !3178 merge error.
is the issue still persists.
Comment #9
hitchshockComment #10
hitchshockMade tests for a new solution and a simple patch for 9.5
Comment #12
hitchshockFixed UT errors for the Drupal 9.5 patch.
I didn't add new tests to the patch file because the main code is in the merge request. The patch just makes it possible to use the new solution for Drupal 9.5
Comment #13
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #14
sahil.goyal commentedrerolling the patch respective to the 10.1.x along with the reroll.
Comment #15
hitchshockComment #16
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.
Since this is changing the configuration it will need an upgrade path for existing sites.
Also will need a change record.
Comment #17
hitchshockHi @smustgrave
Yes, the configuration has been updated, but the new option is FALSE by default, so it won't have any impact on existing sites. Therefore, we don't need to make any additional changes such as hook_update or hook_deploy
Comment #18
smustgrave commented@HitchShock thanks for all the work on this!
Even though the default is FALSE if I go into the field formatter, make no change and click save. If I do config export and it changes the config it will need an upgrade path.
Removing credit for #14 as it's expected to check a patch before uploading.
You can check for build errors make sure to run
./core/scripts/dev/commit-code-check.shbefore uploading a patch to make sure there are no issues with code formatting. see https://www.drupal.org/docs/develop/development-tools/running-core-devel...Comment #19
hitchshockHi @smustgrave
I got your point.
Provided an upgrade path and some tests.
Comment #20
smustgrave commentedupgrade looks good.
Can mark it after the change record.
Comment #21
hitchshockHi @smustgrave
Change record - done.
Comment #22
borisson_Unpublished the CR, because when it is published this is announced trough rss and that should only be done when the issue is committed.
Comment #23
martijn de witWill this be the same functionality as provided by https://www.drupal.org/project/responsive_image_preload ?
Comment #24
borisson_There are a lot of tests updated with
'#image_preload' => FALSE,, does this mean that all custom/contrib code will have to do that as well? Can we not rely on the default value instead? I'd love to see less changes in the tests for this PR.Comment #25
smustgrave commentedFor the new open threads in the MR
Comment #26
hitchshockWent through threads.
Big thanks to @borisson_ for the quality review. Some points were really good
Comment #27
heddnHow is the work here vs in #3048458: Add support of "preload" attribute into FileMediaFormatterBase different? It isn't clear.
Comment #28
hitchshock@heddn the differents is in formats that will be affected.
So, these are different solutions for different formatters
Comment #29
smustgrave commentedWill also post into #ux channel for feedback.
Comment #30
smustgrave commentedPosted in #ux channel and it hasn't had a full review but here is comment from @rkoller who was nice enough to take a quick look.
So seems like there is more votes leaning towards moving this into the image loading fieldset.
Will need a shorter description (if possible)
And nit picky "everything are critical" should be updated.
Comment #31
hitchshock@smustgrave Okay, you've convinced me.
- I moved the preload option into image_loading
- Updated the tests
Also, I banned adding the loading attribute when preload is used because in this case, it won't work anyway.
Comment #32
hitchshockComment #34
benjifisher@HitchShock:
Good timing! @Andrew_B and I are looking at this issue at DrupalCon Pittsburgh today. We will try to give a UX review today.
Comment #35
andrew_b commentedTested 3309016-add-image-preload branch using DrupalPod in core version 10.1.x
Viewed UI changes through the image field present on the Article content type (Structure → Content types → Article → Manage display).
The UI here looks great; Expanding the image loading dropdown in format reveals the "Preload" checkbox above the Image loading attribute radio. Hiding the attributes section upon checking "Preload" clearly indicates the other attribute options are rejected.
Compared page source before and after updating the image field format with preload active to verify that the respective link tags were placed in
HEADwithrel="preload" as="image". Everything appears as described.Working great! Very useful enhancement to the image field formatter.
Comment #36
catchOverall this looks good, added some comments on the MR though. It's still tagged for usability review, has that been done?
Comment #37
hitchshockHi @catch Wrote answers in the MR, Check them, please.
Also, it looks like @andrew_b has done a usability review in #35.
Also, the earlier version of the patch has been applied and tested on the real project.
But I don't know the approval procedure for this, so I'm not sure if I should remove "Needs usability review" tag or not.
Comment #38
benjifisherUsability review
I do not have an opinion on the implementation of this feature, or whether it is useful enough to be added to Drupal core. (If I understand correctly, this feature is already provided by the
blazycontrib module. If only a few sites need the feature, then that should be where it stays.) I am just reviewing the usability of the configuration form.The current MR introduces a very unusual pattern. By default, the
Preloadoption is un-checked and the "Image loading attribute" radio buttons are visible. IfPreloadis selected, then the radio buttons are hidden. The usual "progressive disclosure" pattern is different: initially, some options are hidden, keeping the form simple, but they appear if some other non-default option is selected.If I read the code correctly, then the choice of
loadingattribute is ignored whenPreloadis selected:I think it makes more sense to have three radio buttons. Putting
Preloadthird makes sense: then the options are ordered by how aggressive we are about loading. We will have to change the label "Image loading attribute" since one of the choices does not set theloadingattribute.Here is a first draft:
Lazy render images with native image loading attribute (loading="lazy"). This improves performance by allowing browsers to lazily load images.
Image loading
Delays loading the image until that section of the page is visible in the browser. When in doubt, lazy loading is recommended.
Force browsers to download an image as soon as possible. This is the browser default for legacy reasons. Only use this option when the image is always expected to render.
Preload to optimize the loading of late-discovered resources. Normally large or hero images below the fold.
Select how images are loaded. Learn more about the loading attribute for images and the preload attribute for links.
I do not love having descriptive text in three places (above the fieldset, after each option, and at the end of the fieldset). But I think that reorganizing it is out of scope for this issue.
The labels I suggest are imprecise because they do not indicate that the
loadingandrelattributes apply to different HTML elements. But I want to keep the labels short, and the link text at the bottom suggests what is going on.Comment #39
hitchshockHi @benjifisher
About your comment:
blazycontrib module. But it's worth remembering thatlazyandeagerloadings were also introduced quite recently and were previously only part of the contrib module. So I had a logical question: why wasn't the full solution implemented? Why weren't all possible loading options provided? This is weird for me. That's why I spend time creating this patch along with the tests and an upgrade path for existing sites instead of the simple patch with a simple solution.'image_loading' => [ 'attribute' => 'lazy', ],, but since preload is not an attribute, it cannot be stored in the same place as other loading attributes, cuz this is unlogical. So to implement your proposal, we need one of two ways:That's why I decided to make this option separate, so as not to overcomplicate the decision where it shouldn't be. It would be interesting to hear someone else's opinion on this issue.
Comment #41
spacetaxi commentedWith regard to placement of the preload option in the UI, it doesn't make sense to include preload with the eager and lazy options. To @hitchshock's point, preload is a separately rendered link tag. It can have a big impact of page performance and should be in core.
Comment #42
jwilson3I agree that preload should be kept separately from eager/lazy because preload adds a new HTML tag to the HEAD, as opposed to an attribute on the IMG tag. It is not an alternative option to eager/lazy but an additional feature to enhance LCP optimization even more than what eager can do.
Also, with Lighthouse now in the process of switching over to use "insights" instead of legacy "audits", there will also be forward momentum on the sister issue #3366828: Add option for fetchpriority attribute within "image loading" area on image field formatter, which uses a similar checkbox toggle in the image field formatter UI. So when evaluating UI patterns it would be good to take into account that an ideal "final" product here would have two additional opt-in checkboxes, one for Preload and another for Fetch Priority.
Comment #44
hitchshockAccording to #42 I made sure that we should not change the new option position/setting.
So I created a new MR for 11.x and adapted the existing code.
Comment #45
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #46
catchComment #47
hitchshockComment #49
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #50
jwilson3In a slack thread about introducing early hints for images, we identified with @catch a potential serious issue.
The approach for the D11 MR adds a preload for every image in a responsive image source set. This seems counter-productive for preload. Ideally, we'd want to preload just the one variant needed, but it is fundamentally impossible to pick which one from the server-, because it depends on client-side information (viewport size, rendered layout).
(Sidenote: the D10 MR does not have the responsive image work).
https://drupal.slack.com/archives/C0D5GJZ8B/p1777304794431579
Comment #51
hitchshock@jwilson3
Yes, you’re right, the new option for responsive images adds a preload for every image in the set. And yes, there’s no way to solve this differently on the server side.
But at the same time, I don’t see any serious issue here.
- Could this overload page preloading? - If you don’t approach the issue wisely, it might. But the same can be said about many other site settings. This isn’t something a regular user does; it’s what a developer handles.
- Are a large number of variants used in the responsive image set? - Usually not; 2–3 images at most, which is ok
- Also, don’t forget that such performance aspects need to be analyzed and tested, for example, using https://search.google.com/test/rich-results and https://search.google.com/. After all, the need to use preloading usually arises after such tests.
Comment #52
jwilson3I cant speak for @catch but what I, for sure, was thinking was that preloading several copies of an above-the-fold hero image, eg a super large (eg 2400px wide for large screen retina display), large (desktop), medium (tablet), and small (mobile), all on a mobile device, in that order because that is the presumably the order used to create the
<picture>element in responsive images, is precisely the kind of problem that I would consider a serious waste of mobile bandwidth.Do you have any proof that the images would not start automatically downloading because they're supposed to be used as part of a media query that doesn't match mobile?
Comment #53
heddnhttps://www.drupal.org/project/normalized_responsive_images is an up and coming recipe that offers up to 20 image sizes. I would push back on 3 or 4. https://github.com/ausi/respimagelint is fairly well known linter and recommends many images sizes.
Comment #54
catchYes preloading that many images would really undermine the point of reponsive images.
Preload allows for srcset + sizes on the link https://web.dev/articles/preload-responsive-images - that allows the browser to choose (essentially guess) which image might get used. But it also conflicts with sizes=auto which is newer and preferable, and relies on the page rendering enough to know how much space there is for the images - which implies not preloading at all.
Comment #55
heddnhttps://web.dev/articles/preload-responsive-images#picture seems to suggest, but it isn't clear to me if this is proposed or actual... that we can add preload in the header if we also add media queries.
Comment #56
hitchshock@jwilson3 And again, this is just an option. :)
The developer can decide whether this is appropriate for their site. For example, if a site uses a CDN, it doesn’t matter whether all images have been preloaded or not.
But keep in mind that preloading is, first and foremost, an option for images. For responsive images, it’s just a possibility—if it’s actually needed. For example, I had a site where we needed that.
@catch
If there are a lot of images, then that’s true—it doesn’t make sense to use it for a large number of images.
The whole point of preload is to load ONLY what’s necessary. In other words, this option should be used wisely, and overuse will have negative consequences. But that’s the developer’s responsibility; we’re just providing a way to avoid having to do it via custom code.
But that doesn’t mean it’s inappropriate when a responsive image uses 2–3 images. After all, the main point here is to get an image of the right size quickly.
FYI. Ignore MR test errors, they are caused by https://www.drupal.org/i/3581109
Comment #57
hitchshockhah, tested it quickly again and I see that it doesn't load ALL images. It depends on a responsive image @media
For example:

- installed a vanilla Drupal and installed a responsive image module
- configured a new style on the following way:
- then used this style for a node image field and created a node with an image
Result:
The following links were added to the page
Mobile screen:

Only one 1 image was preloaded:
Full screen (desktop):

All 3 images were preloaded
The result is expected according to the @media in the links (@media comes from the responsive image settings)
Conclusion:
In other words, the preload behavior will fully correspond to the @media rule of the responsive image.
It means it works correctly and efficiently even for responsive images, just the correct @media must be prepared for it.
Comment #58
jwilson3Thank you @hitchshock for providing proof, and screenshots.
So the bandwidth concern raised in #50 and #52 appears nuanced: it's not a problem on smaller viewports, but it becomes problematic on larger screens. This is due to how the media queries are interpreted: classic "mobile first"-style
min-widthconditions are cumulative, so multiple sources can match simultaneously unless explicitly bounded bymax-width.Conversely, implementations using only
max-widthbreakpoints would invert the problem, causing all variants to preload on smaller screens.This behavior differs from typical responsive CSS expectations, where cumulative breakpoints are very common and generally safe. For image preloading, however, non-exclusive conditions can lead to unintended concurrent downloads.
This should be explicitly documented, with clear guidance that breakpoints must be mutually exclusive when used with preload. It would also be worth highlighting this caveat in the UI, since most developers won’t think to verify actual network behavior per breakpoint. Maybe even we should provide a footgun warning, whereby we test breakpoints configured in responsive image sets to ensure they use the exclusionary methodology, and warn users when they're incorrectly configured.
We should also write an explicit test that shows parity between media queries on the preload and the responsive image set breakpoints used.
Comment #60
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #61
hitchshock@jwilson3
ok, expanded description for the option + added a warning message + added new tests
Comment #62
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. The merge request has merge conflicts and cannot be merged. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #63
jwilson3Code changes LGTM, nice work!
Tested with the
demo_umamiprofile on a desktop viewport with a retina display.Scale Crop 7:3 Largemedia view mode, used by the Umami hero banner block. Enable preload on the image field formatter using theHeroresponsive image style. This triggers the breakpoint warning.Responsive 3:2media view mode, used by the Umami frontpage cards via thecard_commonentity view mode. Enable preload on the image field formatter using the3:2 Imageresponsive image style. This does not trigger the warning.wide(desired) andtiny(undesired).large_3_2_2x(desired) andsquare_large(undesired).Side note: repeated homepage loads while logged in as admin did not immediately add the expected preload links to the DOM. After clicking through various admin pages, waiting, and rebuilding caches, both eventually appeared. I'm not certain what fixed this, but it may be out of scope for this issue. Tested on
coder.ddev.com.IMO it makes sense to slightly widen the scope here: get Umami working as expected, and use it to demonstrate how the preload setting should work.
For the
Heroresponsive image style, I suggest updating the breakpoint configuration so it does not trigger the warning and does not download two images at desktop sizes. I suspect thetinybreakpoint needs to be made exclusionary, but that needs a deeper look. Once the breakpoint stack is corrected, we should probably add both a failing test for the current broken configuration and a passing test for the corrected one.For
3:2 Image, preloading the homepage cards is not realistic, since below-the-fold cards should remain lazy-loaded. However, the recipe detail page also uses theResponsive 3:2media view mode, where the image appears above the fold and could benefit from preload. The complication is that the same media view mode is used in both contexts, so I’m not sure whether it can be configured as lazy-loaded in one place and preloaded in another without a preprocess-level alteration.It probably still makes sense to exercise the
3:2 Imagecode path, since it uses viewport sizing instead of breakpoints. We need to determine why two images are loaded there too, and whether that can be tested by generalizinghasNonExclusiveBreakpoints().Comment #64
heddnI'm afraid this PR getting very large. We might want to split it up into 3 smaller pieces. One for responsive image, one for media and one for image.module. At a git stat of 68 files +1930 −55, this is getting hard to review. Splitting it up will give us time to learn as we go too. And if you break the responsive image stuffs out, it punts on the UX concerns around multiple files being downloaded until later.
When we first introduced loading attribute support into core, we also brought it in over multiple PRs for similar review reasons. You might be able to keep media and image in the same PR, but splitting things up is almost always a good thing.
Comment #65
heddnI didn't dwell on it a lot in my initial review but the UX concerns with responsive image are sufficient to need us to spend some time on the UX wording of things. Which reminds me, do we need to do a UX review of the text for adding preload to field formatters? Has that happened yet? A formal review would be nice but even a screenshot posted here and some informal reviews would be great. There seems to be enough nuances here around best practices and suggestions about _not_ using preload in certain situations that guidance would help.
Comment #66
hitchshock@heddn
Thanks for you comment in MR. Fixed some of them and left comments for others.
About "big MR" - The MR was reviewed many, many times already. And all the last reviews didn't have any critical comments, I would say all of them are very minor, even your last review.
At this point, I no longer see much value in further splitting the task or restructuring the code, especially if it would require additional time and delay the release process even more. I decided to contribute this functionality to Drupal on a voluntary basis because I believed it could be useful for the community, and I have already invested a significant amount of my personal time into this work.
For that reason, at the moment, I am only prepared to handle merge conflicts with the main branch and possibly make minor adjustments. Beyond that, I do not feel it is productive to continue extensive work on the issue, as the recent review cycles have not introduced feedback related to critical problems, but instead have mostly resulted in additional iterations that continue to postpone approval and release. Addressing these smaller points requires considerable time while providing limited practical impact on the overall functionality or quality of the solution.
P.S. To be honest, I used to feel motivated to contribute more actively to Drupal core. However, after independently starting and implementing a couple of issues from scratch, the experience has been somewhat discouraging. It often feels that reviews focus primarily on relatively minor details that do not significantly affect the outcome, while the larger goal of moving the issue forward gets delayed repeatedly.
For example, on this particular issue there have not been any requests related to genuinely critical problems for the past 2–3 years, which already indicates the level of work done and the readiness for release. Instead, the issue has remained in a prolonged “in progress” state, where new reviews sometimes introduce only small or non-essential comments, move the issue back to “Needs work,” and then leave it inactive again for an extended period.
I fully understand and respect the importance of code review and maintaining high standards in Drupal core. At the same time, from a contributor’s perspective, the process can sometimes feel discouraging when progress toward resolution becomes extremely slow despite the absence of major technical concerns.
Comment #67
hitchshockHi @jwilson3
Sorry, but demo_umami is a very outdated project. I'd appreciate it if you could reproduce the issue on a newer project so we can raise it locally without any hassle :)
fyi. the main point here is to check *.breakpoints.yml and responsive_image.styles.*.yml files, to check what specific is there. For now, I wasn't able to reproduce it on a fresh site and on my projects.