Safari src/srcset behavior
What problem does this feature solve?
Safari on iOS and macOS (other browsers not sure?) render an <img>
tag src
attribute initially before calculating an <img>
tag srcset
attribute. This basically means the following 2 javascript examples behave differently:
// example 1, srcset first
const newImage = new Image();
newImage.srcset = 'https://domain.com/image.jpg?w=200 200w';
newImage.src = 'https://domain.com/image.jpg';
document.body.appendChild(newImage);
// example 2, src first
const newImage = new Image();
newImage.src = 'https://domain.com/image.jpg';
newImage.srcset = 'https://domain.com/image.jpg?w=200 200w';
document.body.appendChild(newImage);
Safari will send 1 network request for for the srcset
URL for example 1, but 2 network requests for both the src
and srcset
URLs for example 2. I believe most people would not expect example 2 behavior.
This behavior occurs in Vue templates because of how the template compiles down to javascript. So writing:
<img
:src="someSrc"
:srcset="someSrcset"
>
which compiles down to something like (pseudocode) in vue:
...
("img",{src:someSrc, srcset:someSrcset})
...
will experience double network requests in Safari.
I wonder if vue could optimize the template generation to append the srcset attribute first when constructing an image tag? I know there's some funny business around object property order and simply rearranging src and srcset in the object above might have some caveats... so this request, although simple, may have some unappreciated complexities. I at least wanted to start the conversation around what I think is a seemingly trivial and common example for anyone using srcset
, and how Safari behaves. Simply put, a common practice could be resulting in basically double (or more!) bandwidth usage, let alone degrading the render time based on image loading priority.
What does the proposed API look like?
If this is something that makes sense to address, there would be no changes to the developer-facing side. I imagine it would just be an edge case hardcode in vue template compiler for inserting srcset before src potentially?
Totally understand if this isn't "vue's" problem to solve, just logging something I found unexpected. I really think this change would immediately impact performance significantly for anyone using srcset
.
Replicated this behavior as well for safari mobile https://github.com/vuejs/core/issues/6391#issue-1324834994
Just leaving a follow up note that the same problem/behavior happens in safari desktop/mobile for a template like:
<img
:srcset="https://domain.com/image.jpg?w=200 200w, https://domain.com/image.jpg?w=100 100w"
sizes="50px"
>
What happens is, Safari eagerly loads the srcset before the sizes
attribute has been appended by vue, and so it will actually load the 200 width image and then immediately afterward load the 100 width image.
In my opinion, this behavior effectively makes using srcset broken within vue + safari. I understand this isn't really vue's fault, but bring it up again as unexpected behavior.
Also, to be clear, the easiest workaround here is to rearrange the attribute order such that sizes
comes first. I'm not sure there's a guarantee here in vue about the order of a template matching the order that attributes will be appended, so this could just be a problem that crops up if some optimization or change happens inside vue-template-compiler.
Workaround:
<img
sizes="50px"
:srcset="https://domain.com/image.jpg?w=200 200w, https://domain.com/image.jpg?w=100 100w"
>
I've experienced the same problem when working with Angular 15. I couldn't even imagine that the order of src and srcset attributes does matter.
Thanks for finding out what the reason is.
Hi 719media and everyone!
The related Safari bug tracker ticket: https://bugs.webkit.org/show_bug.cgi?id=190031
Perhaps someone here can help get it fixed.