diff --git a/source b/source index f9de26f7166..a6ec979f2c2 100644 --- a/source +++ b/source @@ -7177,6 +7177,37 @@ 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 — 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 directs the user agent to fetch a resource immediately or to defer fetching until + some conditions associated with the element are met, 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>Used to defer fetching a resource until some conditions are met. + <tr> + <td><dfn><code data-x="attr-loading-eager">eager</code></dfn> + <td><dfn data-x="attr-loading-eager-state">Eager</dfn> + <td>Used to fetch a resource immediately; the default state. + </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-eager-state">Eager</span> state.</p> + <h3 split-filename="common-dom-interfaces">Common DOM interfaces</h3> @@ -26338,6 +26369,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-accessibility-considerations">Accessibility considerations</span>:</dt> <dd>If the element has a non-empty <code data-x="attr-img-alt">alt</code> attribute: <a @@ -26368,6 +26400,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<void> <span data-x="dom-img-decode">decode</span>(); };</code></pre> @@ -26443,6 +26476,40 @@ 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.</p> + + <div class="example"> +<pre><code class="html" data-x=""><img src="1.jpeg" alt="1"> +<img src="2.jpeg" loading=eager alt="2"> +<img src="3.jpeg" loading=lazy alt="3"> +<div id=very-large></div> <!-- Everything after this div is below the viewport --> +<img src="4.jpeg" alt="4"> +<img src="5.jpeg" loading=lazy alt="5"></code></pre> + + <p>In the example above, the images load as follows:</p> + + <dl class="switch"> + <dt><code data-x="">1.jpeg</code>, <code data-x="">2.jpeg</code>, + <code data-x="">4.jpeg</code></dt> + <dd><p>The images load eagerly and delay the window's load event.</p></dd> + + <dt><code data-x="">3.jpeg</code></dt> + <dd><p>The image loads when layout is known, due to being in the viewport, however it does not + delay the window's load event.</p></dd> + + <dt><code data-x="">5.jpeg</code></dt> + <dd><p>The image loads only once scrolled into the viewport, and does not delay the window's + load event.</p></dd> + </dl> + + <p class="note">Developers are encouraged to specify an intrinsic aspect ratio via <code + data-x="attr-dim-width">width</code> and <code data-x="attr-dim-height">height</code> attributes + on lazy loaded images, even if CSS sets the image's width and height properties, to prevent the + page layout from shifting around after the image loads.</p> + </div> + <hr> <p>The <code>img</code> element must not be used as a layout tool. In particular, <code>img</code> @@ -26631,7 +26698,11 @@ interface <dfn>HTMLImageElement</dfn> : <span>HTMLElement</span> { <p>The <dfn><code data-x="dom-img-decoding">decoding</code></dfn> IDL attribute must <span>reflect</span> the <code data-x="attr-img-decoding">decoding</code> content - attribute, <span>limited to only known values</span>. + attribute, <span>limited to only known values</span>.</p> + + <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>.</p> </div> @@ -28028,6 +28099,37 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...</code <h6>Updating the image data</h6> + <p>The <dfn>will lazy load image steps</dfn>, given an <code>img</code> element <var>img</var>, + are as follows:</p> + + <ol> + <li> + <p>If <span data-x="concept-n-noscript">scripting is disabled</span> for <var>img</var>, return + false.</p> + + <p class="note">This is an anti-tracking measure, because if a user agent supported lazy loading + when scripting is disabled, it would still be possible for a site to track a user's approximate + scroll position throughout a session, by strategically placing images in a page's markup such + that a server can track how many images are requested and when.</p> + </li> + + <li> + <p>If <var>img</var>'s <span>lazy loading attribute</span> is in the <span + data-x="attr-loading-lazy-state">Lazy</span> state, <var>img</var> does not <span>intersect the + viewport</span>, and <var>img</var> is not about to <span>intersect the viewport</span>, then + return true.</p> + + <p class="note">This allows for fetching the image during scrolling, when it does not, but is + about to intersect the viewport.</p> + </li> + + <li><p>Return false.</p></li> + </ol> + + <p class="note">This algorithm cannot be called from steps running <span>in parallel</span>. If + a user agent needs to call this algorithm from steps running <span>in parallel</span>, it needs to + <span data-x="queue a task">queue</span> a task to do so.</p> + <p>When the user agent is to <dfn>update the image data</dfn> of an <code>img</code> element, optionally with the <i>restart animations</i> flag set, it must run the following steps:</p> @@ -28124,16 +28226,12 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...</code </ol> </li> - <li><p><span>Await a stable state</span>, allowing the <span - data-x="concept-task">task</span> that invoked this algorithm to continue. - The <span>synchronous - section</span> consists of all the remaining steps of this algorithm until the algorithm says the - <span>synchronous section</span> has ended. (Steps in <span data-x="synchronous - section">synchronous sections</span> are marked with ⌛.)</p></li> + <li><p><span>Queue a microtask</span> to perform the rest of this algorithm, allowing the <span + data-x="concept-task">task</span> that invoked this algorithm to continue.</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> + <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> <p class="note">Only the last instance takes effect, to avoid multiple requests when, for example, the <code data-x="attr-img-src">src</code>, <code data-x="attr-img-srcset">srcset</code>, @@ -28141,22 +28239,22 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...</code succession.</p> </li> - <li><p>⌛ Let <var>selected source</var> and <var>selected pixel density</var> be the URL - and pixel density that results from <span data-x="select an image source">selecting an image - source</span>, respectively.</p></li> + <li><p>Let <var>selected source</var> and <var>selected pixel density</var> be the URL and pixel + density that results from <span data-x="select an image source">selecting an image source</span>, + respectively.</p></li> <li> - <p>⌛ If <var>selected source</var> is null, then:</p> + <p>If <var>selected source</var> is null, then:</p> <ol> - <li><p>⌛ Set the <span>current request</span>'s <span - data-x="img-req-state">state</span> to <span data-x="img-error">broken</span>, <span>abort the - image request</span> for the <span>current request</span> and the <span>pending request</span>, - and set <span>pending request</span> to null.</p></li> + <li><p>Set the <span>current request</span>'s <span data-x="img-req-state">state</span> to + <span data-x="img-error">broken</span>, <span>abort the image request</span> for the + <span>current request</span> and the <span>pending request</span>, and set <span>pending + request</span> to null.</p></li> <li> - <p>⌛ <span>Queue an element task</span> on the <span>DOM manipulation task - source</span> given the <code>img</code> element and the following steps:</p> + <p><span>Queue an element task</span> on the <span>DOM manipulation task source</span> given + the <code>img</code> element and the following steps:</p> <ol> <li><p>Change the <span>current request</span>'s <span data-x="img-req-url">current @@ -28169,26 +28267,26 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...</code </ol> </li> - <li><p>⌛ Return.</p></li> + <li><p>Return.</p></li> </ol> </li> <li> - <p>⌛ <span data-x="parse a url">Parse</span> <var>selected source</var>, relative to the - element's <span>node document</span>, and let <var>urlString</var> be the <span>resulting URL + <p><span data-x="parse a url">Parse</span> <var>selected source</var>, relative to the element's + <span>node document</span>, and let <var>urlString</var> be the <span>resulting URL string</span>. If that is not successful, then:</p> <ol> - <li><p>⌛ <span>Abort the image request</span> for the <span>current request</span> and - the <span>pending request</span>.</p></li> + <li><p><span>Abort the image request</span> for the <span>current request</span> and the + <span>pending request</span>.</p></li> - <li><p>⌛ Set the <span>current request</span>'s <span - data-x="img-req-state">state</span> to <span data-x="img-error">broken</span>.</p></li> + <li><p>Set the <span>current request</span>'s <span data-x="img-req-state">state</span> to + <span data-x="img-error">broken</span>.</p></li> - <li><p>⌛ Set <span>pending request</span> to null.</p></li> + <li><p>Set <span>pending request</span> to null.</p></li> <li> - <p>⌛ <span>Queue an element task</span> on the <span>DOM manipulation task + <p><span>Queue an element task</span> on the <span>DOM manipulation task source</span> given the <code>img</code> element and the following steps:</p> <ol> @@ -28200,62 +28298,83 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...</code </ol> </li> - <li><p>⌛ Return.</p></li> + <li><p>Return.</p></li> </ol> </li> - <li><p>⌛ If the <span>pending request</span> is not null and <var>urlString</var> is the - same as the <span>pending request</span>'s <span data-x="img-req-url">current URL</span>, then + <li><p>If the <span>pending request</span> is not null and <var>urlString</var> is the same as + the <span>pending request</span>'s <span data-x="img-req-url">current URL</span>, then return.</p></li> - <li><p>⌛ If <var>urlString</var> is the same as the <span>current request</span>'s <span + <li><p>If <var>urlString</var> is the same as the <span>current request</span>'s <span data-x="img-req-url">current URL</span> and <span>current request</span>'s <span data-x="img-req-state">state</span> is <span data-x="img-inc">partially available</span>, then <span>abort the image request</span> for the <span>pending request</span>, <span>queue a task</span> to <span>restart the animation</span> if <i>restart animation</i> is set, and return.</p></li> - <li><p>⌛ If the <span>pending request</span> is not null, then <span>abort the image - request</span> for the <span>pending request</span>.</p></li> + <li><p>If the <span>pending request</span> is not null, then <span>abort the image request</span> + for the <span>pending request</span>.</p></li> - <li><p>⌛ Set <var>image request</var> to a new <span>image request</span> whose <span + <li><p>Set <var>image request</var> to a new <span>image request</span> whose <span data-x="img-req-url">current URL</span> is <var>urlString</var>.</p></li> - <li><p>⌛ If <span>current request</span>'s <span data-x="img-req-state">state</span> is - <span data-x="img-none">unavailable</span> or <span data-x="img-error">broken</span>, then set - the <span>current request</span> to <var>image request</var>. Otherwise, set the <span>pending + <li><p>If <span>current request</span>'s <span data-x="img-req-state">state</span> is <span + data-x="img-none">unavailable</span> or <span data-x="img-error">broken</span>, then set the + <span>current request</span> to <var>image request</var>. Otherwise, set the <span>pending request</span> to <var>image request</var>.</p></li> - <li><p>⌛ Let <var>request</var> be the result of <span data-x="create a potential-CORS + <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 the current state of the element's <code data-x="attr-img-crossorigin">crossorigin</code> content attribute.</p></li> - <li><p>⌛ Set <var>request</var>'s <span data-x="concept-request-client">client</span> to - the element's <span>node document</span>'s <span>relevant settings object</span>.</p></li> + <li><p>Set <var>request</var>'s <span data-x="concept-request-client">client</span> to the + element's <span>node document</span>'s <span>relevant settings object</span>.</p></li> - <li><p>⌛ If the element <span data-x="use srcset or picture">uses <code>srcset</code> or + <li><p>If the element <span data-x="use srcset or picture">uses <code>srcset</code> or <code>picture</code></span>, 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 + <li><p>Set <var>request</var>'s <span data-x="concept-request-referrer-policy">referrer policy</span> to the current state of the element's <code data-x="attr-img-referrerpolicy">referrerpolicy</code> attribute.</p></li> + <li><p>Let <var>delay load event</var> be true if the <code>img</code>'s <span>lazy loading + attribute</span> is in the <span data-x="attr-loading-eager-state">Eager</span> state, or if + <span data-x="concept-n-noscript">scripting is disabled</span> for the <code>img</code>, and + false otherwise.</p></li> + + <li> + <p>If the <span>will lazy load image steps</span> given the <code>img</code> return true, + then:</p> + + <ol> + <li><p>Continue running this algorithm <span>in parallel</span>.</p></li> + + <li><p>Wait until the <span>will lazy load image steps</span> no longer return true, given the + <code>img</code>.</p></li> + + <li><p><span>Queue a task</span> to continue running the rest of this algorithm.</p></li> + </ol> + </li> + <li> <!--FETCH--> - <p>⌛ <span data-x="concept-fetch">Fetch</span> <var>request</var>. Let this instance of - the <span data-x="concept-fetch">fetching</span> algorithm be associated with <var>image - request</var>.<!-- TODO "Interaction with the Preload Scanner" from the picture spec --></p> + <p><span data-x="concept-fetch">Fetch</span> <var>request</var>. Let this instance of the <span + data-x="concept-fetch">fetching</span> algorithm be associated with <var>image request</var>. + <!-- TODO "Interaction with the Preload Scanner" from the picture spec --></p> - <p>The resource obtained in this fashion, if any, is <var>image request</var>'s <span data-x="img-req-data">image data</span>. - It can be either <span>CORS-same-origin</span> or <span>CORS-cross-origin</span>; this affects - the <span>origin</span> of the image itself (e.g. when used on a <code>canvas</code>).</p> + <p>The resource obtained in this fashion, if any, is <var>image request</var>'s <span + data-x="img-req-data">image data</span>. It can be either <span>CORS-same-origin</span> or + <span>CORS-cross-origin</span>; this affects the <span>origin</span> of the image itself (e.g. + when used on a <code>canvas</code>).</p> <!-- same text in <input type=image> section and similar text elsewhere --> - <p>Fetching the image must <span>delay the load event</span> of the element's <span>node document</span> until the - <span data-x="concept-task">task</span> that is <span data-x="queue a task">queued</span> by the + <p>When <var>delay load event</var> is true, fetching the image must <span>delay the load + event</span> of the element's <span>node document</span> until the <span + data-x="concept-task">task</span> that is <span data-x="queue a task">queued</span> by the <span>networking task source</span> once the resource has been fetched (<a href="#img-load">defined below</a>) has been run. <!--TODO or the fetch was aborted, presumably --></p> @@ -28268,8 +28387,8 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...</code compatible with existing Web content.</p> </li> - <li><p>End the <span>synchronous section</span>, continuing the remaining steps <span>in - parallel</span>, but without missing any data from fetching.</p></li> + <li><p>Continue the remaining steps <span>in parallel</span>, but without missing any data from + fetching.</p></li> <li> @@ -32358,10 +32477,6 @@ interface <dfn>HTMLVideoElement</dfn> : <span>HTMLMediaElement</span> { <p>The <span>default object size</span> is a width of 300 <span data-x="'px'">CSS pixels</span> and a height of 150 <span data-x="'px'">CSS pixels</span>. <ref spec=CSSIMAGES></p> - <p>A <code>video</code> element is said to <dfn>intersect the viewport</dfn> when it is - <span>being rendered</span> and its associated CSS layout box intersects the - <span>viewport</span>.</p> - <hr> <p>User agents should provide controls to enable or disable the display of closed captions, audio @@ -35076,10 +35191,6 @@ interface <dfn>MediaError</dfn> { <p>The user agent may run the following substeps:</p> - <p class="note">This specification doesn't define the precise timing for when the intersection - is tested, but it is suggested that the timing match that of the Intersection Observer API. - <ref spec=INTERSECTIONOBSERVER></p> - <ol> <li>Set the <code data-x="dom-media-paused">paused</code> attribute to false.</li> @@ -35104,10 +35215,6 @@ interface <dfn>MediaError</dfn> { true and the <code data-x="attr-media-autoplay">autoplay</code> attribute is still specified, run the following substeps:</p> - <p class="note">This specification doesn't define the precise timing for when the intersection - is tested, but it is suggested that the timing match that of the Intersection Observer API. - <ref spec=INTERSECTIONOBSERVER></p> - <ol> <li>Run the <span>internal pause steps</span> and set the <span>can autoplay flag</span> to @@ -114452,6 +114559,13 @@ console.assert(container.firstChild instanceof SuperP); means the element is not <span>being rendered</span>, though this might be overridden by the style sheets.</p> + <p>An element is said to <dfn>intersect the viewport</dfn> when it is <span>being rendered</span> + and its associated CSS layout box intersects the <span>viewport</span>.</p> + + <p class="note">This specification does not define the precise timing for when the intersection is + tested, but it is suggested that the timing match that of the Intersection Observer API. <ref + spec=INTERSECTIONOBSERVER></p> + <hr> <p>User agents that do not honor author-level CSS style sheets are nonetheless expected to act as @@ -120397,13 +120511,15 @@ interface <dfn>External</dfn> { <code data-x="attr-img-alt">alt</code>; <code data-x="attr-img-src">src</code>; <code data-x="attr-img-srcset">srcset</code>; + <code data-x="attr-img-sizes">sizes</code>; <code data-x="attr-img-crossorigin">crossorigin</code>; <code data-x="attr-hyperlink-usemap">usemap</code>; <code data-x="attr-img-ismap">ismap</code>; <code data-x="attr-dim-width">width</code>; <code data-x="attr-dim-height">height</code>; + <code data-x="attr-img-referrerpolicy">referrerpolicy</code>; <code data-x="attr-img-decoding">decoding</code>; - <code data-x="attr-img-referrerpolicy">referrerpolicy</code></td> + <code data-x="attr-img-loading">loading</code></td> <td><code>HTMLImageElement</code></td> </tr> @@ -121985,6 +122101,12 @@ interface <dfn>External</dfn> { <td> "<code data-x="attr-img-decoding-sync">sync</code>"; "<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> + <td> Used when determining loading deferral + <td> "<code data-x="attr-loading-lazy">lazy</code>"; + "<code data-x="attr-loading-eager">eager</code>" <tr> <th> <code data-x="">default</code> <td> <code data-x="attr-track-default">track</code>