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

The sizes="" attribute only works with width-constrained images #86

Closed
eeeps opened this Issue Jan 3, 2014 · 22 comments

Comments

Projects
None yet
10 participants
@eeeps

eeeps commented Jan 3, 2014

(Moved from #85, where Yoav was suggesting an 'h' descriptor within the sizes="" attribute for completely different reasons.)

Could such a descriptor also enable height-based selection? I'd be all for that, if there's an elegant way to integrate it into the syntax and if it doesn't complicate the choosing algorithm too much...

<source sizes-h="100vh" srcset="large.jpg 768w 1024h, small.jpg 384w" />

?

While height-constrained layouts (especially responsive ones) aren't common, they're out there. It's much more common to see slideshow modes that constrain on both height and width. To accommodate that sort of thing, though—defining boxes instead of lengths—the syntax + the source selection might have to get a bit hairy...

@tabatkins

This comment has been minimized.

Show comment
Hide comment
@tabatkins

tabatkins Jan 3, 2014

I had planned to do exactly this, but I couldn't come up with an elegant way to do height-based selection. I didn't give it a ton of thought, though - it's very possible for there to be a good method that I just didn't come up with. I'm open to doing this if we can figure it out.

Dealing with both width and height is quite a bit more difficult, but not impossible, particularly if we just allow something like sizes="contain|cover", which is sufficient for slideshow uses I think.

tabatkins commented Jan 3, 2014

I had planned to do exactly this, but I couldn't come up with an elegant way to do height-based selection. I didn't give it a ton of thought, though - it's very possible for there to be a good method that I just didn't come up with. I'm open to doing this if we can figure it out.

Dealing with both width and height is quite a bit more difficult, but not impossible, particularly if we just allow something like sizes="contain|cover", which is sufficient for slideshow uses I think.

@tabatkins

This comment has been minimized.

Show comment
Hide comment
@tabatkins

tabatkins Jan 3, 2014

Wait, I think I'm dumb. The w unit in a source list isn't used for "selection" directly. It specifies the width of the image source in image pixels; once you know the size of the <img> (either from sizes='' or width='' or whatever), then the image source width is converted to an image source density, and that's what's used in the selection algorithm (which is completely browser-defined).

So, using height in sizes='' would work the same way - you'd have to give a height to all your sources (or we can figure out something with ratios, if we wanna get fancy), and then the browser'll convert that into a density like normal.

Doing cover/contain constraints is identical, except we can't tell a priori whether we'll be calculating the density from the width or the height, as that depends on the relative aspect ratios of the viewport and the image source.

So, concrete proposal:

We add an optional "h" unit to the srcset syntax as well, as proposed above in the OP.

We extend the grammar of sizes, so that each value, rather than just being a <length>, is one of:

  1. [width | height]? <length> (defaulting to width - this is the current behavior).
  2. [cover | contain] <length>{2}? (defaulting to 100vw 100vh)

The MQ part of sizes values is unchanged.

We change the algorithm to parse a srcset attribute so that if it finds a source with both a w and h unit, it takes the first such one and considers that the canonical ratio. It then fills in the width/height of any other sources that are missing one of the values with that ratio information.

We then change the algo to normalize the source densities to use either the width or the height, depending on the sizes mode, to calculate the density. Sources missing the required dimension are dropped from the list.

tabatkins commented Jan 3, 2014

Wait, I think I'm dumb. The w unit in a source list isn't used for "selection" directly. It specifies the width of the image source in image pixels; once you know the size of the <img> (either from sizes='' or width='' or whatever), then the image source width is converted to an image source density, and that's what's used in the selection algorithm (which is completely browser-defined).

So, using height in sizes='' would work the same way - you'd have to give a height to all your sources (or we can figure out something with ratios, if we wanna get fancy), and then the browser'll convert that into a density like normal.

Doing cover/contain constraints is identical, except we can't tell a priori whether we'll be calculating the density from the width or the height, as that depends on the relative aspect ratios of the viewport and the image source.

So, concrete proposal:

We add an optional "h" unit to the srcset syntax as well, as proposed above in the OP.

We extend the grammar of sizes, so that each value, rather than just being a <length>, is one of:

  1. [width | height]? <length> (defaulting to width - this is the current behavior).
  2. [cover | contain] <length>{2}? (defaulting to 100vw 100vh)

The MQ part of sizes values is unchanged.

We change the algorithm to parse a srcset attribute so that if it finds a source with both a w and h unit, it takes the first such one and considers that the canonical ratio. It then fills in the width/height of any other sources that are missing one of the values with that ratio information.

We then change the algo to normalize the source densities to use either the width or the height, depending on the sizes mode, to calculate the density. Sources missing the required dimension are dropped from the list.

@igrigorik

This comment has been minimized.

Show comment
Hide comment
@igrigorik

igrigorik Jan 3, 2014

So, once again, trying a (basic) example.. does this make sense:

  <picture>
    <source sizes="(max-width: 30em) contain 30vh, (max-width: 50em) 50vw"
            srcset="pic400.jpg 400w 200h, pic800.jpg 800w, pic1200.jpg 1200w">
    <img src="pic400.jpg" alt="The president giving an award.">
  </picture>

Let's say I'm on an IPhone 5 (320 x 568px viewport, DPR: 2.0):

  • The image should occupy 30% of viewport height
  • 568px * 2DPR * 0.3 ~= 340px and based on 400w 200h, the w/h ratio is .5, so..
  • UA downloads pic800.jpg (400px height) and downscales on the client

Not sure if I'm using the right markup, but does that look about right?

It seems like there would be a lot of edge cases to cover once we get into both vw/vh in sizes plus cover vs. contain. Maybe it's just me, but I'd love to see some hands on examples... easier to grok than spec language. :)

igrigorik commented Jan 3, 2014

So, once again, trying a (basic) example.. does this make sense:

  <picture>
    <source sizes="(max-width: 30em) contain 30vh, (max-width: 50em) 50vw"
            srcset="pic400.jpg 400w 200h, pic800.jpg 800w, pic1200.jpg 1200w">
    <img src="pic400.jpg" alt="The president giving an award.">
  </picture>

Let's say I'm on an IPhone 5 (320 x 568px viewport, DPR: 2.0):

  • The image should occupy 30% of viewport height
  • 568px * 2DPR * 0.3 ~= 340px and based on 400w 200h, the w/h ratio is .5, so..
  • UA downloads pic800.jpg (400px height) and downscales on the client

Not sure if I'm using the right markup, but does that look about right?

It seems like there would be a lot of edge cases to cover once we get into both vw/vh in sizes plus cover vs. contain. Maybe it's just me, but I'd love to see some hands on examples... easier to grok than spec language. :)

@tabatkins

This comment has been minimized.

Show comment
Hide comment
@tabatkins

tabatkins Jan 3, 2014

The contain or cover keywords need either 0 or 2 values - 0 just defaults to "the viewport" (identical to specifying 100vw 100vh, 2 defines a rectangle explicitly that it'll fill.

It sounds like, from the following text, that you meant to say height rather than contain. In that case, yes, your interpretation is correct.

tabatkins commented Jan 3, 2014

The contain or cover keywords need either 0 or 2 values - 0 just defaults to "the viewport" (identical to specifying 100vw 100vh, 2 defines a rectangle explicitly that it'll fill.

It sounds like, from the following text, that you meant to say height rather than contain. In that case, yes, your interpretation is correct.

@yoavweiss

This comment has been minimized.

Show comment
Hide comment
@yoavweiss

yoavweiss Jan 3, 2014

Member

@tabatkins - the proposal sounds great (and would also resolve #85).

One question regarding height based sizes - what do we do with percentage based lengths? Can we simply treat them as percentages of the viewport height (so, identical to vh)?

e.g. in (max-width: 30em) height 30%, (max-width: 50em) 50%, is the height 30% part parsed as 30% of the viewport height? Can it be replaced by height 30vh? (Just like the 50% part can be replaced by 50vw)

Member

yoavweiss commented Jan 3, 2014

@tabatkins - the proposal sounds great (and would also resolve #85).

One question regarding height based sizes - what do we do with percentage based lengths? Can we simply treat them as percentages of the viewport height (so, identical to vh)?

e.g. in (max-width: 30em) height 30%, (max-width: 50em) 50%, is the height 30% part parsed as 30% of the viewport height? Can it be replaced by height 30vh? (Just like the 50% part can be replaced by 50vw)

@tabatkins

This comment has been minimized.

Show comment
Hide comment
@tabatkins

tabatkins Jan 3, 2014

Yeah, definitely.

tabatkins commented Jan 3, 2014

Yeah, definitely.

@eeeps

This comment has been minimized.

Show comment
Hide comment
@eeeps

eeeps Jan 4, 2014

This looks great. Modes + sensible defaults, requiring no change to the already-proposed syntax to get the already-propsed functionality... perfect!

Thinking through the syntax and some edge cases with my own example...

<picture>
  <source
    sizes="(width < 32em) contain, (width >=32em) contain 80vw calc(100vh - 10em)"
    srcset="full.jpg 2048h 1024w, half.jpg 1024h, quarter.jpg 512h, eighth.jpg 256h" />
  <img src="eighth.jpg" alt="¡Obama mambo!" />
</picture>

In "cover" or "contain" modes:

  • what happens if only zero or one length is supplied? Hunch: the first specified value is always a width, and default values (100vw/100vh) get substituted for any missing values.
  • what happens when the srcset dosen't have both an h and a w on any of its sources, and is therefore unable to determine the image's aspect ratio? Hunch: the CSS default replaced element size (300x150 CSS pixels) is used for any missing, needed length. This could lead to some frustratingly silent bugs for authors... but it could also be a way to handle cases where the dimensions supplied in srcset don't match the mode, e.g. <source sizes="width 100%" srcset="pic.jpg 1024h, small.jpg" /> would work equivalently to <source sizes="width 100%" srcset="pic.jpg 300w 1024h, small.jpg 300w 150h" />. Or should that throw some sort of error?

eeeps commented Jan 4, 2014

This looks great. Modes + sensible defaults, requiring no change to the already-proposed syntax to get the already-propsed functionality... perfect!

Thinking through the syntax and some edge cases with my own example...

<picture>
  <source
    sizes="(width < 32em) contain, (width >=32em) contain 80vw calc(100vh - 10em)"
    srcset="full.jpg 2048h 1024w, half.jpg 1024h, quarter.jpg 512h, eighth.jpg 256h" />
  <img src="eighth.jpg" alt="¡Obama mambo!" />
</picture>

In "cover" or "contain" modes:

  • what happens if only zero or one length is supplied? Hunch: the first specified value is always a width, and default values (100vw/100vh) get substituted for any missing values.
  • what happens when the srcset dosen't have both an h and a w on any of its sources, and is therefore unable to determine the image's aspect ratio? Hunch: the CSS default replaced element size (300x150 CSS pixels) is used for any missing, needed length. This could lead to some frustratingly silent bugs for authors... but it could also be a way to handle cases where the dimensions supplied in srcset don't match the mode, e.g. <source sizes="width 100%" srcset="pic.jpg 1024h, small.jpg" /> would work equivalently to <source sizes="width 100%" srcset="pic.jpg 300w 1024h, small.jpg 300w 150h" />. Or should that throw some sort of error?
@tabatkins

This comment has been minimized.

Show comment
Hide comment
@tabatkins

tabatkins Jan 4, 2014

Following a cover/contain keyword, you must supply either zero or two lengths. Zero is identical to supplying 100vw 100vh - it refers to the viewport. Supplying only one value violates the syntax, and will cause the <source> to be ignored.

Hmm, good point on none of them having both lengths - you need the aspect ratio so you can compare it with the ratio of the contain/cover rect. I'll have to think on this.

Regarding unneeded dimensions, such as giving a h value when the mode is width, the unneeded dimension is simply ignored. This means that in your first example, the first source has no relevant dimensions, and so is treated as 1x, same as the second source.

However, it will still affect the intrinsic size of the image. Since the canonical ratio is taken from the first such image, in your second example the intrinsic width will be 100vw and the intrinsic height'll be 341.3vw (calc(100vw * 1024 / 300)).

tabatkins commented Jan 4, 2014

Following a cover/contain keyword, you must supply either zero or two lengths. Zero is identical to supplying 100vw 100vh - it refers to the viewport. Supplying only one value violates the syntax, and will cause the <source> to be ignored.

Hmm, good point on none of them having both lengths - you need the aspect ratio so you can compare it with the ratio of the contain/cover rect. I'll have to think on this.

Regarding unneeded dimensions, such as giving a h value when the mode is width, the unneeded dimension is simply ignored. This means that in your first example, the first source has no relevant dimensions, and so is treated as 1x, same as the second source.

However, it will still affect the intrinsic size of the image. Since the canonical ratio is taken from the first such image, in your second example the intrinsic width will be 100vw and the intrinsic height'll be 341.3vw (calc(100vw * 1024 / 300)).

@eeeps

This comment has been minimized.

Show comment
Hide comment
@eeeps

eeeps Jan 4, 2014

If we're going to discard <source> elements with the wrong number of sizes lengths in the first case, rather than supplying default values, it probably makes sense to discard cover/contain'd sources whose aspect ratio is indeterminate, too?

eeeps commented Jan 4, 2014

If we're going to discard <source> elements with the wrong number of sizes lengths in the first case, rather than supplying default values, it probably makes sense to discard cover/contain'd sources whose aspect ratio is indeterminate, too?

@tabatkins

This comment has been minimized.

Show comment
Hide comment
@tabatkins

tabatkins Jan 4, 2014

Oh yeah, that makes sense.

On Sat Jan 04 2014 at 1:25:09 PM, eeeps notifications@github.com wrote:

If we're going to discard elements with the wrong number of sizeslengths in the first case, rather than supplying default values, it
probably makes sense to discard cover/contain'd sources whose aspect ratio
is indeterminate, too?


Reply to this email directly or view it on GitHubhttps://github.com/ResponsiveImagesCG/picture-element/issues/86#issuecomment-31589011
.

tabatkins commented Jan 4, 2014

Oh yeah, that makes sense.

On Sat Jan 04 2014 at 1:25:09 PM, eeeps notifications@github.com wrote:

If we're going to discard elements with the wrong number of sizeslengths in the first case, rather than supplying default values, it
probably makes sense to discard cover/contain'd sources whose aspect ratio
is indeterminate, too?


Reply to this email directly or view it on GitHubhttps://github.com/ResponsiveImagesCG/picture-element/issues/86#issuecomment-31589011
.

@zcorpan

This comment has been minimized.

Show comment
Hide comment
@zcorpan

zcorpan Feb 25, 2014

I think we should wait with adding this until the current proposal has implementation experience. If I recall correctly from the picture face-to-face in Paris last year, there was consensus that height-based selection is rare and does not need to be supported (yet).

zcorpan commented Feb 25, 2014

I think we should wait with adding this until the current proposal has implementation experience. If I recall correctly from the picture face-to-face in Paris last year, there was consensus that height-based selection is rare and does not need to be supported (yet).

@yoavweiss

This comment has been minimized.

Show comment
Hide comment
@yoavweiss

yoavweiss Apr 22, 2014

Member

@zcorpan: Do you propose that we start shipping srcset's 'w' descriptor, and only then see if 'h' should be added? (either for the purpose of height based images, or to provide authors with means to set the image's display dimensions to avoid re-layouts (per #85 ))

Member

yoavweiss commented Apr 22, 2014

@zcorpan: Do you propose that we start shipping srcset's 'w' descriptor, and only then see if 'h' should be added? (either for the purpose of height based images, or to provide authors with means to set the image's display dimensions to avoid re-layouts (per #85 ))

@zcorpan

This comment has been minimized.

Show comment
Hide comment
@zcorpan

zcorpan Apr 22, 2014

Yeah. Actually I think we should wait with adding new stuff until what we have now is implemented in WebKit, Blink, Gecko and IE. If we add too many things we risk vendors rejecting the whole thing. "Baby steps"...

zcorpan commented Apr 22, 2014

Yeah. Actually I think we should wait with adding new stuff until what we have now is implemented in WebKit, Blink, Gecko and IE. If we add too many things we risk vendors rejecting the whole thing. "Baby steps"...

@Wilto

This comment has been minimized.

Show comment
Hide comment
@Wilto

Wilto Apr 22, 2014

Member

+1 to shipping piecemeal, so long as we keep in mind that it might make feature testing a little more complicated (we can test for sizes independent of picture easily enough—testing for h support separate from w support might get complicated). If there’s anything we can do to mitigate that complication, I am 100% into it.

Member

Wilto commented Apr 22, 2014

+1 to shipping piecemeal, so long as we keep in mind that it might make feature testing a little more complicated (we can test for sizes independent of picture easily enough—testing for h support separate from w support might get complicated). If there’s anything we can do to mitigate that complication, I am 100% into it.

@zcorpan

This comment has been minimized.

Show comment
Hide comment
@zcorpan

zcorpan Apr 22, 2014

That's where future-compatible error handling comes in. It might be a bit ugly to test for it, and #152 would make it async, but it should be possible.

For instance <img srcset="foo 1h 1x"> would load foo if h is not supported but not if it is.

zcorpan commented Apr 22, 2014

That's where future-compatible error handling comes in. It might be a bit ugly to test for it, and #152 would make it async, but it should be possible.

For instance <img srcset="foo 1h 1x"> would load foo if h is not supported but not if it is.

@yoavweiss

This comment has been minimized.

Show comment
Hide comment
@yoavweiss

yoavweiss Oct 14, 2014

Member

A use-case that came up on twitter RE 'h' descriptor support: this site displays height constrained images, and width only sizes makes little sense for it.

Member

yoavweiss commented Oct 14, 2014

A use-case that came up on twitter RE 'h' descriptor support: this site displays height constrained images, and width only sizes makes little sense for it.

@tigt

This comment has been minimized.

Show comment
Hide comment
@tigt

tigt Jan 16, 2015

+1 on adding an h descriptor. I'm working on a project where images would act like contain based on a larger container (to make a long story short, it's <img> inside <foreignObject> inside inline SVG), and height-constraining is critical.

tigt commented Jan 16, 2015

+1 on adding an h descriptor. I'm working on a project where images would act like contain based on a larger container (to make a long story short, it's <img> inside <foreignObject> inside inline SVG), and height-constraining is critical.

@anselmh

This comment has been minimized.

Show comment
Hide comment
@anselmh

anselmh Jan 17, 2015

Member

Or in short it could become handy when object-fit: contain (or similar techniques as mentioned above) is in use. I think photo galeries are the main target for this.

Member

anselmh commented Jan 17, 2015

Or in short it could become handy when object-fit: contain (or similar techniques as mentioned above) is in use. I think photo galeries are the main target for this.

@ckrack

This comment has been minimized.

Show comment
Hide comment
@ckrack

ckrack Oct 23, 2015

+1 for adding contain / cover keywords.
I am not sure an h descriptor is necessary if we have those.

ckrack commented Oct 23, 2015

+1 for adding contain / cover keywords.
I am not sure an h descriptor is necessary if we have those.

@tigt

This comment has been minimized.

Show comment
Hide comment
@tigt

tigt Oct 23, 2015

It's possible to hack this logic in today, but it's ugly.

<img sizes="(min-aspect-ratio: 4/5) 80vh">

tigt commented Oct 23, 2015

It's possible to hack this logic in today, but it's ugly.

<img sizes="(min-aspect-ratio: 4/5) 80vh">
@neptunian

This comment has been minimized.

Show comment
Hide comment
@neptunian

neptunian Nov 18, 2015

+1 for h in srcset on the img tag. The browser currently fetches the wrong image for a height constrained Lightbox viewer which, of course, isn't meant to scroll. h is the height of the viewport. In order to find best size and only providing widths i have to calculate the best width myself.

neptunian commented Nov 18, 2015

+1 for h in srcset on the img tag. The browser currently fetches the wrong image for a height constrained Lightbox viewer which, of course, isn't meant to scroll. h is the height of the viewport. In order to find best size and only providing widths i have to calculate the best width myself.

@zcorpan

This comment has been minimized.

Show comment
Hide comment
@zcorpan

zcorpan Aug 29, 2017

Let's continue this discussion in whatwg/html#2973

Links to sites that would benefit from this, so a solution can be evaluated against real-world cases, would be very useful.

zcorpan commented Aug 29, 2017

Let's continue this discussion in whatwg/html#2973

Links to sites that would benefit from this, so a solution can be evaluated against real-world cases, would be very useful.

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