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

A proposal for the sizes attribute #34

Closed
joemcgill opened this issue Jan 25, 2015 · 17 comments
Closed

A proposal for the sizes attribute #34

joemcgill opened this issue Jan 25, 2015 · 17 comments
Milestone

Comments

@joemcgill
Copy link
Member

After some thought, I have a proposal for how we might be able to incorporate the sizes attribute as it was meant to function in relation to the w descriptor in srcset. At present, the plugin does not set any sizes attribute on images because, by doing so, we would be giving the browser information about the intended layout width of the image relative to the page—information we do not have, and information which only the theme author (or someone implementing a theme) would know for certain.

However, as has been expressed in #15, #21, #29, and elsewhere, not setting a sizes attribute currently tells browsers (or PictureFill) that the image will be displayed at 100% of the viewport, which will often mislead to the browser into choosing an image from the source set list that is much larger than what is actually needed. Particularly when the image is actually being displayed at a much smaller layout width than the full viewport width (e.g., tablets, laptop/desktop screens, etc.).

For content images, we may not know the actual width of the image in a layout, but we might be able to assume that the maximum width of the image is the width of the original image selected (i.e., the one referenced by the src attribute) and build a sizes list accordingly. For example, if the original image that was chosen is 600px wide, we might be able to safely tell the browser that the image should never be larger than 600px wide. Or to put it in terms of a sizes attribute list, it would look like this:

sizes="(min-width: 600px) 600px, 100vw"

To extend this example, let's say we upload a 3000px wide image and WordPress makes the standard soft crops: medium 300px and large 1024px. Now let's assume we've chosen to embed the medium size image in our post. Currently, the plugin would embed that image with the following markup (omitting a sizes attribute):

<img class="size-medium" 
    src="http://mysite.com/wp-content/uploads/2015/1/sample-image-300x230.jpg" 
    srcset="http://mysite.com/wp-content/uploads/2015/1/sample-image-300x230.jpg 300w,
        http://mysite.com/wp-content/uploads/2015/1/sample-image-300x230.jpg -1024x768.jpg 1024w,
        http://mysite.com/wp-content/uploads/2015/1/sample-image-300x230.jpg 3000w"
    alt="6882791353_7d4a982544_o" width="300" height="230" 
/>

If I were viewing this image on a non-retina (1x pixel density) tablet with a viewport width of 1024px, the browser would assume that the image should be 100% of the screen and choose to load the large, 1024px image, when in fact, it should have chosen the 300px version. On a larger retina screen, we very well might get served the 3000px image when the 1024px version would be much more than adequate.

By adding a sizes attribute such that the first source size in the source size list matches (min-width: {{chosen-size}}) {{chosen-size}}, 100vw the markup from above would now be:

<img class="size-medium" 
    src="http://mysite.com/wp-content/uploads/2015/1/sample-image-300x230.jpg" 
    sizes="(min-width: 300px) 300px, 100vw"
    srcset="http://mysite.com/wp-content/uploads/2015/1/sample-image-300x230.jpg 300w,
        http://mysite.com/wp-content/uploads/2015/1/sample-image-300x230.jpg -1024x768.jpg 1024w,
        http://mysite.com/wp-content/uploads/2015/1/sample-image-300x230.jpg 3000w"
    alt="6882791353_7d4a982544_o" width="300" height="230" 
/>

In our above examples, the tablet would choose the 300px wide image and the retina screen would choose the 1024px wide image, a considerable bandwidth savings in both cases.

Given that the RICG has as recently as 10 days ago changed the proposed spec such that a srcset list using w descriptors without a corresponding sizes attribute would not assume a source size of 100vw but instead do nothing, as @aFarkas rightly pointed out in #29 (comment), we may end up needing to deal with the sizes attribute in a more explicit way no matter what.

I think this may be a sensible approach, but I'd love to get feedback before trudging down this path in case there be dragons of which I'm unaware. Thanks!

@tevko
Copy link
Member

tevko commented Jan 25, 2015

@joemcgill thank you for the incredibly detailed and well though out post. I agree completely with this idea as the default option. @Wilto what are your thoughts? @joemcgill would there be any reason for a theme developer to want to override this proposed functionality, and if so, how would they do that?

@joemcgill
Copy link
Member Author

Thanks Tim,

Giving developers a way to hook into and override the default functionality is something we would definitely need to consider. For content images (i.e. images inserted directly into posts through the editor) we could separate srcset and sizes into two distinct filters so they would be easier to override/disable. For the template tag tevkori_get_src_sizes($id, $name, $args), we could simply look to see if a sizes array was passed to an $args parameter and, if not, set our defaults based on the size of the image passed as the second $name parameter.

@chriscoyier
Copy link

Sounds smart to me re: sizes="(min-width: {{width of image}}) {{width of image}}"

At one point I guessed that something like sizes="(min-width: 800px) 50vw, 100vw" would be a sensible default and probably pretty close to true on a majority of sites.

Thoughts:

  • I know that I would definitely want to override this on my own site. Is the UI for that? Or hook or something?
  • I'd probably want different settings depending how the image is used. Images within post content very likely to be used differently than a featured_image

@aFarkas
Copy link

aFarkas commented Jan 26, 2015

@joemcgill
I like your pure idea, not the variation using (min-width: 800px) 50vw, 100vw.

But it seems there is still a slight misunderstanding regarding what changed about sizes:

The browser itself will always go to 100vw if sizes is missing or invalid. There was no change in the browser requirements, but there where some changes in the authoring requirements. And for backward capability reason the browser requirements will likely never change.

@joemcgill
Copy link
Member Author

@chriscoyier both good points.

In terms of overriding/removing, I imagine we would be adding the sizes attribute in a way that is filterable so you could alter the values before the output is returned. Would that be sufficient, in your view, or are you thinking of creating a UI in the WP admin for editing these settings?

I would also use different settings for featured images than I would use for content images, so we'd need separate filters or execution paths for those different use cases. Even so, I think the default logic could be the same for both. For example, featured images are often displayed in themes using a template tag like this:

<?php the_post_thumbnail( $size, $attr); ?>

We could use the value passed to $size as the default layout width unless a source size list was passed to the $attr parameter. If neither is passed, we use the function's default for $size, which in this case would be the post-thumbnail.

@kadamwhite
Copy link

are you thinking of creating a UI in the WP admin for editing these settings?

I'd lean towards not having a UI live as part of this plugin. It's not a bad idea—it could be a useful thing to prototype/implement as a separate plugin, and could be presented as a dashboard or integrated throughout a site. However, many of the less-technical WordPress users I know already get flummoxed at the number of options and panels available within the UI. Better to let the customization be an opt-in, and to try to provide sane defaults and utilities for theme developers to use.
</my-$0.02>:

@jhned
Copy link

jhned commented Jan 26, 2015

@joemcgill, we could also probably set part of the sizes attribute by checking if the $content_width variable is present.

I like your idea of splitting out srcset and sizes into two functions. I'm almost done with a first pass at how to incorporate the sizes attribute into the template tag tevkori_get_src_sizes($id, $name, $args). I'll post a pull request once I test it.

@joemcgill
Copy link
Member Author

Good point. Maybe it would be useful to use $content_width (if it's set) as a low-pass filter for users who lazily embed a full size image in their content when they could get by with the large, for example.

@tevko
Copy link
Member

tevko commented Jan 26, 2015

For anyone wondering, the goal for this plugin is to enable responsive images without the need for a UI. That being said, a plugin separate from this one (using this plugin as a dependency), that introduces a UI in order to make managing responsive images easier, would be pretty interesting

@jhned
Copy link

jhned commented Jan 26, 2015

ok @joemcgill, @tevko, I made a pull request (#35) for my update. I added an $args variable, which includes these arguments:

  1. sizes for the sizes attribute settings
  2. maintain_aspect_ratio, which runs the aspect ratio/hard crop check if true
  3. included_sizes to specify which WordPress image sizes to include
  4. excluded_sizes to specify which WordPress image sizes to exclude

I created a couple of filter functions to give devs a way to hook into the template tag tevkori_get_src_sizes itself, rather than image_send_to_editor or post_thumbnail_html.

This gives us both a hook to modify the output, and useful settings to specify how to modify the output.

@Wilto
Copy link
Member

Wilto commented Jan 26, 2015

Man, this is some great discussion—this is exactly how I was hoping things would play out once @tevko got the first iteration out the door.

We gotta start with the idea that any sensible default we come up with here is only going to be “technically correct” the same way a broken clock is “technically correct” twice a day: sizes is only valid if it matches the exact sizes necessary, which is gonna be a rare stoke of luck for anything we do there. So, what we need is this:

  1. A “sensible default,” and for that I am 100% into the ideas above. While it isn’t any more correct-on-paper than defaulting to 100vw, it is absolutely a step in the right direction.
  2. In terms of the end user, there’s never any need to mess with sizes, no matter what they upload or what they set for the automated sizes—as long as whatever we’re setting up in here is easily configurable by the theme author, we’re in very good shape. I don’t know a hell of a lot about editing/authoring themes and that’s tripping me up here, but I don’t imagine we’ll need to expose this on the I’m-just-trying-to-write-a-blog-post-here side of things.

So long as we make it easy for the theme authors, we can say “hey, use valid markup; write sizes to match your theme” without flinching—but we can’t rely on that 100%, so that reasonable default is absolutely necessary for the sake of the end users.

@xsynaptic
Copy link

Hi everyone! It looks like we've all been grinding away at some of the same issues. I was alerted to this project via Reddit, briefly corresponded with Tim, and figure I may as well see if I have anything to contribute to the discussion.

Over the last several months I have implemented support for srcset and sizes attributes in an image management plugin/component of my own devising, Ubik Imagery, and have faced a lot of same design challenges being discussed here (and no doubt elsewhere, this being kind of a hot topic at the moment). I opted to provide a couple of filter hooks for the sizes attributes for theme authors to hook into and manipulate on a conditional basis.

For an example of how this system of hooks interfaces with actual images in a theme have a look at this module. It's rather complicated but well-commented (a consequence of working through this without much of a reference and wanting to document everything for the benefit of others). I use a number of non-standard image layout conventions on my blog: full-width images, group images, ad hoc galleries of post thumbnails, etc. All of these are flex-width and, as such, required a fair amount of work to come up with something close to pixel-perfect values for the sizes attribute. Check out this post for an example of this markup in action.

Anyhow, I just wanted to share this stuff to provide an example of a full and (I hope) working implementation of responsive images in a WP plugin/theme combination. I've been working on this stuff for my own use and don't have any specific plans to develop it into something for the main WP plugin repository so perhaps it will be of some help here.

@zcorpan
Copy link

zcorpan commented Feb 10, 2015

Given that the RICG has as recently as 10 days ago changed the proposed spec such that a srcset list using w descriptors without a corresponding sizes attribute would not assume a source size of 100vw but instead do nothing

Not quite, the behavior is unchanged. It's just invalid markup to omit sizes when using w in srcset.

@joemcgill
Copy link
Member Author

@zcorpan My mistake, thanks for clarifying. At any rate, the main point is that we need a default way of handling default values for the sizes attribute, otherwise we will be generating invalid markup (i.e. using w descriptors without specifying sizes).

@aFarkas
Copy link

aFarkas commented Feb 11, 2015

...otherwise we will be generating invalid markup...

I really feel a little bit sorry about bringing the validity discussion up. For me this was just an unsubstantial formal argument. My main point is: Adding srcset with the width descriptor automatically without having sizes is mostly a bad thing.

In case validity is the only thing that is a concern: It has to be said, that the spec didn't change that much. Omitting the sizes attribute was 100% equivalent with writing explicitly sizes="100vw" and it is still equivalent from behavior. So if you want to do the exact same thing you did before you only need to add sizes="100vw" and you are expressing exactly the same thing you did before.

The fact, that you have problems with this easy fix is that you didn't wanted this behavior before. You only quietened your concerns with the excuse: "We are not doing something explicitly wrong, we are just doing it implicitly wrong."

And I must say, that all this discussion about this problem shows how huge and great this small spec change actually is, it forces developers to think about useful values inside the sizes attribute. This said you still don't need to handle sizes, if you don't want. But you should have something in place, that forces at least the theme author to handle sizes himself. My proposal was that the filters are only adding srcset, if they see a sizes attribute.

@tevko
Copy link
Member

tevko commented Feb 13, 2015

@joemcgill as discussed earlier, I'd like to move forward with the default sizes attribute. We also need to provide a responsible hook so that developers can customize the sizes attribute as needed.

That hook would need to be done via filtering the_content, and the function would need to be called from the themes functions.php file only. That way a theme change would revert back to the default sizes attribute and nothing would break.

Another issue is concerning featured images which won't be found in the_content. I'm not sure how we would look for these, but it still needs to function the same way that post images would function, so that changing a theme doesn't leave breaking changes

@jhned
Copy link

jhned commented Feb 13, 2015

@tevko, filtering the_content might be difficult. You'd basically be matching images based on regex, right? And you wouldn't have access to any of the image variables either.

In my pull request in #35, I added filters that worked in the scope of the tevkori_extend_image_tag and tevkori_filter_post_thumbnail_html functions.

Basically what happens is, those two functions start off by getting the srcset string, but then apply any filters that have been hooked in. That will probably be an easier way of hooking it in rather than the_content. Would that work?

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

9 participants