From 0283e9e5f349b107c745dbeb73034445a6b55796 Mon Sep 17 00:00:00 2001 From: bengreenstein Date: Wed, 12 Feb 2020 05:20:23 -0800 Subject: [PATCH] Add "lazy loading images" Follow-up: #5236. Tests: * https://github.com/web-platform-tests/wpt/pull/14914 * https://github.com/web-platform-tests/wpt/pull/17985 * https://github.com/web-platform-tests/wpt/pull/18087 * https://github.com/web-platform-tests/wpt/pull/20634 * https://github.com/web-platform-tests/wpt/pull/20747 * https://github.com/web-platform-tests/wpt/pull/20683 * https://github.com/web-platform-tests/wpt/pull/20774 * https://github.com/web-platform-tests/wpt/pull/20680 * Some as part of https://bugzilla.mozilla.org/show_bug.cgi?id=1542784 Closes #2806. Closes #5250. Co-authored-by: Dominic Farolino Co-authored-by: Anne van Kesteren --- source | 254 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 188 insertions(+), 66 deletions(-) diff --git a/source b/source index 6084f8ff361..60579e079e9 100644 --- a/source +++ b/source @@ -7180,6 +7180,37 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute HTMLOrSVGElement must set the [[CryptographicNonce]] slot on the copy to the value of the slot on the element being cloned.

+

Lazy loading attributes

+ +

A lazy loading attribute is an enumerated attribute. 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.

+ +

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.

+ + + + + + + +
Keyword + State + Description +
lazy + Lazy + Used to defer fetching a resource until some conditions are met. +
eager + Eager + Used to fetch a resource immediately; the default state. +
+ +

The attribute's missing value default and invalid value default are both the Eager state.

+

Common DOM interfaces

@@ -26341,6 +26372,7 @@ interface HTMLSourceElement : HTMLElement {
height
referrerpolicy
decoding
+
loading
Accessibility considerations:
If the element has a non-empty alt attribute: HTMLImageElement : HTMLElement { readonly attribute USVString currentSrc; [CEReactions] attribute DOMString referrerPolicy; [CEReactions] attribute DOMString decoding; + [CEReactions] attribute DOMString loading; Promise<void> decode(); }; @@ -26446,6 +26479,40 @@ interface HTMLImageElement : HTMLElement { default">missing value default and invalid value default are both the auto state.

+

The loading attribute is a lazy + loading attribute. Its purpose is to indicate the policy for loading images that are + outside the viewport.

+ +
+
<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">
+ +

In the example above, the images load as follows:

+ +
+
1.jpeg, 2.jpeg, + 4.jpeg
+

The images load eagerly and delay the window's load event.

+ +
3.jpeg
+

The image loads when layout is known, due to being in the viewport, however it does not + delay the window's load event.

+ +
5.jpeg
+

The image loads only once scrolled into the viewport, and does not delay the window's + load event.

+
+ +

Developers are encouraged to specify an intrinsic aspect ratio via width and height 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.

+
+

The img element must not be used as a layout tool. In particular, img @@ -26634,7 +26701,11 @@ interface HTMLImageElement : HTMLElement {

The decoding IDL attribute must reflect the decoding content - attribute, limited to only known values. + attribute, limited to only known values.

+ +

The loading IDL attribute must + reflect the loading content attribute, + limited to only known values.

@@ -28031,6 +28102,37 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...Updating the image data +

The will lazy load image steps, given an img element img, + are as follows:

+ +
    +
  1. +

    If scripting is disabled for img, return + false.

    + +

    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.

    +
  2. + +
  3. +

    If img's lazy loading attribute is in the Lazy state, img does not intersect the + viewport, and img is not about to intersect the viewport, then + return true.

    + +

    This allows for fetching the image during scrolling, when it does not, but is + about to intersect the viewport.

    +
  4. + +
  5. Return false.

  6. +
+ +

This algorithm cannot be called from steps running in parallel. If + a user agent needs to call this algorithm from steps running in parallel, it needs to + queue a task to do so.

+

When the user agent is to update the image data of an img element, optionally with the restart animations flag set, it must run the following steps:

@@ -28127,16 +28229,12 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ... -
  • Await a stable state, allowing the task that invoked this algorithm to continue. - The synchronous - section consists of all the remaining steps of this algorithm until the algorithm says the - synchronous section has ended. (Steps in synchronous sections are marked with ⌛.)

  • +
  • Queue a microtask to perform the rest of this algorithm, allowing the task that invoked this algorithm to continue.

  • -

    ⌛ If another instance of this algorithm for this img element was started - after this instance (even if it aborted and is no longer running), then return.

    +

    If another instance of this algorithm for this img element was started after + this instance (even if it aborted and is no longer running), then return.

    Only the last instance takes effect, to avoid multiple requests when, for example, the src, srcset, @@ -28144,22 +28242,22 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...

  • -
  • ⌛ Let selected source and selected pixel density be the URL - and pixel density that results from selecting an image - source, respectively.

  • +
  • Let selected source and selected pixel density be the URL and pixel + density that results from selecting an image source, + respectively.

  • -

    ⌛ If selected source is null, then:

    +

    If selected source is null, then:

      -
    1. ⌛ Set the current request's state to broken, abort the - image request for the current request and the pending request, - and set pending request to null.

    2. +
    3. Set the current request's state to + broken, abort the image request for the + current request and the pending request, and set pending + request to null.

    4. -

      Queue an element task on the DOM manipulation task - source given the img element and the following steps:

      +

      Queue an element task on the DOM manipulation task source given + the img element and the following steps:

      1. Change the current request's current @@ -28172,26 +28270,26 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...

      2. -
      3. ⌛ Return.

      4. +
      5. Return.

    5. -

      Parse selected source, relative to the - element's node document, and let urlString be the resulting URL +

      Parse selected source, relative to the element's + node document, and let urlString be the resulting URL string. If that is not successful, then:

        -
      1. Abort the image request for the current request and - the pending request.

      2. +
      3. Abort the image request for the current request and the + pending request.

      4. -
      5. ⌛ Set the current request's state to broken.

      6. +
      7. Set the current request's state to + broken.

      8. -
      9. ⌛ Set pending request to null.

      10. +
      11. Set pending request to null.

      12. -

        Queue an element task on the DOM manipulation task +

        Queue an element task on the DOM manipulation task source given the img element and the following steps:

          @@ -28203,62 +28301,83 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ... -
        1. ⌛ Return.

        2. +
        3. Return.

      13. -
      14. ⌛ If the pending request is not null and urlString is the - same as the pending request's current URL, then +

      15. If the pending request is not null and urlString is the same as + the pending request's current URL, then return.

      16. -
      17. ⌛ If urlString is the same as the current request's

        If urlString is the same as the current request's current URL and current request's state is partially available, then abort the image request for the pending request, queue a task to restart the animation if restart animation is set, and return.

      18. -
      19. ⌛ If the pending request is not null, then abort the image - request for the pending request.

      20. +
      21. If the pending request is not null, then abort the image request + for the pending request.

      22. -
      23. ⌛ Set image request to a new image request whose

        Set image request to a new image request whose current URL is urlString.

      24. -
      25. ⌛ If current request's state is - unavailable or broken, then set - the current request to image request. Otherwise, set the pending +

      26. If current request's state is unavailable or broken, then set the + current request to image request. Otherwise, set the pending request to image request.

      27. -
      28. ⌛ Let request be the result of creating a potential-CORS request given urlString, "image", and the current state of the element's crossorigin content attribute.

      29. -
      30. ⌛ Set request's client to - the element's node document's relevant settings object.

      31. +
      32. Set request's client to the + element's node document's relevant settings object.

      33. -
      34. ⌛ If the element uses srcset or +

      35. If the element uses srcset or picture, set request's initiator to "imageset".

      36. -
      37. ⌛ Set request's referrer +

      38. Set request's referrer policy to the current state of the element's referrerpolicy attribute.

      39. +
      40. Let delay load event be true if the img's lazy loading + attribute is in the Eager state, or if + scripting is disabled for the img, and + false otherwise.

      41. + +
      42. +

        If the will lazy load image steps given the img return true, + then:

        + +
          +
        1. Continue running this algorithm in parallel.

        2. + +
        3. Wait until the will lazy load image steps no longer return true, given the + img.

        4. + +
        5. Queue a task to continue running the rest of this algorithm.

        6. +
        +
      43. +
      44. -

        Fetch request. Let this instance of - the fetching algorithm be associated with image - request.

        +

        Fetch request. Let this instance of the fetching algorithm be associated with image request. +

        -

        The resource obtained in this fashion, if any, is image request's image data. - It can be either CORS-same-origin or CORS-cross-origin; this affects - the origin of the image itself (e.g. when used on a canvas).

        +

        The resource obtained in this fashion, if any, is image request's image data. It can be either CORS-same-origin or + CORS-cross-origin; this affects the origin of the image itself (e.g. + when used on a canvas).

        -

        Fetching the image must delay the load event of the element's node document until the - task that is queued by the +

        When delay load event is true, fetching the image must delay the load + event of the element's node document until the task that is queued by the networking task source once the resource has been fetched (defined below) has been run.

        @@ -28271,8 +28390,8 @@ was an English <a href="/wiki/Music_hall">music hall</a> singer, ...
      45. -
      46. End the synchronous section, continuing the remaining steps in - parallel, but without missing any data from fetching.

      47. +
      48. Continue the remaining steps in parallel, but without missing any data from + fetching.

      49. @@ -32361,10 +32480,6 @@ interface HTMLVideoElement : HTMLMediaElement {

        The default object size is a width of 300 CSS pixels and a height of 150 CSS pixels.

        -

        A video element is said to intersect the viewport when it is - being rendered and its associated CSS layout box intersects the - viewport.

        -

        User agents should provide controls to enable or disable the display of closed captions, audio @@ -35079,10 +35194,6 @@ interface MediaError {

        The user agent may run the following substeps:

        -

        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. -

        -
        1. Set the paused attribute to false.
        2. @@ -35107,10 +35218,6 @@ interface MediaError { true and the autoplay attribute is still specified, run the following substeps:

          -

          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. -

          -
          1. Run the internal pause steps and set the can autoplay flag to @@ -114646,6 +114753,13 @@ console.assert(container.firstChild instanceof SuperP); means the element is not being rendered, though this might be overridden by the style sheets.

            +

            An element is said to intersect the viewport when it is being rendered + and its associated CSS layout box intersects the viewport.

            + +

            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.

            +

            User agents that do not honor author-level CSS style sheets are nonetheless expected to act as @@ -120591,13 +120705,15 @@ interface External { alt; src; srcset; + sizes; crossorigin; usemap; ismap; width; height; + referrerpolicy; decoding; - referrerpolicy + loading HTMLImageElement @@ -122179,6 +122295,12 @@ interface External { "sync"; "async"; "auto" + + loading + img + Used when determining loading deferral + "lazy"; + "eager" default track