6

Is it possible to catch CSS background | background-image: url(..); errors (e.g 404) with JavaScript and make corrections?

Only option I can think of right now is to loop over all elements in page, check background and background-image property, if present, try to make corrections. This is undesirable fix as you can probably guess.


I've notices that if I use custom Image src setter, it seems that CSS url does make an Image in background and operate on that but even if I change its src, url('images/example.jpg') still stays the same and points to wrong path.

const {get, set} = Object.getOwnPropertyDescriptor(Image.prototype, 'src');

Object.defineProperty(Image.prototype, 'src', {
  set(value) {
    // this gets called even for CSS url()
    return set.call(this, value);
  },
  get() {
    return get.call(this);
  }
});
slaidurch
  • 35
  • 5
Solo
  • 6,687
  • 7
  • 35
  • 67
  • 1
    Does this answer your question? [onerror event using background: url()](https://stackoverflow.com/questions/22287474/onerror-event-using-background-url) – Justinas May 12 '20 at 09:15
  • @Justinas Unfortunately no, I have no control over these things, HTML elements, sources, styles, etc are added dynamically by third-party library. – Solo May 12 '20 at 09:16
  • 1
    Well, maybe you can just place images where it should be? – Justinas May 12 '20 at 09:17
  • 1
    @Justinas For that I'd need to find out if `url()` error occured and where (in DOM) it occured. Like I said, I have no control over HTML nor CSS, I have to "clean up after". – Solo May 12 '20 at 09:19
  • Kindly see the reference website, i hope its useul it http://web.archive.org/web/20121119020227/http://lucassmith.name/pub/imgload.html – Uday May 12 '20 at 09:23
  • @Solo, do you know which elements to check? Or can the background be on any element on the page? – rid May 12 '20 at 09:25
  • @rid It seems to be mostly on `div's` but yeah, I'd require a more flexible solution. – Solo May 12 '20 at 09:28
  • @Solo, can you also do this on the server, or does it have to be on the client? – rid May 12 '20 at 09:31
  • @rid Has to be on client, I need to clean up after third-party code I have no control over. – Solo May 12 '20 at 09:32
  • @rid I wonder if it's possible to manually fill the image pixels without altering the `src`, because I have the `img` element in setter as `this` and I also have image data as blob. – Solo May 12 '20 at 09:37
  • @Solo, oh, wait, you have the `Image` instance. You can do a lot with that. But how did you get it? Do you go through all elements in the page? – rid May 12 '20 at 09:39
  • @rid Look at the example `src` setter code, apparently CSS `url` creates an Image instance. I don't mind hacks like this as long as I get it to work, hacking Image is not an issue anyway because all this code runs in iframe and doesn't affect top window. – Solo May 12 '20 at 09:42
  • @rid I should add that I found out that Image instance in setter is not to final one being used, not sure what's the browser logic here. – Solo May 12 '20 at 10:08

1 Answers1

0

Service Workers can be used to intercept all the network calls in the browser.

You have to register the service worker like:

const registerServiceWorker = async () => {
  if ('serviceWorker' in navigator) {
    try {
      const registration = await navigator.serviceWorker.register(
        '/sw-test/sw.js',
        {
          scope: '/sw-test/',
        }
      );
    } catch (error) {
      console.error(`Registration failed with ${error}`);
    }
  }
};

registerServiceWorker();

And have the service worker /sw-test/sw.js look like:

const customFetch = async ({ request }) => {
  try {
    const responseFromNetwork = await fetch(request);
    // ADD FALLBACK HERE
    return responseFromNetwork;
  } catch (error) {
    return new Response('Network error happened', {
      status: 408,
      headers: { 'Content-Type': 'text/plain' },
    });
  }
};

self.addEventListener('fetch', (event) => {
  const response = customFetch({
    request: event.request,
  });
  event.respondWith(response);
});

Anurag Kalia
  • 4,668
  • 4
  • 21
  • 28