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

www.ikea.com - design is broken #113635

Closed
karlcow opened this issue Nov 7, 2022 — with webcompat-app · 24 comments
Closed

www.ikea.com - design is broken #113635

karlcow opened this issue Nov 7, 2022 — with webcompat-app · 24 comments
Labels
browser-firefox browser-safari engine-gecko The browser uses the Gecko rendering engine os-mac Issues only happening on macOS. type-image Issues with specific images rendering differently (the server is sending the same image to each UA).
Milestone

Comments

@karlcow
Copy link
Member

karlcow commented Nov 7, 2022

URL: https://www.ikea.com/us/en/home-design/

Browser / Version: Firefox 108.0
Operating System: Mac OS X 10.15
Tested Another Browser: Yes Safari

Problem type: Design is broken
Description: Images not loaded
Steps to Reproduce:

  1. Go to https://www.ikea.com/us/en/home-design/
  2. Block location
  3. Allow cookies
  4. Refresh if images are loaded, until you get a version without images. (Maybe 2 or 3 reloads)

Expected:
Images visible

Actual:
Some images are missing.

Notes:
This happens in Firefox NIghtly and Safari Tech Preview but not able to reproduce in Chrome Canary.

View the screenshot Screenshot
Browser Configuration
  • None

From webcompat.com with ❤️

@webcompat-bot webcompat-bot added this to the needstriage milestone Nov 7, 2022
@webcompat-bot webcompat-bot added browser-firefox engine-gecko The browser uses the Gecko rendering engine priority-important labels Nov 7, 2022
@karlcow karlcow added browser-safari type-image Issues with specific images rendering differently (the server is sending the same image to each UA). and removed priority-important labels Nov 7, 2022
@karlcow
Copy link
Member Author

karlcow commented Nov 7, 2022

This is the code when the image is not being loaded.

<div class="dl-card__image">
  <span
    class="dl-aspect-ratio-image dl-aspect-ratio-image--wide dl-card__image-aspect-ratio"
    ><div
      data-gatsby-image-wrapper=""
      class="gatsby-image-wrapper gatsby-image-wrapper-constrained"
      suppresshydrationwarning="true"
    >
      <div style="max-width: 1000px; display: block">
        <img
          alt=""
          role="presentation"
          aria-hidden="true"
          src="data:image/svg+xml;charset=utf-8,%3Csvg height='718' width='1000' xmlns='http://www.w3.org/2000/svg' version='1.1'%3E%3C/svg%3E"
          style="max-width: 100%; display: block; position: static"
        />
      </div></div
  ></span>
</div>

And this is the code when the image is being loaded.

<div class="dl-card__image">
  <span
    class="dl-aspect-ratio-image dl-aspect-ratio-image--wide dl-card__image-aspect-ratio"
    ><div
      data-gatsby-image-wrapper=""
      class="gatsby-image-wrapper gatsby-image-wrapper-constrained"
      suppresshydrationwarning="true"
    >
      <div style="max-width: 1000px; display: block">
        <img
          alt=""
          role="presentation"
          aria-hidden="true"
          src="data:image/svg+xml;charset=utf-8,%3Csvg height='718' width='1000' xmlns='http://www.w3.org/2000/svg' version='1.1'%3E%3C/svg%3E"
          style="max-width: 100%; display: block; position: static"
        />
      </div>
      <img
        aria-hidden="true"
        data-placeholder-image=""
        style="opacity: 0; transition: opacity 500ms linear; object-fit: cover"
        decoding="async"
        src="data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEAgX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABqbxrJdiQ/8QAGRABAQEBAQEAAAAAAAAAAAAAAQIREhMh/9oACAEBAAEFAs6eflYJTL6K0zv/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAEAAgMBAAAAAAAAAAAAAAAAASERMUKh/9oACAEBAAY/AqlhtUr8dP/EABoQAAMBAAMAAAAAAAAAAAAAAAABESFhcYH/2gAIAQEAAT8hl0yVfsSAM2TFQv0NW3vlH//aAAwDAQACAAMAAAAQ2C//xAAWEQEBAQAAAAAAAAAAAAAAAAAAETH/2gAIAQMBAT8Q1X//xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQIBAT8QcLC//8QAGxABAAIDAQEAAAAAAAAAAAAAAQARITFhQfD/2gAIAQEAAT8QriGt7zFAzDRvr5EKNnIdIFZuMq1hbk10jp9y+if/2Q=="
        alt=""
      /><picture
        ><source
          type="image/webp"
          srcset="
            /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/52dbe/showroom-1.webp  250w,
            /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/85d7d/showroom-1.webp  500w,
            /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/b4d58/showroom-1.webp 1000w
          "
          sizes="(min-width: 1000px) 1000px, 100vw" />
        <img
          data-main-image=""
          style="object-fit: cover; opacity: 1"
          sizes="(min-width: 1000px) 1000px, 100vw"
          decoding="async"
          loading="eager"
          src="/us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/41a63/showroom-1.jpg"
          srcset="
            /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/87461/showroom-1.jpg  250w,
            /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/1f3b1/showroom-1.jpg  500w,
            /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/41a63/showroom-1.jpg 1000w
          "
          alt=""
          width="1000"
          height="718" /></picture
      ><noscript></noscript></div
  ></span>
</div>

@karlcow
Copy link
Member Author

karlcow commented Nov 7, 2022

I suspect a glitch in native image lazy loading.
webpack://design-lab-frontend/src/components/hooks.ts

and also webpack://design-lab-frontend/src/components/gatsby-image.browser.tsx

    // The plugin image component is a bit special where if it's server-side rendered, we add extra script tags to support lazy-loading without
    // In this case we stop hydration but fire the correct events.
    const ssrImage = root.current.querySelector(
      `[data-gatsby-image-ssr]`
    ) as HTMLImageElement
    if (ssrImage && hasNativeLazyLoadSupport()) {
      if (ssrImage.complete) {
        // Trigger onStartload and onLoad events
        onStartLoad?.({
          wasCached: true,
        })
        onLoad?.({
          wasCached: true,
        })

        // remove ssr key for state updates but add delay to not fight with native code snippt of gatsby-ssr
        setTimeout(() => {
          ssrImage.removeAttribute(`data-gatsby-image-ssr`)
        }, 0)
      } else {
        onStartLoad?.({
          wasCached: true,
        })

        ssrImage.addEventListener(`load`, function onLoadListener() {
          ssrImage.removeEventListener(`load`, onLoadListener)

          onLoad?.({
            wasCached: true,
          })
          // remove ssr key for state updates but add delay to not fight with native code snippt of gatsby-ssr
          setTimeout(() => {
            ssrImage.removeAttribute(`data-gatsby-image-ssr`)
          }, 0)
        })
      }

      imageCache.add(cacheKey)

      return
    }

    if (renderImage && imageCache.has(cacheKey)) {
      return
    }

@karlcow
Copy link
Member Author

karlcow commented Nov 7, 2022

@ksy36 @denschub what do you think?

@karlcow
Copy link
Member Author

karlcow commented Nov 8, 2022

It looks very similar to gatsbyjs/gatsby#35628

@karlcow
Copy link
Member Author

karlcow commented Nov 8, 2022

In Safari technical preview, deactivating lazy loading makes the site slower, but the images load every time.

@karlcow
Copy link
Member Author

karlcow commented Nov 8, 2022

This is probably outreach to ikea.

@sv-calin sv-calin added the os-mac Issues only happening on macOS. label Nov 8, 2022
@robinwhittleton
Copy link

I’ll pick this up and bring it to the appropriate team.

@sv-calin
Copy link

sv-calin commented Nov 9, 2022

Thanks for the report, Karl. The images do not load on every refresh.

image

I was not able to reproduce the issue on Safari. (5/5 tries)

image

Tested on:
• Browser / Version: Firefox Nightly 108.0a1 (2022-11-08) / Firefox Release 106.0.5 / Chrome 107.0.5304.110 / Safari 16.1 (18614.2.9.1.12)
• Operating System: Mac OS X 10.15

Notes:

  1. Reproducible on both Firefox Release and Nightly
  2. Not reproducible on Chrome

Moving to Needsdiagnosis.

[qa_45/2022]

@sv-calin sv-calin modified the milestones: needstriage, needsdiagnosis Nov 9, 2022
@robinwhittleton
Copy link

So this page is currently going through a redevelopment which should resolve this, but in the event that the component continues to be used they’ll work to fix this now that they know the issue.

Thanks for highlighting the problem @karlcow, and I’ll keep an eye on it.

@denschub
Copy link
Member

denschub commented Nov 9, 2022

@robinwhittleton just for the record, y'all shipping sourcemaps into production is so much appreciated. ❤️ it makes our work of diagnosing web-compat issues soooooo much easier. :)

If you run into any browser specific issues, please report them on webcompat.com, and we'll take a look at it!

For now, I'll move this issue into sitewait, as there is nothing for us to do here.

@denschub denschub modified the milestones: needsdiagnosis, sitewait Nov 9, 2022
@karlcow
Copy link
Member Author

karlcow commented Nov 9, 2022

it makes our work of diagnosing web-compat issues soooooo much easier. :)

This!

Thanks a lot.

@karlcow
Copy link
Member Author

karlcow commented Nov 9, 2022

Tracked at Apple with rdar://101657305

@brentfulgham
Copy link

How will we know when Ikea pushes a fix for this? Do we just need to check the site periodically, or will someone notify us here?

@robinwhittleton
Copy link

I’m at IKEA, so you can poke me. But I’m not in the team that owns this, and I have no update on timing at the moment.

@karlcow
Copy link
Member Author

karlcow commented Nov 16, 2022

When it succeeds the image being displayed by Safari is:

<picture
  ><source
    type="image/webp"
    srcset="
      /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/52dbe/showroom-1.webp  250w,
      /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/85d7d/showroom-1.webp  500w,
      /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/b4d58/showroom-1.webp 1000w
    "
    sizes="(min-width: 1000px) 1000px, 100vw" />
  <img
    data-gatsby-image-ssr=""
    data-main-image=""
    style="opacity: 1"
    sizes="(min-width: 1000px) 1000px, 100vw"
    decoding="async"
    loading="eager"
    src="/us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/41a63/showroom-1.jpg"
    srcset="
      /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/87461/showroom-1.jpg  250w,
      /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/1f3b1/showroom-1.jpg  500w,
      /us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/41a63/showroom-1.jpg 1000w
    "
    alt=""
/></picture>

https://www.ikea.com/us/en/home-design/static/977d4773fdd6e9c4a336afb08f13682f/b4d58/showroom-1.webp

BUT my impression is that images are always loaded, but then the DOM is being rewritten.

When we deactivate lazy loading, it's always working. which means it never goes through this code which is in the HTML source, where I replaced: t by hasNativeLazyLoadingSupport to make it clearer.

const hasNativeLazyLoadingSupport =
  "undefined" != typeof HTMLImageElement &&
  "loading" in HTMLImageElement.prototype;
if (hasNativeLazyLoadingSupport) {
  const t = document.querySelectorAll("img[data-main-image]");
  for (let e of t) {
    e.dataset.src &&
      (e.setAttribute("src", e.dataset.src), e.removeAttribute("data-src")),
      e.dataset.srcset &&
        (e.setAttribute("srcset", e.dataset.srcset),
        e.removeAttribute("data-srcset"));
    const t = e.parentNode.querySelectorAll("source[data-srcset]");
    for (let e of t)
      e.setAttribute("srcset", e.dataset.srcset),
        e.removeAttribute("data-srcset");
    e.complete &&
      ((e.style.opacity = 1),
      (e.parentNode.parentNode.querySelector(
        "[data-placeholder-image]"
      ).style.opacity = 0));
  }
}

This script seems to be repeated as much as they are images in the document.

There is another similar script in the head of the document.

const e =
  "undefined" != typeof HTMLImageElement &&
  "loading" in HTMLImageElement.prototype;
e &&
  document.body.addEventListener(
    "load",
    function (e) {
      const t = e.target;
      if (void 0 === t.dataset.mainImage) return;
      if (void 0 === t.dataset.gatsbyImageSsr) return;
      let a = null,
        n = t;
      for (; null === a && n; )
        void 0 !== n.parentNode.dataset.gatsbyImageWrapper &&
          (a = n.parentNode),
          (n = n.parentNode);
      const o = a.querySelector("[data-placeholder-image]"),
        r = new Image();
      (r.src = t.currentSrc),
        r
          .decode()
          .catch(() => {})
          .then(() => {
            (t.style.opacity = 1),
              o &&
                ((o.style.opacity = 0),
                (o.style.transition = "opacity 500ms linear"));
          });
    },
    !0
  );

all these scripts are wrapped into

<script type="module"></script>

There are 18 instances of them.

The one in the head is the one called a lot. Around ~160 times

There is something looking like a race issue in all of these.

@karlcow
Copy link
Member Author

karlcow commented Nov 16, 2022

Removing all the individual scripts module for each image with a local override in Web Inspector dev tools in Safari doesn't fix the issue. So There is something else going on.

@karlcow
Copy link
Member Author

karlcow commented Nov 16, 2022

The last piece of code checking for Lazy Loading is:

              const e = k.current.querySelector("[data-gatsby-image-ssr]");
              if (e && l())
                return (
                    e.complete
                    ? (null == g ||
                        g({
                          wasCached: !0,
                        }),
                      null == h ||
                        h({
                          wasCached: !0,
                        }),
                      setTimeout(() => {
                        e.removeAttribute("data-gatsby-image-ssr");
                      }, 0))
                    : (null == g ||
                        g({
                          wasCached: !0,
                        }),
                      e.addEventListener("load", function t() {
                        e.removeEventListener("load", t),
                          null == h ||
                            h({
                              wasCached: !0,
                            }),
                          setTimeout(() => {
                            e.removeAttribute("data-gatsby-image-ssr");
                          }, 0);
                      })),
                  void I.add(C)
                );

which is in fact

https://github.com/gatsbyjs/gatsby/blob/3dfc1ec1c03a962bfdcf3db6ec200883d612d3ad/packages/gatsby-plugin-image/src/components/gatsby-image.browser.tsx#L110-L145

    const ssrImage = root.current.querySelector(
      `[data-gatsby-image-ssr]`
    ) as HTMLImageElement
    if (ssrImage && hasNativeLazyLoadSupport()) {
      if (ssrImage.complete) {
        // Trigger onStartload and onLoad events
        onStartLoad?.({
          wasCached: true,
        })
        onLoad?.({
          wasCached: true,
        })

        // remove ssr key for state updates but add delay to not fight with native code snippt of gatsby-ssr
        setTimeout(() => {
          ssrImage.removeAttribute(`data-gatsby-image-ssr`)
        }, 0)
      } else {
        onStartLoad?.({
          wasCached: true,
        })

        ssrImage.addEventListener(`load`, function onLoadListener() {
          ssrImage.removeEventListener(`load`, onLoadListener)

          onLoad?.({
            wasCached: true,
          })
          // remove ssr key for state updates but add delay to not fight with native code snippt of gatsby-ssr
          setTimeout(() => {
            ssrImage.removeAttribute(`data-gatsby-image-ssr`)
          }, 0)
        })
      }

      imageCache.add(cacheKey)

      return
    }

Also:
https://github.com/gatsbyjs/gatsby/blob/9a912956a5ea66be7281f6263928b64f20ff1d53/packages/gatsby-plugin-image/src/components/lazy-hydrate.tsx#L57

Gatsby 4.24.1 is used. Current Gatsby is 5.0

I need to dig a bit more there

@karlcow
Copy link
Member Author

karlcow commented Nov 17, 2022

ok I'm 100% sure now that the issue is happening in this part of the code that the issue is.

@robinwhittleton

                    const e = k.current.querySelector("[data-gatsby-image-ssr]");
                    if (e && l())
                        return e.complete ? (null == g || g({
                            wasCached: !0
                        }), null == h || h({
                            wasCached: !0
                        }), setTimeout((() => {
                            e.removeAttribute("data-gatsby-image-ssr")
                        }), 0)) : (null == g || g({
                            wasCached: !0
                        }), e.addEventListener("load", (function t() {
                            e.removeEventListener("load", t),
                            null == h || h({
                                wasCached: !0
                            }),
                            setTimeout((() => {
                                e.removeAttribute("data-gatsby-image-ssr")
                            }), 0)
                        }))), void I.add(C);

If I just change

                    if (e && l())

by

                    if (e && false)

so that it is never executed. The images are always displayed.

Modifying the code a bit to better understand.

const e = k.current.querySelector("[data-gatsby-image-ssr]");
const wasCachedTrue = { wasCached: !0 };
if (e && l()) {
  if (e.complete) {
    console.log("e.complete OK");
    null == g || g(wasCachedTrue),
      null == h || h(wasCachedTrue),
      setTimeout(() => {
        e.removeAttribute("data-gatsby-image-ssr");
      }, 0);
  } else {
    console.log("e.complete NOT OK");
    null == g || g(wasCachedTrue),
      e.addEventListener("load", function t() {
        e.removeEventListener("load", t),
          null == h || h(wasCachedTrue),
          setTimeout(() => {
            e.removeAttribute("data-gatsby-image-ssr");
          }, 0);
      });
  }
  void I.add(C);
}

Each time the images are NOT displayed is when we reach the second part of the condition aka when HTMLImageElement.complete is false.
So basically when the image has not finished being loaded.

@karlcow
Copy link
Member Author

karlcow commented Feb 14, 2023

@robinwhittleton This is still happening.

Steps to reproduce

  1. Open Safari Tech Preview 163
  2. Go to Develop Menu and select Disable Site Specific Hacks
  3. Go to https://www.ikea.com/us/en/home-design/
  4. (Images are loading)
  5. Then reload

Expected:
Images here.

Actual:
Images are not visible.

@robinwhittleton
Copy link

The rebuild on this page has (I believe) happened, and I can’t replicate the issue any more in either Firefox or Safari TP.

@denschub
Copy link
Member

Indeed, images seem to load fine now. Thank you so much. <3

@denschub denschub modified the milestones: sitewait, fixed Apr 18, 2023
@karlcow
Copy link
Member Author

karlcow commented May 15, 2023

@karlcow
Copy link
Member Author

karlcow commented May 19, 2023

This is working for me too. I will remove the Quirk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
browser-firefox browser-safari engine-gecko The browser uses the Gecko rendering engine os-mac Issues only happening on macOS. type-image Issues with specific images rendering differently (the server is sending the same image to each UA).
Projects
None yet
Development

No branches or pull requests

6 participants