Vue: `src` attribute of `img` inside `picture` should be set after `img` is appended to `picture` to avoid unnecessary requests

Created on 29 Apr 2020  路  5Comments  路  Source: vuejs/vue

Version

2.6.11

Reproduction link

https://codepen.io/CaseJnr/pen/VwvWbPE

Steps to reproduce

  1. Open the codepen link in safari

  2. Inspect the element

  3. Reduce the view width below 900px and refresh the page

  4. You will notice that both the red and blue image is requested.

  5. Comment out the vue instance and refresh the page.

  6. You will notice only the red image is requested (as expected).

What is expected?

Only the required picture resource is requested.

What is actually happening?

Both of the pictures resources are requested, causing redundant downloads.


In Safari, adding a vue instance to any page will cause redundant picture sources to be requested. The picture element will behave correctly if the vue instance is removed.

E.g.

<picture>
<source media="(max-width: 900px)" srcset="small.jpg">
<img src="large.jpg" alt="">
</picture>

By default, only the small.jpg should be requested when the view width is below 900px. However, if a vue instance is added to the page, then both the small.jpg and large.jpg are requested.

The mobile inspector shows the small.jpg request initiator as the page (expected). The large.jpg initiator is actually the vue instance.

browser quirks improvement

All 5 comments

It seems to happen with vanilla JS:

if(document.getElementById("app")) {
  // new Vue({ el: '#app'});
}

let picture = document.createElement('picture')
let s1 = document.createElement('source')
s1.media = '(max-width: 900px)'
s1.srcset = "https://www.abc.net.au/radionational/image/6289622-4x3-340x255.png"

let s2 = document.createElement('img')
s2.src = "https://www.solidbackgrounds.com/images/2560x1440/2560x1440-brandeis-blue-solid-color-background.jpg"
s2.alt =''

picture.appendChild(s1)
picture.appendChild(s2)

window.app.innerHTML = 'new'
window.app.appendChild(picture)

Could you open a bug report at https://bugs.webkit.org please?

@posva The issue is how vue is constructing the picture. Creating an img element and setting the src will initiate a request, as expected. To eliminate the redundant img request, the img element must first be added to a picture element before the img.src is set.

The following code eliminates the redundant img.src request for views with a width less than 900px

let picture = document.createElement('picture')
let source = document.createElement('source')
source.media = '(max-width: 900px)'
source.srcset = "https://www.abc.net.au/radionational/image/6289622-4x3-340x255.png"

let img = document.createElement('img')
img.alt =''

picture.appendChild(source)
picture.appendChild(img) // Append img to picture before setting the src

img.src = "https://www.solidbackgrounds.com/images/2560x1440/2560x1440-brandeis-blue-solid-color-background.jpg"

window.app.appendChild(picture)

Good to know the order here matters. Did you find the section on the HTML spec defining this behavior? It's still surprising that Chrome handles it but Safari doesn't

@posva Any chance you could recommend a fix for this while I wait for a PR?

Good to know the order here matters. Did you find the section on the HTML spec defining this behavior? It's still surprising that Chrome handles it but Safari doesn't..

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hiendv picture hiendv  路  3Comments

robertleeplummerjr picture robertleeplummerjr  路  3Comments

wufeng87 picture wufeng87  路  3Comments

aviggngyv picture aviggngyv  路  3Comments

finico picture finico  路  3Comments