tl;dr
Use the srcset
attribute with an image candidate string that has a URL of about:blank
and a width descriptor of 1w
and set the sizes
attribute's fallback <source-size-value>
to 0vw
. Then, add CSS rules to hide the image for smaller viewports. Finally, wrap it in a <picture>
with <source>
s for absolute control.
srcset
It appears to me that this can be solved using responsive images and a bit of CSS.
Consider the following responsive image:
<img
src="foo-585.png"
alt="foo"
srcset="foo-375.png 375w, foo-585.png 585w"
sizes="(min-width: 1200px) 585px, (min-width: 768px) 375px"
>
Despite there being no fallback <source-size-value>
in sizes
, foo-375.png
is still loaded. So it appears we need to find an image candidate string that doesn't send any additional HTTP requests.
I searched SO for tips on how to essentially set a null image candidate string. I found several methods, all of which can be implemented like so:
<img
src="foo-585.png"
alt="foo"
srcset="[URL] 1w foo-375.png 375w, foo-585.png 585w"
sizes="(min-width: 1200px) 585px, (min-width: 768px) 375px, 0vw"
>
Note that a new image candidate string with a width descriptor of 1w
and a fallback <source-size-value>
of 0vw
are added. In this example, [URL]
is a placeholder for one of the URLs described below:
Empty Fragment
One answer advises using an empty fragment (#
) as a valid option. Unfortunately, my tests indicate this method repeatedly sends HTTP requests to the current URL. Not good.
Tiny Data URL
Another answer recommends using The Tiniest GIF Ever in a Base64-encoded data URL:
data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=
Initially, I thought that at 58 bytes with very little opportunity for gzip compression on its own, it stands to reason that saving the GIF as an external resource with a shorter URL might be more efficient than multiple data URLs, but I was wrong; gzip eats multiple instances of this data URL for breakfast.
But, as one comment points out, data URLs are slow on mobile.
No Scheme, No Host, Port 0
Yet another answer suggests using a URL with no scheme, no host, and port 0
(//:0
). This appears to work, but there are concerns about firewall warnings. CSS is also required to hide the broken image styling.
about:blank
That same commenter suggested using about:blank
, which actually seems to work well enough, but like the last method, does require CSS to hide the broken image styling:
img {
display: none;
}
@media (min-width: 768px) {
img {
display: inline-block;
}
}
To me, this seems like the best option, as it is valid, efficient, and will not display any user-facing warnings. Those few lines of CSS seem well-worthwhile to me.
<picture>
As the comments have pointed out, srcset
isn't guaranteed. If the browser for some reason decides against your about:blank
image candidate, then the solution falls apart. To remedy this, wrap your <img>
in <picture>
element and add the relevant <source>
s:
<picture>
<source
media="(min-width: 768px)"
srcset="[URL] 1w foo-375.png 375w, foo-585.png 585w"
>
<source srcset="about:blank">
<img
src="foo-585.png"
alt="foo"
srcset="[URL] 1w foo-375.png 375w, foo-585.png 585w"
sizes="(min-width: 1200px) 585px, (min-width: 768px) 375px, 0vw"
>
</picture>