Skip to content

Instantly share code, notes, and snippets.

@williammalo
Forked from 140bytes/LICENSE.txt
Last active March 1, 2019 17:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save williammalo/3077264 to your computer and use it in GitHub Desktop.
Save williammalo/3077264 to your computer and use it in GitHub Desktop.
Responsive image loading in 199bytes (minification help needed)

This function loops through all images on the page, and serves the appropriately sized image file from a list in a data attribute.

example link: http://total.maloweb.com/responsive

example html:

<img src="default.png" data-widths="400,600,800,1023" data-srcsuffix="-foo.png">

example javascript:

onload=onresize=function(){
    respImg("data-widths","data-srcsuffix")
}

example filenames:

400-foo.png
600-foo.png
800-foo.png
1023-foo.png
function(x,y, //x:attribute name for widths, y:attribute name for suffix
a,c,d,b,e,f,g){ //placeholders
for(d in f=document.images)if(a=f[d],g=a.getAttribute(x)){ //for every image with a width list
b=g.split(","); //split width list into array
for(c=b.length;c--;) //for every width
if(e=b[0],b[c]<a.offsetWidth){ //set lowest width as default(e), when the loop encounters a width smaller than the image:
e=b[c+1]||b[c];break} //set e to one width higher, or the highest width available
a.src=e+a.getAttribute(y) //set src attribute to the right width
}
}
function(x,y,a,c,d,b,e,f,g){for(d in f=document.images)if(a=f[d],g=a.getAttribute(x)){b=g.split(",");for(c=b.length;c--;)if(e=b[0],b[c]<a.offsetWidth){e=b[c+1]||b[c];break}a.src=e+a.getAttribute(y)}}
{
"name": "respImg",
"description": "Responsive image loading",
"keywords": [
"responsive",
"conditional",
"image",
"loading"
]
}
<!DOCTYPE html>
<title>Foo</title>
<a href="http://total.maloweb.com/responsive">click link for example</a>
@atk
Copy link

atk commented Jul 10, 2012

First minification attempt (untested for correct working, only tested for errors, 165bytes):

function(x,y,a,d,e,f,g){for(d in f=document.images)a=f[d],e=a.offsetWidth,(a[g='getAttribute']&&a[g](x)||g).replace(/\d+/g,function(c){+c<e&&(a.src=c+a[g](y),e=0)})}

@atk
Copy link

atk commented Jul 10, 2012

Reused variable (163bytes):

function(x,y,d,e,f,g){for(d in f=document.images)d=f[d],e=d.offsetWidth,(d[g='getAttribute']&&d[g](x)||g).replace(/\d+/g,function(c){+c<e&&(d.src=c+d[g](y),e=0)})}

@atk
Copy link

atk commented Jul 10, 2012

Reused e for testing if f[d] is actually image element (instead of testing for d.getAttribute, 160bytes):

function(x,y,d,e,f,g){for(d in f=document.images)d=f[d],e=d.offsetWidth,(e&&d[g='getAttribute'](x)||g).replace(/\d+/g,function(c){+c<e&&(d.src=c+d[g](y),e=0)})}

Now I'm out of ideas how to minimize this further.

@williammalo
Copy link
Author

@atk your functions don't work, they load the lowest resolution image...

@atk
Copy link

atk commented Jul 10, 2012

Oh, forgot to tell you that you'll have to reverse the order of resolutions in the data attribute. My fault.

@williammalo
Copy link
Author

@atk I used your tips to make my function a bit smaller 189bytes

function(x,y,a,c,d,e,f,g){for(d in f=document.images)if(d=f[d],g=d[a="getAttribute"](x)){g=g.split(",");for(c=g.length;c--;)if(e=g[0],g[c]<d.offsetWidth)e=g[c+1]||g[c],c=0;d.src=e+d[a](y)}}

your's still doesn't work if I reverse the widths, it always shows one resolution lower.

@atk
Copy link

atk commented Jul 10, 2012

OK, will have to look into this later. This will probably require to revert the resolution numbers to the former order. Do I get it right in that case that it should always be the resolution 1 notch above (and not below, like it is now) the current one?

Update: made a mix of both of our codes (168bytes):

function(x,y,d,e,f,g,h){for(d in f=document.images)for(e in h=((d=f[d])[g='getAttribute']&&(d[g](x)||'').split(',')))if(h[e]<d.offsetWidth){d.src=h[e+1]+d[g](y);break}}

Another update: rethought my regex version (161bytes):

function(x,y,d,e,f,g){for(d in f=document.images)d=f[d],e=d.offsetWidth,(e&&d[g='getAttribute'](x)||g).replace(/\d+/g,function(c){c>e&&(d.src=c+d[g](y),e=1/0)})}

Last update (depending on the former one): sneaky abuse of string value comparison (159bytes):

function(x,y,d,e,f,g){for(d in f=document.images)d=f[d],e=d.offsetWidth,(e&&d[g='getAttribute'](x)||g).replace(/\d+/g,function(c){c>e&&(d.src=c+d[g](y),e=g)})}

@williammalo
Copy link
Author

@atk it doesn't work at all now... it either returns "undefined-suffix.png" or "NaN"

@atk
Copy link

atk commented Jul 10, 2012

I'll have a look into the problem later.

@atk
Copy link

atk commented Jul 11, 2012

OK, got this now. Forgot that there was no resolution beyond the last one. 176bytes now:

function(x,y,d,e,f,g,h){for(d in f=document.images)for(e in h=((d=f[d])[g='getAttribute']&&(d[g](x)||'').split(',')))if(h[e]<d.offsetWidth){d.src=(h[e+1]||h[e])+d[g](y);break}}

@atk
Copy link

atk commented Jul 11, 2012

Currently, I am trying to get rid of split, because it's too long. Not sure if this will work, but it goes around the lines of:

function(x,y,d,e,f,g,h,i){for(d in f=document.images)for(d=f[d],e=d.offsetWidth,h=/d+/g;i<e&&(i=h.exec(e&&d[g='getAttribute'](x)||g)[0]||i););i&&(d.src=i+d[g](y))}

@williammalo
Copy link
Author

@atk the latest two don't work as well...

@atk
Copy link

atk commented Jul 12, 2012

I'll have to copy your test page so I could test myself...

@maettig
Copy link

maettig commented Jul 17, 2012

Can you drop the prefix and simply use "default.png", "400-default.png" and so on as filenames?

@williammalo
Copy link
Author

@maettig
Sure?

@maettig
Copy link

maettig commented Jul 17, 2012

Just a suggestion. I don't know if this is what you want. Simply write <img src="default.png" data-widths="400,600,800,1023"> and use a.src=e+'-'+a.src instead of a.src=e+a.getAttribute(y).

@williammalo
Copy link
Author

@maettig
Thats a brilliant idea! I'll implement it when I have the time!
Edit:
I just remembered why I didn't do this.
The browser loads the default automatically.
So to prevent loading a useless image, you have to either put no src attribute, or make the src a data url of a one pixel gif or something.

@shinsenter
Copy link

My idea 136 bytes: (posted from my phone, not tested)

function respImg(s,u,d,l){document.images.map(a=>{d=a.dataset,for(l=d[s].split(',');l.length||a.offsetWidth>w=l.shift();)a.src=w+d[u]})}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment