Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazyload images and iframes #3752

Open
wants to merge 22 commits into
base: master
from
Open
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

176 source
@@ -2795,6 +2795,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<li><dfn data-x="concept-request-method" data-x-href="https://fetch.spec.whatwg.org/#concept-request-method">method</dfn></li>
<li><dfn data-x="concept-request-header-list" data-x-href="https://fetch.spec.whatwg.org/#concept-request-header-list">header list</dfn></li>
<li><dfn data-x="concept-request-body" data-x-href="https://fetch.spec.whatwg.org/#concept-request-body">body</dfn></li>
<li><dfn data-x="concept-request-add-range-header" data-x-href="https://fetch.spec.whatwg.org/#concept-request-add-range-header">add a range header</dfn></li>
<li><dfn data-x="concept-request-client" data-x-href="https://fetch.spec.whatwg.org/#concept-request-client">client</dfn></li>
<li><dfn data-x="concept-request-current-url" data-x-href="https://fetch.spec.whatwg.org/#concept-request-current-url">current URL</dfn></li>
<li><dfn data-x="concept-request-reserved-client" data-x-href="https://fetch.spec.whatwg.org/#concept-request-reserved-client">reserved client</dfn></li>
@@ -7211,6 +7212,42 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<code>HTMLOrSVGElement</code> must set the <span>[[CryptographicNonce]]</span> slot on the copy
to the value of the slot on the element being cloned.</p>

<h4>Lazy loading attributes</h4>

<p>A <dfn>lazy loading attribute</dfn> is an <span>enumerated attribute</span>. The following
table lists the keywords and states for the attribute &mdash; the keywords in the left column map
to the states in the cell in the second column on the same row as the keyword.</p>

<p>The attribute provides a hint to the user agent to aid in deciding whether to load an element
immediately or to defer loading until the element will be viewable, according to the attribute's
current state.</p>

<table>
<thead>
<tr>
<th>Keyword
<th>State
<th>Description
<tbody>
<tr>
<td><dfn><code data-x="attr-loading-lazy">lazy</code></dfn>
<td><dfn data-x="attr-loading-lazy-state">Lazy</dfn>
<td>Indicates a strong preference to defer fetching the element's resource until it will be
viewable.
<tr>
<td><dfn><code data-x="attr-loading-eager">eager</code></dfn>
<td><dfn data-x="attr-loading-eager-state">Eager</dfn>
<td>Indicates the element's resource must be fetched immediately, regardless of viewability.

This comment has been minimized.

Copy link
@zcorpan

zcorpan Mar 6, 2019

Member

Don't use must here

This comment has been minimized.

Copy link
@ahmadawais

ahmadawais Apr 8, 2019

Suggested change
<td>Indicates the element's resource must be fetched immediately, regardless of viewability.
<td>Indicates the element's resource will be fetched immediately, regardless of viewability.

This comment has been minimized.

Copy link
@domfarolino

domfarolino Jun 11, 2019

Member

Hmm, is the reason we can't use must, because even before this change, UAs are not "required" to fetch/support images

This comment has been minimized.

Copy link
@zcorpan

zcorpan Jun 12, 2019

Member

No. The reason is that this text is supposed to be informative, and the actual requirement should be part of the processing model. We don't want duplicate requirements for the same thing as that can be conflicting in subtle ways.

<tr>
<td><dfn><code data-x="attr-loading-auto">auto</code></dfn>
<td><dfn data-x="attr-loading-auto-state">Auto</dfn>
<td>Indicates that the user agent may determine the fetching strategy (the default).

This comment has been minimized.

Copy link
@zcorpan

zcorpan Mar 6, 2019

Member

Don't use may here

This comment has been minimized.

Copy link
@ahmadawais

ahmadawais Apr 8, 2019

Suggested change
<td>Indicates that the user agent may determine the fetching strategy (the default).
<td>Indicates that the user agent will determine the fetching strategy (the default).

This comment has been minimized.

Copy link
@domfarolino

domfarolino Jun 12, 2019

Member

Can we use must here, since I think the intent is for all images/iframes' to be either lazy-loaded or eagerly-loaded (therefore auto is just an intermediate value where the UA has to pick one or the other)?

This comment has been minimized.

Copy link
@zcorpan

zcorpan Jun 12, 2019

Member

No, this table should just be non-normative.

For iframe, the normative text is

If the element's loading attribute is in the Lazy or Auto states, and the element's CSS layout box does not intersect the viewport, then running these steps may be deferred until such intersection occurs.

For img, the normative text is the first paragraph in #when-to-obtain-images

</table>

<p>The attribute's <i data-x="missing value default">missing value default</i> and <i
data-x="invalid value default">invalid value default</i> are both the <span
data-x="attr-loading-auto-state">Auto</span> state.</p>


<h3 split-filename="common-dom-interfaces">Common DOM interfaces</h3>

@@ -25711,6 +25748,7 @@ interface <dfn>HTMLSourceElement</dfn> : <span>HTMLElement</span> {
<dd><code data-x="attr-dim-height">height</code></dd>
<dd><code data-x="attr-img-referrerpolicy">referrerpolicy</code></dd>
<dd><code data-x="attr-img-decoding">decoding</code></dd>
<dd><code data-x="attr-img-loading">loading</code></dd>
<dt><span data-x="concept-element-dom">DOM interface</span>:</dt>
<dd w-nodev>
<pre><code class="idl" data-x="">[Exposed=Window,
@@ -25732,6 +25770,7 @@ interface <dfn>HTMLImageElement</dfn> : <span>HTMLElement</span> {
readonly attribute USVString <span data-x="dom-img-currentSrc">currentSrc</span>;
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-img-referrerPolicy">referrerPolicy</span>;
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-img-decoding">decoding</span>;
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-img-loading">loading</span>;

Promise&lt;void&gt; <span data-x="dom-img-decode">decode</span>();
};</code></pre>
@@ -25807,6 +25846,10 @@ interface <dfn>HTMLImageElement</dfn> : <span>HTMLElement</span> {
default">missing value default</i> and <i data-x="invalid value default">invalid value
default</i> are both the <span data-x="attr-img-decoding-auto-state">auto</span> state.</p>

<p>The <dfn data-x="attr-img-loading"><code>loading</code></dfn> attribute is a <span>lazy
loading attribute</span>. Its purpose is to indicate the policy for loading images that are
outside the viewport.

<hr>

<p>The <code>img</code> element must not be used as a layout tool. In particular, <code>img</code>
@@ -25997,6 +26040,10 @@ interface <dfn>HTMLImageElement</dfn> : <span>HTMLElement</span> {
<span>reflect</span> the <code data-x="attr-img-decoding">decoding</code> content
attribute, <span>limited to only known values</span>.

<p>The <dfn><code data-x="dom-img-loading">loading</code></dfn> IDL attribute must
<span>reflect</span> the <code data-x="attr-img-loading">loading</code> content
attribute, <span>limited to only known values</span>.

</div>

<dl class="domintro">
@@ -26044,14 +26091,6 @@ interface <dfn>HTMLImageElement</dfn> : <span>HTMLElement</span> {

</dd>

<dt><var>image</var> . <code subdfn data-x="dom-img-decoding">decoding</code></dt>

<dd>

<p>Returns the <span>image decoding hint</span> set for this image.</p>

</dd>

<dt><var>image</var> . <code subdfn data-x="dom-img-decode">decode</code>()</dt>

<dd>
@@ -26299,6 +26338,9 @@ img.decode().then(() => {
element</span> given <var>document</var>, <code>img</code>, and the <span>HTML
namespace</span>.</p></li>

<li><p>Set <var>img</var>'s <code data-x="attr-img-loading">loading</code> attribute to the <span
data-x="attr-loading-eager">eager</span> state.</p></li>

<li><p>If <var>width</var> is given, then <span data-x="concept-element-attributes-set-value">set
an attribute value</span> for <var>img</var> using "<code data-x="attr-dim-width">width</code>"
and <var>width</var>.</p></li>
@@ -27257,7 +27299,20 @@ was an English &lt;a href="/wiki/Music_hall">music hall&lt;/a> singer, ...</code
<p>In a <span>browsing context</span> where <span data-x="concept-bc-noscript">scripting is
This conversation was marked as resolved by bengreenstein

This comment has been minimized.

Copy link
@domenic

domenic Dec 18, 2018

Member

"the CSS boxes those" -> "the CSS boxes of those"

This comment has been minimized.

Copy link
@yoavweiss

yoavweiss Mar 28, 2019

Collaborator

"CSS boxes of those images intersect" feels a bit handwavy. You probably want to link from that to relevant definitions

disabled</span>, user agents may obtain images immediately or on demand. In a <span>browsing
context</span> where <span data-x="concept-bc-noscript">scripting is enabled</span>, user agents

This comment has been minimized.

Copy link
@domenic

domenic Apr 1, 2019

Member

This isn't a dfn; it should be a link to another spec's definition. See https://github.com/whatwg/wattsi/blob/master/Syntax.md#cross-specification-cross-references

must obtain images immediately.</p>
must obtain images immediately when an image and the <span>viewport</span> intersect
according to
<dfn data-x-href="https://w3c.github.io/IntersectionObserver/#calculate-intersection-rect-algo">
compute the intersection of a target element and the root</dfn>,
or when the corresponding <code>img</code> element's <code
data-x="attr-img-loading">loading</code> attribute is in the <span
data-x="attr-loading-eager-state">Eager</span> state. Otherwise, they may obtain images immediately
or on demand, using the current state of the corresponding <code>img</code> element's <code
data-x="attr-img-loading">loading</code> attribute to guide the decision.</p>

<p class="note">The above requirements imply that if the author changes the <code
data-x="attr-img-loading">loading</code> attribute to be in the <span
data-x="attr-loading-eager-state">Eager</span> state, and the image has not already been obtained,
it will immediately be obtained.</p>

<p>A user agent that obtains images immediately must synchronously
<span>update the image data</span> of an <code>img</code> element,
@@ -27272,6 +27327,83 @@ was an English &lt;a href="/wiki/Music_hall">music hall&lt;/a> singer, ...</code
obtains images on demand, the <code>img</code> element's <span>current request</span>'s <span
data-x="img-req-state">state</span> must return to <span data-x="img-none">unavailable</span>.</p>
This conversation was marked as resolved by domenic

This comment has been minimized.

Copy link
@domenic

domenic Dec 20, 2018

Member

What if the element does use srcset or picture? What are selected source and selected pixel density set to? In the next step you parse selected source, so your code will "crash" in that case currently.


<p>If the <code>img</code> element's <code data-x="attr-img-loading">loading</code> attribute is

This comment has been minimized.

Copy link
@JoshTumath

JoshTumath Apr 13, 2019

To save needing to fetch image metadata, could we first check if the width and height attributes are specified and assume the image dimensions from that?

This comment has been minimized.

Copy link
@mikesherov

mikesherov Apr 13, 2019

The usage of may here only intends to allow retrieval of this metadata and not explicitly forbid it. There are proposals like https://github.com/WICG/intrinsicsize-attribute and h specifier for srcset that also attempt to address the issue, so I think the intent here is to solve the lazyload problem separate from the “discover the intrinsic size of an image” problem.

This comment has been minimized.

Copy link
@bengreenstein

bengreenstein Jun 11, 2019

Author

Yes, that's the intent.

not in the <span data-x="attr-loading-eager-state">Eager</span> state, the user agent may
immediately <dfn>fetch image metadata</dfn> for an <code>img</code> element <var>el</var> by
This conversation was marked as resolved by bengreenstein

This comment has been minimized.

Copy link
@domenic

domenic Dec 18, 2018

Member

This should just be element's node document's relevant settings object; see https://whatpr.org/html/3752/images.html#updating-the-image-data step 19.

running the following steps:</p>

<ol>
<li>
<p>If the element's <span>node document</span> is not the <span>active document</span>,
then:</p>

<ol>
<li><p>Continue running this algorithm <span>in parallel</span>.</p></li>

<li><p>Wait until the element's <span>node document</span> is the <span>active document</span>.</p></li>

<li><p>If another instance of this algorithm for this <code>img</code> element was started after this instance
(even if it aborted and is no longer running), then return.</p></li>

<li><p><span>Queue a microtask</span> to continue this algorithm.</p></li>
</ol>
This conversation was marked as resolved by bengreenstein

This comment has been minimized.

Copy link
@domenic

domenic Dec 18, 2018

Member

"should be rejected" is not very precise. Maybe "must not be used as metadata"?

</li>
This conversation was marked as resolved by domenic

This comment has been minimized.

Copy link
@domenic

domenic Dec 18, 2018

Member

"it should be used and not refetched" needs to be formalized, in terms of the "list of available images". In particular it seems like you'd want a nested series of steps that creates a cache key and stores it in the list. Cf. steps 6.2 and other usages of "key" in the "update the image data" algorithm.

This comment has been minimized.

Copy link
@bengreenstein

bengreenstein Dec 19, 2018

Author

6.2 defines the key and the bottom of step 24 actually adds the image to the list of available images. Are any other steps relevant in your opinion? Are all of them? I'm not sure how much should be included.

This comment has been minimized.

Copy link
@domenic

domenic Dec 19, 2018

Member

The point is to get it into the list of available images, so I think those two steps suffice. Once it's put in there, future fetches will reuse the result, which is what the currently-vague text is aiming for.


<li><p>Let <var>selected source</var> and <var>selected pixel density</var> be the URL
and pixel density that result from <span data-x="select an image source">selecting an image
source</span>, given <var>el</var>.</p></li>

<li><p>Let <var>document</var> be <var>el</var>'s <span>node document</span>.</p></li>

<li><p><span data-x="parse a url">Parse</span> <var>selected source</var>, relative to
<var>document</var>. If that is not successful, return. Otherwise, let <var>urlString</var> be
the <span>resulting URL string</span>.</p></li>

This conversation was marked as resolved by domenic

This comment has been minimized.

Copy link
@domenic

domenic Dec 20, 2018

Member

You want to remove "it should be used and not refected" since that's not clear.

This comment has been minimized.

Copy link
@bengreenstein

bengreenstein Dec 20, 2018

Author

What do you think I should say it it's place or do you think I should delete the entire sentence?

This comment has been minimized.

Copy link
@domenic

domenic Dec 20, 2018

Member

See the below comment. You shouldn't have an imprecise sentence, so in that sense delete it. But portions of it need to be preserved because right now the substeps seem to run regardless.

<li><p>Let <var>corsState</var> be the current state of <var>el</var>'s <code
data-x="attr-img-crossorigin">crossorigin</code> content attribute.</p></li>
This conversation was marked as resolved by domenic

This comment has been minimized.

Copy link
@domenic

domenic Dec 20, 2018

Member

These steps should only run "If the full image is returned by this fetch". Probably also you need a guard like "If the resource type and data corresponds to a supported image format, as described below" (see step 24 of updating the image data").


<li><p>Let <var>request</var> be the result of <span data-x="create a potential-CORS
request">creating a potential-CORS request</span> given <var>urlString</var>, "<code
data-x="">image</code>", and <var>corsState</var>.</p></li>

<li><p>Set <var>request</var>'s <span data-x="concept-request-client">client</span> to
<var>document</var>'s <span>relevant settings object</span>.</p></li>

<li><p>If <var>el</var> <span data-x="use srcset or picture">uses <code>srcset</code> or
<code>picture</code></span>, then set <var>request</var>'s <span
data-x="concept-request-initiator">initiator</span> to "<code
data-x="">imageset</code>".</p></li>

<li><p>Set <var>request</var>'s <span data-x="concept-request-referrer-policy">referrer
policy</span> to the current state of <var>el</var>'s <code
data-x="attr-img-referrerpolicy">referrerpolicy</code> attribute.</p></li>

This conversation was marked as resolved by domfarolino

This comment has been minimized.

Copy link
@JoshTumath

JoshTumath Apr 13, 2019

Typo 🙂

Suggested change
user agent determines is reasonable to retrieve metatdata.</p></li>
user agent determines is reasonable to retrieve metadata.</p></li>

This comment has been minimized.

Copy link
@rajendrant

rajendrant May 28, 2019

@bengreenstein This typo is not yet fixed.

<li><p><span data-x="concept-request-add-range-header">Add a range header</span> to
<var>request</var> starting at byte 0 and ending with as many bytes of the image file as the
user agent determines is reasonable to retrieve metadata.</p></li>

This comment has been minimized.

Copy link
@jakearchibald

jakearchibald Apr 17, 2019

Collaborator

What if this data arrives later than the full image, and the two results have different dimensions? It feels like the ordering here needs to be a 'must' not a 'may'.

This comment has been minimized.

Copy link
@othermaciej

othermaciej Apr 17, 2019

I think the important must should be that the user agent must ignore the results of this load if the actual image load has already determined a size. It's probably more good than bad if the image load has started but not gotten enough data to determine a size; and it doesn't matter if the load has already finished but has not been processed yet for some reason, if the UA has already determined the size the real way, the result should be ignored.

This comment has been minimized.

Copy link
@jakearchibald

jakearchibald Apr 25, 2019

Collaborator

I agree this is the most sensible thing to do. Just needs to be in the spec.

<li>
<p><span data-x="concept-fetch">Fetch</span> <var>request</var>, and, if the actual image load
has not already determined a size, use the metadata contained in the response as appropriate to
lay out the image. The user agent may cancel this fetch if the <span>update the image data
</span> algorithm for <var>el</var> begins its own independent fetch. Responses that begin after
byte 0 must be ignored.</p>

<p>If the full image is returned by the fetch, and the resource type and data corresponds to a
supported image format <a href="#img-determine-type">as described below</a>, then in addition to
using the result as metadata, perform the following steps:</p>

<ol>
<li><p>Let <var>key</var> be a tuple consisting of <var>urlString</var>, <var>corsState</var>,
and, if <var>corsState</var> is not <span data-x="attr-crossorigin-none">No CORS</span>,
<var>document</var>'s <span>origin</span>.</p></li>

<li><p>Add the image to the <span>list of available images</span> using the key <var>key</var>,
with the <span>ignore higher-layer caching</span> flag set.</p></li>
</ol>
</li>
</ol>


<h6>Reacting to DOM mutations</h6>

@@ -29500,6 +29632,7 @@ href="?audio">audio&lt;/a> test instead.)&lt;/p></code></pre>
<dd><code data-x="attr-dim-width">width</code></dd>
<dd><code data-x="attr-dim-height">height</code></dd>
<dd><code data-x="attr-iframe-referrerpolicy">referrerpolicy</code></dd>
<dd><code data-x="attr-iframe-loading">loading</code></dd>
<dt><span data-x="concept-element-dom">DOM interface</span>:</dt>
<dd w-nodev>
<pre><code class="idl" data-x="">[Exposed=Window,
@@ -29515,6 +29648,7 @@ interface <dfn>HTMLIFrameElement</dfn> : <span>HTMLElement</span> {
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-dim-width">width</span>;
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-dim-height">height</span>;
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-iframe-referrerPolicy">referrerPolicy</span>;
[<span>CEReactions</span>] attribute DOMString <span data-x="dom-iframe-loading">loading</span>;
readonly attribute <span>Document</span>? <span data-x="dom-iframe-contentDocument">contentDocument</span>;
readonly attribute <span>WindowProxy</span>? <span data-x="dom-iframe-contentWindow">contentWindow</span>;
<span>Document</span>? <span data-x="dom-media-getSVGDocument">getSVGDocument</span>();
@@ -29713,7 +29847,11 @@ interface <dfn>HTMLIFrameElement</dfn> : <span>HTMLElement</span> {
<dt>Otherwise</dt>

<dd><p>Run the <span>otherwise steps for <code>iframe</code> or <code>frame</code>
elements</span>.</p></dd>
elements</span>. If the element's <code data-x="attr-iframe-loading">loading</code> attribute
is in the <span data-x="attr-loading-lazy-state">Lazy</span> or <span
data-x="attr-loading-auto-state">Auto</span> states, and the element's CSS layout box does not
intersect the <span>viewport</span>, then running these steps may be deferred until such
intersection occurs.</p></dd>

</dl>

@@ -30119,6 +30257,12 @@ interface <dfn>HTMLIFrameElement</dfn> : <span>HTMLElement</span> {
used when <span data-x="process the iframe attributes">processing the <code>iframe</code>
attributes</span>. <ref spec=REFERRERPOLICY></p>

<hr> <!-- LAZYLOAD ATTRIBUTE -->

<p>The <dfn data-x="attr-iframe-loading"><code>loading</code></dfn> attribute is a
<span>lazy loading attribute</span>. It indicates the policy for loading <code>iframe</code>
elements that are outside the viewport.</p>

<hr> <!-- FALLBACK -->

<p>Descendants of <code>iframe</code> elements represent nothing. (In legacy user agents that do
@@ -30157,6 +30301,10 @@ interface <dfn>HTMLIFrameElement</dfn> : <span>HTMLElement</span> {
must <span>reflect</span> the <code data-x="attr-iframe-referrerpolicy">referrerpolicy</code>
content attribute, <span>limited to only known values</span>.</p>

<p>The <dfn><code data-x="dom-iframe-loading">loading</code></dfn> IDL attribute must
<span>reflect</span> the <code data-x="attr-iframe-loading">loading</code> content
attribute, <span>limited to only known values</span>.</p>

<p>The <dfn><code data-x="dom-iframe-contentDocument">contentDocument</code></dfn> IDL attribute,
on getting, must return the <code>iframe</code> element's <span
data-x="concept-bcc-content-document">content document</span>.</p>
@@ -118961,6 +119109,14 @@ interface <dfn>External</dfn> {
<td> "<code data-x="attr-img-decoding-sync">sync</code>";
This conversation was marked as resolved by bengreenstein

This comment has been minimized.

Copy link
@jakearchibald

jakearchibald Apr 17, 2019

Collaborator

Needs updating?

"<code data-x="attr-img-decoding-async">async</code>";
"<code data-x="attr-img-decoding-auto">auto</code>"
<tr>
<th> <code data-x="">loading</code>
<td> <code data-x="attr-img-loading">img</code>;
<code data-x="attr-iframe-loading">iframe</code>
<td> Hint to use when determining loading deferral
<td> "<code data-x="attr-loading-lazy">lazy</code>";
"<code data-x="attr-loading-eager">eager</code>";
"<code data-x="attr-loading-auto">auto</code>"
<tr>
<th> <code data-x="">default</code>
<td> <code data-x="attr-track-default">track</code>
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.