Issue with images being rendered twice

Hi everyone,

I have an issue with an <img> tag getting re-rendered, and I can’t figure out how to stop this.

So any help would be greatly appreciated.

Issue description.

Steps from the browser’s perspective:

  1. <img> tag gets rendered.
  2. Then the <img> is removed from the DOM, causing a layout change.
  3. Then the <img> is re-rendered, together with an additional get request for the already loaded image.

This issue causes a distracting jittery effect on the web page.

Context for debugging: Liveview re-renders views, by design.

It is expected that pages render twice with Liveview, first for the static view, then for the “stateful” view after socket connection.

However I am not able to understand why, in this case: an already rendered element is re-rendered (with an additional get request for the already fetched resource).

Code example for reference.

Test image component:

attr :src, :string
def test_img(assigns) do
  <img src={@src} />

(Which is called with <.test_img src="/images/test.jpg" />)

Link to website where the issue is occurring – issue is more prominent when refreshing the page on mobile:

I’m on mobile so can’t check developer tools. To me this looks like a progressive compression format.
If you directly open the image on mobile I get a link to an SVG that doesn’t progress in the clear picture.

Hi @tcoopman,

Thanks for checking.

That SVG is actually a low quality placeholder.

In the production website the browser steps for this are issue:

  1. The low quality placeholder .svg gets loaded.
  2. The actual image .jpg gets loaded.
  3. Then both the placeholder & actual image are removed from the DOM.
  4. Then, the low quality placeholder gets re-rendered.
  5. Then, the actual image gets re-rendered.

So there are 4 get requests in total – two for the placeholder & two for the actual image.

You can see this when you scroll in the image gallery. When images are loaded, there is a flicker effect.

The issue occurs for any <img> tag on the website.
In development for example, I added that example test_img component, and the issue occurred in the simplified form:

  1. <img> gets rendered with test.jpg.
  2. <img> gets removed from the DOM.
  3. <img> gets re-rendered, with an additional get request for test.jpg.

For me there is only 2 get requests, 1 for the svg, 1 for the jpg. I’m using Firefox.

Can you provide some extra information, like what browser you’re using? Maybe record a video of the problem?

I am using Firefox too.

I can see the double get requests on:

  • Desktop Firefox browser.
  • Desktop Safari browser.
  • Mobile Safari browser (using the webinspector bridge from mobile safari to desktop safari).

Unfortunately, I can’t upload screenshots, to show the network calls.
So here are imgur links for the screenshots:

Thanks for suggesting screen recording the issue.
It highlighted differences in how different browsers are handling this issue.

The recording of Safari on Desktop clearly showed that:

  1. The placeholder image is rendered.
  2. The placeholder image is removed from the DOM.
  3. The placeholder image is re-rendered.
  4. The actual image is rendered.

Here is a link to the recording video: Imgur - Recording of image re-rendering issue on Safari.

I can reproduce it on Safari, but not on Firefox.

Do you have any custom javascript loading?
Can you create a minimal reproduction of the problem?

Hi @tcoopman,

Thanks for helping me debug the issue.

Thanks also for suggesting that I minimally reproduce the problem. For some reason my previous minimal example with “test_img” didn’t work properly.

The issue was that the <img> tag was being generated using a random id.
So when LiveView re-renders the view: a new random id is set for the <img> tag (which gets treated as a new DOM element).

Example of issue causing code

<img id={Enum.random(0..9)} src="/images/test.jpg" />