<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Yoav Weiss on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Yoav Weiss</name>
  </author>
  <link href="https://web.dev/authors/yoavweiss/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/admin/FOIxDKJfuHssXMNzezIt.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Our latest news, updates, and stories by Yoav Weiss.</subtitle>
  
  
  <entry>
    <title>How SPA architectures affect Core Web Vitals</title>
    <link href="https://web.dev/vitals-spa-faq/"/>
    <updated>2021-09-14T00:00:00Z</updated>
    <id>https://web.dev/vitals-spa-faq/</id>
    <content type="html" mode="escaped">&lt;p&gt;Since first introducing the &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Web Vitals&lt;/a&gt; initiative in May of 2020, we
on the Chrome team have received a lot of great questions and feedback about the
program.&lt;/p&gt;
&lt;p&gt;Perhaps the topic we&#39;ve received the most questions about, which is also
probably the hardest question to answer, is how to measure Core Web Vitals in a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Single-page_application&quot; rel=&quot;noopener&quot;&gt;single-page application&lt;/a&gt;
(SPA), as well as how SPA architectures affect Core Web Vitals scores.&lt;/p&gt;
&lt;p&gt;These questions are hard to answer because the problem is quite nuanced, so in
this post we&#39;re going to do our best to answer the most common questions,
providing as much detail and context as we can.&lt;/p&gt;
&lt;p&gt;Before getting into specifics, though, it&#39;s important to state that Google does
not have any preference as to what architecture or technology is used to build a
site. We believe that SPAs and multi-page applications (MPAs) are both capable
of delivering high quality experiences to users, and our intention with the Web
Vitals initiative is to provide metrics that measure the experience independent
of the technology. While this is not possible in every case today (due to
limitations in the web platform), we are &lt;a href=&quot;https://web.dev/vitals-spa-faq/#what-is-google-doing-to-ensure-mpas-do-not-have-an-unfair-advantage-compared-to-spas&quot;&gt;actively working on closing those
gaps&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Update (February 2023): The work is now available for sites to experiment with. See the &lt;a href=&quot;https://developer.chrome.com/blog/soft-navigations-experiment/&quot;&gt;Experimenting with measuring soft navigations&lt;/a&gt; post for more details. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;frequently-asked-questions&quot;&gt;Frequently asked questions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#frequently-asked-questions&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;do-core-web-vitals-metrics-include-spa-route-transitions&quot;&gt;Do Core Web Vitals metrics include SPA route transitions? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#do-core-web-vitals-metrics-include-spa-route-transitions&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No. Each of the Core Web Vitals metrics is measured relative to the current,
top-level page navigation. If a page dynamically loads new
content and updates the URL of the page in the address bar, it will have no
effect on how the Core Web Vitals metrics are measured. Metric values are not
reset, and the URL associated with each metric measurement is the URL the user
navigated to that initiated the page load.&lt;/p&gt;
&lt;h3 id=&quot;can-the-core-web-vitals-metrics-treat-spa-route-changes-the-same-as-traditional-page-loads&quot;&gt;Can the Core Web Vitals metrics treat SPA route changes the same as traditional page loads? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#can-the-core-web-vitals-metrics-treat-spa-route-changes-the-same-as-traditional-page-loads&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unfortunately, no. Not yet anyway.&lt;/p&gt;
&lt;p&gt;There is no standardized way of building an SPA today, and even among the
popular SPA and routing libraries, the user experience can be quite different
from app to app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some SPAs update the URL only when loading new &amp;quot;full page&amp;quot; content, whereas
other sites update the URL for tiny content changes or even just UI state
changes.&lt;/li&gt;
&lt;li&gt;Some SPAs update the URL using the History API, whereas others use hash
changes in order to support older browsers (and others do not update the URL
at all).&lt;/li&gt;
&lt;li&gt;Some SPAs load content and then update the URL, whereas others update the URL
before loading content.&lt;/li&gt;
&lt;li&gt;Some SPAs load content all at once, synchronously, in a single JavaScript
task, whereas others transition content in, asynchronously, across multiple
tasks (with no clear transition end event).&lt;/li&gt;
&lt;li&gt;Some SPAs always load content from the network, whereas others preload all
content upfront so that route changes load instantly from memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These differences make defining and identifying what constitutes an SPA route
change, or even an SPA itself, very difficult to do &lt;em&gt;at scale&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In some cases an SPA route change is logically identical to an MPA page load,
and in such cases it would be great if the existing Core Web Vitals metrics
could be applied.&lt;/p&gt;
&lt;p&gt;However, without solid heuristics to reliably identify &amp;quot;real&amp;quot; route changes from
all other URL changes—as well as clear signals marking the beginning and end of
such transitions—reporting Core Web Vitals metrics in these cases would muddy
the data and make it less useful or representative of the real user experience
on the site.&lt;/p&gt;
&lt;h3 id=&quot;is-it-harder-for-spas-to-do-well-on-core-web-vitals-than-mpas&quot;&gt;Is it harder for SPAs to do well on Core Web Vitals than MPAs? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#is-it-harder-for-spas-to-do-well-on-core-web-vitals-than-mpas&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There is nothing inherent in the SPA architecture that would prevent a page in
an SPA from loading just as quickly—and scoring just as well on all of the Core
Web Vitals metrics—as a similar page in an MPA.&lt;/p&gt;
&lt;p&gt;However, properly optimized MPAs do have some advantages in meeting the Core Web
Vitals thresholds that SPAs currently do not. The reason is because with the MPA
architecture, each &amp;quot;page&amp;quot; is loaded as a full-page navigation (rather than
dynamically fetching content and inserting it into the existing page), which
means users who visit an MPA are more likely to load more than one page from the
site, which in turn means that a larger percentage of the distribution of all
page loads for an MPA will involve some or all of the sub-resources being
cached.&lt;/p&gt;
&lt;p&gt;Granted, for an MPA to perform better on the Core Web Vitals metrics than an SPA
requires a few things to be true:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The MPA needs to have optimized sub-resource caching in order to ensure
same-origin page loads are indeed faster than cross-origin page loads at the
75th percentile.&lt;/li&gt;
&lt;li&gt;Users who visit MPAs need to visit multiple pages in order for the site to
receive the caching benefits that result in faster page loads.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since Core Web Vitals assessments &lt;a href=&quot;https://web.dev/defining-core-web-vitals-thresholds/#choice-of-percentile&quot;&gt;consider the 75th
percentile&lt;/a&gt; of page
visits, having more, well-performing page visits in the dataset will increase
the likelihood that the visit at the 75th percentile of the distribution will be
within the recommended thresholds.&lt;/p&gt;
&lt;p&gt;Note that an important thing to consider when comparing Core Web Vitals scores
is how the data is aggregated—that is, whether the dataset in the distribution
includes all pages from your site or origin, or just page loads for a particular
page URL.&lt;/p&gt;
&lt;p&gt;When aggregating the scores of all pages in an origin, individual fast pages can
improve the 75th percentile for the origin as a whole. However, when aggregating
by individual pages, the scores of one page will not affect the scores of the
next. In other words, when aggregating the scores of an MPA by page, fast cache
loads seen on the checkout page will &lt;em&gt;not&lt;/em&gt; improve the scores of slow initial
loads experienced on the site&#39;s &lt;a href=&quot;https://en.wikipedia.org/wiki/Landing_page&quot; rel=&quot;noopener&quot;&gt;landing
page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can check your site&#39;s score for different aggregation methods using
&lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights&lt;/a&gt; or
the &lt;a href=&quot;https://developer.chrome.com/blog/chrome-ux-report-api/&quot; rel=&quot;noopener&quot;&gt;Chrome User Experience Report
API&lt;/a&gt;,
which reports scores for both individual page URLs and the entire origin.&lt;/p&gt;
&lt;p&gt;Another way the SPA architecture can affect Core Web Vitals scores is for
metrics that consider the full lifespan of a page. Since users visiting SPAs
tend to stay on the same &amp;quot;page&amp;quot; for the entire session, metrics that accumulate
over time can be harsher on SPAs than MPAs.&lt;/p&gt;
&lt;p&gt;In April 2021, we announced &lt;a href=&quot;https://web.dev/evolving-cls/&quot;&gt;changes to the CLS metric&lt;/a&gt; that
partially addressed this problem. Previously CLS would accumulate over the
entire page lifespan, whereas now it only accumulates over a specific window of
time—essentially the worst burst of layout shifts on a given page.&lt;/p&gt;
&lt;p&gt;However, even with the new CLS definition, SPAs are still at a disadvantage
because the CLS value doesn&#39;t &amp;quot;reset&amp;quot; after a route transitions like it does
with full page loads in an MPA. This can also lead to confusion because layout
shifts that occur after a route transition will be attributed to the URL of the
page when it was loaded, not the URL in the address bar at the time of the shift
(&lt;a href=&quot;https://web.dev/vitals-spa-faq/#if-core-web-vitals-scores-are-only-reported-for-an-spa&#39;s-landing-pages-how-can-i-debug-issues-that-occur-on-pages-after-a-route-transition&quot;&gt;more details
below&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;if-spa-architectures-improve-the-user-experience,-shouldnt-that-improvement-be-reflected-in-the-metrics&quot;&gt;If SPA architectures improve the user experience, shouldn&#39;t that improvement be reflected in the metrics? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#if-spa-architectures-improve-the-user-experience,-shouldnt-that-improvement-be-reflected-in-the-metrics&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Yes, it should. Though as mentioned previously, quantifying just how much the
experience has improved is difficult to do at scale, given all the different
ways SPAs are implemented on the web today.&lt;/p&gt;
&lt;p&gt;The truth is the web performance industry (Google included) has historically not
invested nearly as much time and effort into developing &lt;a href=&quot;https://web.dev/user-centric-performance-metrics/&quot;&gt;user-centric
metrics&lt;/a&gt; for the post-load performance of a
page as it has for the page load itself. This isn&#39;t because post-load
performance isn&#39;t important, it&#39;s because post-load UX and interactions are so
much more varied and less well-defined—making it hard to design metrics for
them.&lt;/p&gt;
&lt;p&gt;But even if we did have well defined post-load metrics to measure SPA
performance, we wouldn&#39;t want to ignore the load experience just because the
post load experience got better.&lt;/p&gt;
&lt;p&gt;One of the goals of the Web Vitals initiative is to promote and incentivize good
user experiences across as many aspects of loading and using a web page as
possible. We don&#39;t want to encourage scenarios where bad experiences are
justified if you can have enough good experiences to make up for them. Users
want pages to load fast &lt;em&gt;and&lt;/em&gt; transition to new content fast, and we&#39;ve tried to
design metrics that favor those types of experiences.&lt;/p&gt;
&lt;p&gt;So while it&#39;s true that an MPA version of a site may fare better on the Core Web
Vitals metrics at the 75th percentile than an SPA version of the exact same
site, the SPA version should still strive to meet the &amp;quot;good&amp;quot; threshold. If the
SPA version doesn&#39;t meet the &amp;quot;good&amp;quot; threshold for most users, then the initial
load experience is probably still not perceived as good—even if the subsequent,
in-page navigation experience is excellent.&lt;/p&gt;
&lt;p&gt;In the future we plan to develop metrics that encourage great, post-load
experiences, and we believe this is the best path to incentivize high-quality
SPAs in a way that doesn&#39;t compromise the initial load experience. We have
already delivered a new metric named &lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint (INP)&lt;/a&gt; that measures interaction latency throughout the entire page lifecycle, and we&#39;re actively working on other
post-load metrics as well, including metrics that measure SPA route transitions
(&lt;a href=&quot;https://web.dev/vitals-spa-faq/#design-new-apis-that-enable-better-spa-measurement&quot;&gt;see below&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;we-switched-our-site-from-an-mpa-to-an-spa-and-our-scores-regressed-is-that-expected&quot;&gt;We switched our site from an MPA to an SPA and our scores regressed. Is that expected? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#we-switched-our-site-from-an-mpa-to-an-spa-and-our-scores-regressed-is-that-expected&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It depends. There are a number of reasons why your scores could change after a
major architecture migration, but a decrease in the number of warm cache loads
could account for some of the change.&lt;/p&gt;
&lt;p&gt;A quick way to check would be to test both an MPA and SPA version of one of your
landing pages with
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt;. If the
Lighthouse score is lower on any of the Core Web Vitals metric for the SPA
version, then it&#39;s likely that the load experience did get worse after the
update.&lt;/p&gt;
&lt;h3 id=&quot;should-i-switch-my-site-from-an-spa-to-an-mpa-to-score-better-on-core-web-vitals&quot;&gt;Should I switch my site from an SPA to an MPA to score better on Core Web Vitals? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#should-i-switch-my-site-from-an-spa-to-an-mpa-to-score-better-on-core-web-vitals&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Probably not. You should only switch from an SPA to an MPA if you are not happy
with your SPA stack and you have reason to believe an MPA will provide a better
user experience.&lt;/p&gt;
&lt;p&gt;Over time, as the Core Web Vitals metrics improve and cover more of the full
browsing experience, teams with well-built SPAs that provide great UX should
expect to see their Core Web Vitals scores reflect that.&lt;/p&gt;
&lt;h3 id=&quot;if-core-web-vitals-scores-are-only-reported-for-an-spas-landing-pages,-how-can-i-debug-issues-that-occur-on-pages-after-a-route-transition&quot;&gt;If Core Web Vitals scores are only reported for an SPA&#39;s landing pages, how can I debug issues that occur on &amp;quot;pages&amp;quot; after a route transition? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#if-core-web-vitals-scores-are-only-reported-for-an-spas-landing-pages,-how-can-i-debug-issues-that-occur-on-pages-after-a-route-transition&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Google tools that report field data for the Core Web Vitals metric (like Search
Console and PageSpeed Insights) get their data from the &lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome User Experience
Report&lt;/a&gt;
(CrUX). And CrUX aggregates data either by origin or by page URL (that is, the
page URL at load time).&lt;/p&gt;
&lt;p&gt;For all the reasons already listed above, CrUX is not able to aggregate data by
SPA route. However, as a site owner who is familiar with your own architecture,
it is possible to measure this yourself, and many analytics tools allow you to
signal when an SPA route change is occurring and they update your measurement
data accordingly.&lt;/p&gt;
&lt;p&gt;When measuring Web Vitals metrics with an analytics tool, make sure you&#39;re
measuring both the current route URL as well as the original page URL. This will
allow you to both debug individual issues that occur throughout the page
lifecycle as well as aggregate by original page URL in order to match how Google
tools measure and report on the metrics.&lt;/p&gt;
&lt;p&gt;For more details and best practices on this topic, see: &lt;a href=&quot;https://web.dev/debug-performance-in-the-field/&quot;&gt;Debug performance in the
field&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-is-google-doing-to-ensure-mpas-do-not-have-an-unfair-advantage-compared-to-spas&quot;&gt;What is Google doing to ensure MPAs do not have an unfair advantage compared to SPAs? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#what-is-google-doing-to-ensure-mpas-do-not-have-an-unfair-advantage-compared-to-spas&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned above, a properly-optimized MPA can, in some cases, report better
Web Vitals scores at the 75th percentile due to the fact that it will likely
have a higher percentage of cached page visits. Conversely, real improvements to
the user experience in properly-optimized SPAs are not currently being captured
by any of the Core Web Vitals metrics.&lt;/p&gt;
&lt;p&gt;At Google, we recognize that this creates incentives that do not fully align
with the goals of the Web Vitals initiative, and we are actively looking at ways
to fix this. Currently, we&#39;re exploring two potential solutions, one short term
and one longer term:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Assess cross-origin and same-origin page visits separately.&lt;/li&gt;
&lt;li&gt;Design new APIs that enable better SPA measurement.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;assess-cross-origin-and-same-origin-page-visits-separately&quot;&gt;Assess cross-origin and same-origin page visits separately &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#assess-cross-origin-and-same-origin-page-visits-separately&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Today the Core Web Vitals metrics aggregate all page visits into a single
bucket—they do not differentiate between new versus returning visits or landing
pages versus checkout pages or any other aggregation type where cache state
could have an effect on performance.&lt;/p&gt;
&lt;p&gt;One way to normalize the differences between SPA and MPA performance would be to
apply different weighting to different types of visits, potentially even with
completely different &lt;a href=&quot;https://web.dev/defining-core-web-vitals-thresholds/&quot;&gt;threshold
recommendations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While we definitely do want to reward effective cache implementations, we don&#39;t
want fast intra-site navigations to be able to cover up for slow landing page
loads. We also don&#39;t want to incentivize sites to break up long pages into a
collection of shorter pages just for the sake of improving metric scores.&lt;/p&gt;
&lt;p&gt;By separately assessing cross-origin and same-origin page visits we can help
ensure that both types of experiences are important without letting the relative
popularity of one type on a given site skew the distribution of any particular
metric.&lt;/p&gt;
&lt;h4 id=&quot;design-new-apis-that-enable-better-spa-measurement&quot;&gt;Design new APIs that enable better SPA measurement &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#design-new-apis-that-enable-better-spa-measurement&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Another solution that is actively being worked on (in parallel to the above) is
a new &lt;a href=&quot;https://web.dev/app-history-api/&quot;&gt;App History API&lt;/a&gt;, which would help standardize current
SPA patterns and make it easier to measure and understand SPA usage at scale.&lt;/p&gt;
&lt;p&gt;The App History API introduces a new
&lt;a href=&quot;https://wicg.github.io/app-history/#navigate-event&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;navigate&lt;/code&gt;&lt;/a&gt; event, which
has two key features specific to SPA measurement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A
&lt;a href=&quot;https://wicg.github.io/app-history/#ref-for-dom-apphistorynavigateevent-userinitiated%E2%91%A0&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;userInitiated&lt;/code&gt;&lt;/a&gt;
flag, which will only be set to true if the navigation was initiated via a
link click, form submission, or the browser&#39;s back or forward UI.&lt;/li&gt;
&lt;li&gt;A
&lt;a href=&quot;https://wicg.github.io/app-history/#ref-for-dom-apphistorynavigateevent-transitionwhile%E2%91%A0%E2%91%A8&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;transitionWhile()&lt;/code&gt;&lt;/a&gt;
method, which takes a promise allowing the developer to signal when the work
they&#39;ve initiated to perform the navigation is complete.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;userInitiated&lt;/code&gt; flag can be used to determine a semantic starting point for
an SPA route transition, indicating clear user intent. The &lt;code&gt;transitionWhile()&lt;/code&gt;
promise resolving can help the browser correlate paints with the specific route
transition, such that it may be able to determine the largest contentful paint
related to that transition.&lt;/p&gt;
&lt;p&gt;Building on top of the idea presented in the previous section, it might even be
possible to aggregate SPA route transition time into the same bucket as
same-origin page loads in an MPA. This is exciting because it would allow a site
migrating from an MPA to an SPA to actually compare the performance before and
after.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Update (February 2023): See the &lt;a href=&quot;https://developer.chrome.com/blog/soft-navigations-experiment/&quot;&gt;Experimenting with measuring soft navigations&lt;/a&gt; post for more information on a new &amp;quot;soft-navigations&amp;quot; API that is intended to allow better Core Web Vitals measurements for SPAs. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Of course, more research is needed before we&#39;ll know whether we can accurately
make these determinations. If you have suggestions or feedback on these
proposals, please email
&lt;a href=&quot;mailto:web-vitals-feedback@googlegrouops.com&quot; rel=&quot;noopener&quot;&gt;web-vitals-feedback@googlegroups.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/vitals-spa-faq/#final-thoughts&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Google is deeply committed to improving the Web Vitals metrics, and ensuring
they measure and incentivize high-quality experiences that are important to
users. That being said, we do acknowledge that measurement gaps exist today. The
metrics do not currently cover every aspect of user experience, but we are
actively working to close these gaps.&lt;/p&gt;
&lt;p&gt;Despite the current limitations, we believe the areas the existing metrics do
capture are critical to the health and success of the web, and to the extent
that sites (regardless of architecture) do not meet the recommended thresholds,
we believe there is room for improvement.&lt;/p&gt;
&lt;p&gt;I hope this post has helped shed some light on this complex and nuanced subject.
As always, if you have feedback on the current or future Web Vitals metrics,
please email
&lt;a href=&quot;mailto:web-vitals-feedback@googlegrouops.com&quot; rel=&quot;noopener&quot;&gt;web-vitals-feedback@googlegroups.com&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Philip Walton</name>
    </author><author>
      <name>Yoav Weiss</name>
    </author>
  </entry>
  
  <entry>
    <title>Preloading responsive images</title>
    <link href="https://web.dev/preload-responsive-images/"/>
    <updated>2019-09-30T00:00:00Z</updated>
    <id>https://web.dev/preload-responsive-images/</id>
    <content type="html" mode="escaped">&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 73, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      73
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 78, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      78
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari, Not supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;p&gt;&lt;/p&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;This article gives me an opportunity to discuss two of my favorite things: responsive images &lt;em&gt;and&lt;/em&gt; preload. As someone who was heavily involved in developing both of those features, I&#39;m super excited to see them working together!&lt;/p&gt;
&lt;h2 id=&quot;responsive-images-overview&quot;&gt;Responsive images overview &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#responsive-images-overview&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Suppose you&#39;re browsing the web on a screen that&#39;s 300 pixels wide, and the page just requested an image that&#39;s 1500 pixels wide. That page just wasted a lot of your cellular data because your screen can&#39;t do anything with all of that extra resolution. Ideally, the browser should fetch a version of the image that&#39;s just a &lt;em&gt;little&lt;/em&gt; wider than your screen size, say 325 pixels. This ensures a high-resolution image without wasting data. And, even better, the image will load faster. &lt;a href=&quot;https://web.dev/serve-responsive-images/#serve-multiple-image-versions&quot;&gt;Responsive images&lt;/a&gt; enable browsers to fetch different image resources to different devices. If you don&#39;t use an &lt;a href=&quot;https://web.dev/image-cdns/&quot;&gt;image CDN&lt;/a&gt; you need to save multiple dimensions for each image and specify them in the &lt;code&gt;srcset&lt;/code&gt; attribute. The &lt;code&gt;w&lt;/code&gt; value tells the browser the width of each version. Depending on the device, the browser can choose the appropriate one:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;small.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;small.jpg 500w, medium.jpg 1000w, large.jpg 1500w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;preload-overview&quot;&gt;Preload overview &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#preload-overview&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/preload-critical-assets&quot;&gt;Preload&lt;/a&gt; lets you tell the browser about critical resources that you want to load as soon as possible, before they are discovered in HTML. This is especially useful for resources that are not easily discoverable, such as fonts included in stylesheets, background images, or resources loaded from a script.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;important.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;responsive-images-preload-=-faster-image-loads&quot;&gt;Responsive images + preload = faster image loads &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#responsive-images-preload-=-faster-image-loads&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Responsive images and preload have been available for the last few years, but at the same time something was missing: there was no way to preload responsive images. &lt;a href=&quot;https://developers.google.com/web/updates/2019/03/nic73#more&quot; rel=&quot;noopener&quot;&gt;Starting in Chrome 73&lt;/a&gt;, the browser can preload the right variant of responsive images specified in &lt;code&gt;srcset&lt;/code&gt; before it discovers the &lt;code&gt;img&lt;/code&gt; tag!&lt;/p&gt;
&lt;p&gt;Depending on your site&#39;s structure, that could mean significantly faster image display! We ran tests on a site that uses JavaScript to lazy-load responsive images. Preloading resulted in images loading 1.2 seconds faster.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;  Responsive images are &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/img#Browser_compatibility&quot;&gt;supported in all modern browsers&lt;/a&gt; while preloading them is &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Preloading_content#Browser_compatibility&quot;&gt;supported only in Chromium-based browsers&lt;/a&gt;.  &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;imagesrcset-and-imagesizes&quot;&gt;&lt;code&gt;imagesrcset&lt;/code&gt; and &lt;code&gt;imagesizes&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#imagesrcset-and-imagesizes&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To preload responsive images, new attributes were recently added to the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element: &lt;code&gt;imagesrcset&lt;/code&gt; and &lt;code&gt;imagesizes&lt;/code&gt;.  They are used with &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt; and match the &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; syntax used in &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;For example, if you want to preload a responsive image specified with:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wolf.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wolf_400px.jpg 400w, wolf_800px.jpg 800w, wolf_1600px.jpg 1600w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;50vw&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;A rad wolf&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can do that by adding the following to your HTML&#39;s &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wolf.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;imagesrcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;wolf_400px.jpg 400w, wolf_800px.jpg 800w, wolf_1600px.jpg 1600w&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;imagesizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;50vw&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This kicks off a request using the same resource selection logic that &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; will apply.&lt;/p&gt;
&lt;h2 id=&quot;use-cases&quot;&gt;Use cases &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#use-cases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;preloading-dynamically-injected-responsive-images&quot;&gt;Preloading dynamically-injected responsive images &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#preloading-dynamically-injected-responsive-images&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let&#39;s say you&#39;re dynamically-loading hero images as part of a slideshow and know which image will be displayed first. In that case, you probably want to avoid waiting for the script before loading the image in question, as that would delay when users can see it.&lt;/p&gt;
&lt;p&gt;You can inspect this issue on a website with a dynamically-loaded image gallery:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open &lt;a href=&quot;https://responsive-preload.glitch.me/no_preload.html&quot; rel=&quot;noopener&quot;&gt;this example website&lt;/a&gt; in a new tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Throttling&lt;/strong&gt; drop-down list, select &lt;strong&gt;Fast 3G&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Disable the &lt;strong&gt;Disable cache&lt;/strong&gt; checkbox.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reload the page.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
&lt;img alt=&quot;Screenshot of Chrome DevTools Network panel.&quot; decoding=&quot;async&quot; height=&quot;481&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/cyocwRmB3XlfY26vUZ5h.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;figcaption&gt;This waterfall shows that the images only start loading after the browser has finished running the script, introducing unnecessary delay to the time the image is initially displayed to the user.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Using &lt;code&gt;preload&lt;/code&gt; helps here because the image starts loading ahead of time and is likely to already be there when the browser needs to display it.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Screenshot of Chrome DevTools Network panel.&quot; decoding=&quot;async&quot; height=&quot;481&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/rIRdFypLWf1ljMaXCVCs.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;figcaption&gt;This waterfall shows that the first image started loading at the same time as the script, avoiding unnecessary delays and resulting in faster displaying images.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To see the difference that preloading makes, you can inspect the same dynamically-loaded image gallery but &lt;a href=&quot;https://responsive-preload.glitch.me/preload.html&quot; rel=&quot;noopener&quot;&gt;with preloaded first image&lt;/a&gt; by following the steps from the first example.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; An alternative way to avoid the problem would be to use a markup-based carousel and have the &lt;a href=&quot;https://hacks.mozilla.org/2017/09/building-the-dom-faster-speculative-parsing-async-defer-and-preload/&quot;&gt;browser&#39;s preloader&lt;/a&gt; pick up the required resources. However, this approach may not always be practical. (For example, if you are reusing an existing component, which is not markup-based.) &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;preloading-background-images-using-image-set&quot;&gt;Preloading background images using image-set &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#preloading-background-images-using-image-set&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you have different background images for different screen densities, you can specify them in your CSS with the &lt;code&gt;image-set&lt;/code&gt; syntax. The browser can then choose which one to display based on the screen&#39;s &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Window/devicePixelRatio&quot; rel=&quot;noopener&quot;&gt;DPR&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;image-set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cat.png&quot;&lt;/span&gt; 1x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cat-2x.png&quot;&lt;/span&gt; 2x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;  The above syntax ignores the fact that vendor prefixes are needed for this feature in both Chromium and WebKit based browsers. If you&#39;re planning to use this feature, you should consider using &lt;a href=&quot;https://github.com/postcss/autoprefixer&quot;&gt;Autoprefixer&lt;/a&gt; (&lt;a href=&quot;https://goonlinetools.com/autoprefixer/&quot;&gt;available as an online tool&lt;/a&gt;) to address that automatically.  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The problem with CSS background images is that they are discovered by the browser only after it has downloaded and processed all the CSS in the page&#39;s &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, which can be a lot of CSS…&lt;/p&gt;
&lt;p&gt;You can inspect this issue on an example website with &lt;a href=&quot;https://responsive-preload.glitch.me/background_no_preload.html&quot; rel=&quot;noopener&quot;&gt;responsive background image&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Screenshot of Chrome DevTools Network panel.&quot; decoding=&quot;async&quot; height=&quot;451&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/7sjFt1RsoEOKn5zlS5zb.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;figcaption&gt;In this example, the image download doesn&#39;t start until the CSS is fully downloaded, resulting in unnecessary lag to the image&#39;s display.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Responsive image preloading provides a simple and hack-free way to load those images faster.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;imagesrcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;cat.png 1x, cat-2x.png 2x&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Note that by excluding the &lt;code&gt;href&lt;/code&gt; attribute, you can ensure the browsers that do not support &lt;code&gt;imagesrcset&lt;/code&gt; on the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element, but do support &lt;code&gt;image-set&lt;/code&gt; in CSS, will not download an incorrect source. However, they will also not benefit from the preload in this case.&lt;/p&gt;
&lt;p&gt;You can inspect how the previous example behaves with &lt;a href=&quot;https://responsive-preload.glitch.me/background_preload.html&quot; rel=&quot;noopener&quot;&gt;preloaded responsive background image&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Screenshot of Chrome DevTools Network panel.&quot; decoding=&quot;async&quot; height=&quot;439&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/dOI6EmChfahBujnZOke7.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;figcaption&gt;Here the image and CSS start downloading at the same time, avoiding delays and resulting in a faster loading image.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;preloading-responsive-images-in-action&quot;&gt;Preloading responsive images in action &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#preloading-responsive-images-in-action&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Preloading your responsive images can speed them up in theory, but what does it do in practice?&lt;/p&gt;
&lt;p&gt;To answer that I created two copies of a &lt;a href=&quot;https://github.com/GoogleChromeLabs/sample-pie-shop&quot; rel=&quot;noopener&quot;&gt;demo PWA shop&lt;/a&gt;: &lt;a href=&quot;https://20190710t144416-dot-pie-shop-app.appspot.com/apparel&quot; rel=&quot;noopener&quot;&gt;one that does not preload images&lt;/a&gt;, and &lt;a href=&quot;https://20190710t132936-dot-pie-shop-app.appspot.com/apparel&quot; rel=&quot;noopener&quot;&gt;one that preloads some of them&lt;/a&gt;. Since the site lazy loads images using JavaScript, it&#39;s likely to benefit from preloading the ones that will be in the initial viewport.&lt;/p&gt;
&lt;p&gt;That gave me the following results for &lt;a href=&quot;https://www.webpagetest.org/result/190710_VM_30b9d4c993a1e60befba17e1261ba1ca/&quot; rel=&quot;noopener&quot;&gt;no preload&lt;/a&gt; and for &lt;a href=&quot;https://www.webpagetest.org/result/190710_7B_a99e792121760f81a270b4b9c847797b/&quot; rel=&quot;noopener&quot;&gt;image preload&lt;/a&gt;. Looking at the raw numbers we see that &lt;a href=&quot;https://github.com/WPO-Foundation/webpagetest-docs/blob/main/src/getting-started.md#start-render&quot; rel=&quot;noopener&quot;&gt;Start Render&lt;/a&gt; stayed the same, &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/speed-index/&quot; rel=&quot;noopener&quot;&gt;Speed Index&lt;/a&gt; slightly improved (273 ms, as images arrive faster, but don&#39;t take up a huge chunk of the pixel area), but the real metric which captures the difference is the &lt;a href=&quot;https://github.com/WPO-Foundation/webpagetest/blob/master/docs/Metrics/HeroElements.md&quot; rel=&quot;noopener&quot;&gt;Last Painted Hero&lt;/a&gt; metric, which improved by 1.2 seconds. 🎉🎉&lt;/p&gt;
&lt;p&gt;Of course, nothing captures the visual difference quite like a filmstrip comparison:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Screenshot of WebPageTest filmstrip comparison showing preloaded images are displayed about 1.5 seconds faster.&quot; decoding=&quot;async&quot; height=&quot;328&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/sXyZOvsNoAY0K2NRqT4U.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;figcaption&gt;The filmstrip shows that images arrive significantly faster when preloaded, resulting in a hugely-improved user experience.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;preload-and-lesspicturegreater&quot;&gt;Preload and &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#preload-and-lesspicturegreater&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re familiar with responsive images, you may be wondering &amp;quot;What about &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/picture&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;&lt;/a&gt;?&amp;quot;.&lt;/p&gt;
&lt;p&gt;The Web Performance Working Group is talking about adding a preload equivalent for &lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt;, but not the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element, which tackles the &lt;a href=&quot;https://web.dev/codelab-art-direction/&quot;&gt;&amp;quot;art direction&amp;quot;&lt;/a&gt; use-case.&lt;/p&gt;
&lt;p&gt;Why is this use-case being &amp;quot;neglected&amp;quot;?&lt;/p&gt;
&lt;p&gt;While there&#39;s interest in solving that use case as well, there are still a number of &lt;a href=&quot;https://calendar.perfplanet.com/2018/how-the-sausage-is-made-webperfwg-meeting-summary/&quot; rel=&quot;noopener&quot;&gt;technical issues to sort out&lt;/a&gt; which means that a solution here would have significant complexity. On top of that, it seems like for the most part, the use-case can be addressed today, even if in a hacky way (see below).&lt;/p&gt;
&lt;p&gt;Given that, the Web Performance WG decided to ship &lt;code&gt;srcset&lt;/code&gt; first and see if the demand for equivalent &lt;code&gt;picture&lt;/code&gt; support arises.&lt;/p&gt;
&lt;p&gt;If you do find yourself in a position to preload &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; you may be able to use the following technique as a workaround.&lt;/p&gt;
&lt;p&gt;Given the following scenario:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;small_cat.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(max-width: 400px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;medium_cat.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(max-width: 800px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;large_cat.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element&#39;s logic (or the image source selection logic, to be precise), would be to go over the &lt;code&gt;media&lt;/code&gt; attributes of the &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements in order, find the first one that matches, and use the attached resource.&lt;/p&gt;
&lt;p&gt;Because responsive preload has no notion of &amp;quot;order&amp;quot; or &amp;quot;first match&amp;quot;, the breakpoints need to be translated into something like:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;small_cat.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(max-width: 400px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;medium_cat.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(min-width: 400.1px) and (max-width: 800px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;large_cat.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(min-width: 800.1px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;preload-and-type&quot;&gt;Preload and &lt;code&gt;type&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#preload-and-type&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element also supports matching on the first &lt;code&gt;type&lt;/code&gt;, to allow different image formats to be provided and the browser to pick the first image format it supports. This use case is not currently supported with preload.&lt;/p&gt;
&lt;p&gt;For sites using this, avoiding preload is the best option, and instead having the &lt;a href=&quot;https://web.dev/preload-scanner/&quot;&gt;preload scanner&lt;/a&gt; pick these up from the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements instead. This is a best practice anyway, particular with the support of &lt;a href=&quot;https://web.dev/priority-hints/&quot;&gt;Priority Hints&lt;/a&gt; which allows the appropriate image to be prioritised in a better manner than preload alone.&lt;/p&gt;
&lt;h2 id=&quot;effects-on-largest-contentful-paint-lcp&quot;&gt;Effects on Largest Contentful Paint (LCP) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#effects-on-largest-contentful-paint-lcp&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since images can be &lt;a href=&quot;https://web.dev/lcp/#what-elements-are-considered&quot;&gt;candidates for Largest Contentful Paint (LCP)&lt;/a&gt;, preloading them may improve your website&#39;s LCP. Using the techniques above, you can also ensure that your responsive images will load more quickly.&lt;/p&gt;
&lt;p&gt;Regardless of whether the image you&#39;re preloading is responsive, be aware that preloads work especially well when the image resource isn&#39;t discoverable in the initial markup payload. For websites that send complete markup from the server, you may not realize a huge benefit. However, if your website renders markup on the client—which sidesteps the browser&#39;s &lt;a href=&quot;https://web.dev/preload-scanner/&quot;&gt;preload scanner&lt;/a&gt;—there&#39;s an opportunity on the table to preload potential LCP images to improve performance.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-responsive-images/#summary&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Responsive image preload gives us new and exciting possibilities to preload responsive images in ways that were previously only possible using hacks. It&#39;s an important new addition to the speed-conscious developer&#39;s toolbox and enables us to make sure the important images we want to get in front of our users as soon as possible will be there when we need them.&lt;/p&gt;
</content>
    <author>
      <name>Yoav Weiss</name>
    </author><author>
      <name>Barry Pollard</name>
    </author>
  </entry>
</feed>
