Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Media-query-like data-src option #35

Open
mjau-mjau opened this issue Sep 25, 2013 · 9 comments
Open

Media-query-like data-src option #35

mjau-mjau opened this issue Sep 25, 2013 · 9 comments

Comments

@mjau-mjau
Copy link

I see you already have similar issues #9 and #16 but since my post is quite elaborate, I would like make a separate request. I agree with @Reyncor that the retina method is too rigid in a world of responsive designs, and there are additional reasons by example:

In a responsive design, I might have a default 800 px wide image, that scales down to 320 px on an iPhone 5. The image will therefore already be retina-ready for the iPhone and I don't want to load a 2x file for this device. However, for devices like iPad 3, it would make sense to load a 2x file. In another scenario, I might have thumbnails in columns where I in fact do want to load 2x for all retina devices. What does this mean? Simply put, it means we don't really want the retina alone to dictate what image we should be loading. There are two solutions:

Media-query-like data-src
I have done a lot of research on how others are solving this problem, and by far the best and most flexible solution I came across is the Interchange plugin from Zurb, which uses media queries directly in the data-src:

data-interchange="[/path/to/default.jpg, (only screen and (min-width: 1px))], [/path/to/bigger-image.jpg, (only screen and (min-width: 1024px) and (min-device-pixel-ratio: 2))]"

This allows full flexibility to load multiple image-sizes based on device screen size, pixel-ratio and orientation. http://foundation.zurb.com/docs/components/interchange.html

Multiplier
In many cases for images in responsive designs, a threshold value can be calculated by pixel-ratio * device-width. However, this method is not flexible and only applies to certain scenarios.

I prefer to avoid being limited to naming conventions for different file-sizes, because I use a CMS with an image processor where images can be called by URI like this '/render/w730-h-c3:2-q95//file.jpg'. This is one of the reasons I liked unveil in the first place, because we can set names independently.

I know unveil is supposed to be simple, and I wouldn't normally request such a nice simple plugin to do more than it is supposed to. However, the image-switching mechanism is a single process, and you can't really have multiple scripts competing to set the image src! Right now, I am using a custom unveil JS adapted to work in similar fashion as method 1 above.

Thanks!

@luis-almeida
Copy link
Owner

Hi Karl,

First of all, I really appreciate all the replies you added to some of the other open issues. Big thanks on that!
Moving on to the "retina" issue. When I first made this code available, there wasn't an option to define a data-src-retina. I added it later on because it seemed like a good idea and it would actually be helpful for the simplest use-cases. I was aware that the possibility to load a second image src wouldn't solve all the issues of a fully responsive layout but I added the "feature" anyway.
I kinda regret doing that now since, just like you said, most of the times you don't really want the retina alone to dictate what image should be loaded, the screen size is equally important to make that decision. Unveil definitely never aimed to solved this problem well.
That said I think making Unveil more flexible wouldn't be that hard but I'm not sure if agree with the way interchange is solving the problem.
There's just too much configuration going on. The data-interchange attribute is basically holding an array of arrays and all of these is being rendered in the DOM where I think it doesn't belong. I believe we can have the same functionality in a much simpler way.
What I have in mind is adding an option where people can pass a function and decide themselves where to look for the most appropriate src path for the image. And example of what that could look like:

$("img").unveil({
  dataFilter: function(image) {
    var dataAttr;
    if (matchMedia("(min-width: 768px)").matches) {
      dataAttr = "data-src-something";
    } else if (matchMedia("(min-width: 1280px)").matches) {
      dataAttr = "data-src-something-else";
    }
    return image.getAttribute(dataAttr);
  }
})

I think this is a better approach. I prefer it because it pushes all the responsibility for choosing the right data-src to the user. This way:

  • The plugin gets a lot more flexible.
  • We manage to keep it almost as simple as it is now.
  • We only need to store the src paths in the DOM.

But lets hear what people say first. I'd definitely like to hear some feedback.

@mjau-mjau
Copy link
Author

Thanks for the comprehensive reply Luis -

After some thought, I can live with that solution!

At first glance, I thought there was a flaw, as a group of pre-defined dataFilters may be appropriate for one section of unveiled images, but perhaps not so much for another. However, it occurred to me that this is still flexible because the various data-src-attributes can be populated on a per-section basis. In my case, I would likely create 3 dataAttributes data-src-small-retina, data-src-large-retina in addition to the default data-src. In some sections of my layout, the data-src-small-retina image would be the same as the data-src image (responsive image), in other sections, the data-src-small-retina image would be the same as the data-src-large-retina image (collapsing columnized thumbnails). It is rare I would need to use more than 2 image sizes, but I would still need 3 attributes to select them appropriately for separate sections.

Some high-traffic websites like newspapers might even want to add data-src-small for low-res non-retina mobile devices, just so images load very quickly at minimal bandwidth consumption.

I would suggest you still keep data-src as native default fallback for two cases:

  1. If dataAttr does not get assigned in the dataFilter function, value would automatically default to data-src.
  2. If a matched src attribute for a specific img element does not exist, it should default to data-src.

Another thing to mention, is the device-pixel-ratio media query. Because of all the vendor-prefixes for min-device-pixel-ratio, it would probably be better to use a native javascript method window.devicePixelRatio. I would probably populate my default function like this:

$("img").unveil({
  dataFilter: function(image) {
    var dataAttr;
    if (matchMedia("(min-width: 768px)").matches && window.devicePixelRatio >= 1.5) {
      dataAttr = "data-src-retina-large";
    } else if (window.devicePixelRatio >= 1.5) {
      dataAttr = "data-src-retina-small";
    } else { // Can be removed if dataAttr automatically reverts to 'data-src' if unassigned.
      dataAttr = "data-src";
    }
    return image.getAttribute(dataAttr);
  }
})

I guess the main challenge is making this method approachable to users who have not considered the somewhat intricate nature of loading different-size images in a responsive layout based on device screen size/orientation/pixel-ratio. But if they don't grasp it, they probably shouldn't be using it to much extent anyway.

I am finishing my new blog website, and once ready, I would be interested in writing a post about this and including Unveil as a recommended tool to achieve required result.

I would love to see this implemented in Unveil. Keep up the good work!

@luis-almeida
Copy link
Owner

What you're suggesting is what I have in mind as well.
This function dataFilter - perhaps it needs a better name - should only replace the hardcoded data-src-retina attribute for more flexibility. Unveil should always fallback to data-src so you don't need that extra step to make it work.
Also, unlike interchange that relies on window.matchMedia, if you need to support older browsers you could go for document.width instead.

I tend to agree that this might not be so approachable for new developers, but I think with the right documentation it's still quite easy to understand what's going on and how to make it work.

I'm looking forward for that blogpost. Let me know when it comes out!
Thanks for your feedback!

@mjau-mjau
Copy link
Author

Sounds great to me Luis, looking forward to see this functionality in unveil js.

Just for reference of topic, its interesting that webkit now supports the srcset attribute, which aims to solve "responsive images" natively in the browser without JS.
http://mobile.smashingmagazine.com/2013/08/21/webkit-implements-srcset-and-why-its-a-good-thing/

Also, would be cool to see unveil on CDNJS, where I like to load my scripts for fast often cached access:
http://cdnjs.com/

@o-l-e
Copy link

o-l-e commented Oct 1, 2013

👍

@suncat100 would love to see your solution, i am looking at similar issues with Unveil and the cms Stacey (that i think you are also using). Currently i am also trying to figure out how to load images (with stacey/unveil) and somehow getting the variable heights of the images before unveiled, to avoid the jump/flicker.

@mjau-mjau
Copy link
Author

@o-l-e yes I am also using Stacey, and will have the page up shortly so you can view my examples then. Right now I am actually using the SLIR image processor to load a really small version of the image into the original src, so it responds to the layout since the aspect is identical. For example, I may load a 3x2 px image at 0% compression, making the placeholder file less than 1kb. This is not optimal however, as it still creates a bunch of unnecessary requests, so I will be looking into adapting the method explained here (scroll down to "The Padding Bottom Hack"):
http://mobile.smashingmagazine.com/2013/09/16/responsive-images-performance-problem-case-study/

@mjau-mjau
Copy link
Author

@luis-almeida any timeline with this cool feature you proposed? I am looking forward to it ;)

@alancwoo
Copy link

alancwoo commented Jul 5, 2014

@luis-almeida Also very interested in this functionality should there be any further development, I'm using unveil with foundation and it would be great to be able to utilize a set of images for different screen sizes. I do understand that unveil set out to be a rather focused, minimal tool, but I suppose it's impossible to use interchange and unveil together as they would definitely conflict.

@milansimek
Copy link

I have created a pull request #147 which adds srcset support

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants