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

[css-grid][css-sizing] Aspect Ratio #333

Open
fantasai opened this issue Jul 20, 2016 · 52 comments
Open

[css-grid][css-sizing] Aspect Ratio #333

fantasai opened this issue Jul 20, 2016 · 52 comments

Comments

@fantasai
Copy link
Collaborator

@fantasai fantasai commented Jul 20, 2016

Grid & Flexbox make the aspect ratio problem more urgent, since they're so much better at flexible sizing than previous layout models...

Jen Simmons wrote:

I wish big time there were a way to transfer a calculated size from one dimension to the other. AKA… I define columns to be 1fr each. And I want the cells to be squares (or always have a 16x9 ratio, or whatever — but to maintain a fixed aspect ratio). How can I define the rows to be 1fr-from-the-column-calculation?? I want that.

@fantasai fantasai changed the title [css-sizing] Aspect Ratio [css-grid][css-sizing] Aspect Ratio Jul 20, 2016
@fantasai

This comment has been minimized.

Copy link
Collaborator Author

@fantasai fantasai commented Jul 20, 2016

Filing also under Grid, because it needs to be handled in a way that also works with grid-template-rows/cols.

@fantasai

This comment has been minimized.

Copy link
Collaborator Author

@fantasai fantasai commented Jan 15, 2018

https://lists.w3.org/Archives/Public/www-style/2018Jan/0023.html is a related problem; we could solve it if HTML calculates an aspect-ratio value to inject at the preshint level alongside width/height. We should file a follow-up issue with HTML once we've addressed this issue in CSS.

@ewanm89

This comment has been minimized.

Copy link

@ewanm89 ewanm89 commented Feb 19, 2018

How about a simple ew relative unit added that is percentage of element width?

Then we can just height: 100ew; to make something square or height: 56.25ew for a 16:9 box?

Obviously with an addendum that ew is ignored on the width property. This way, it can apply to all elements as they already work?

@tobireif

This comment has been minimized.

Copy link

@tobireif tobireif commented Mar 31, 2018

This feature really is needed. It's a common use case to have to ensure a certain aspect ratio for each item, eg in Flexbox or Grid, through all viewport widths / element widths.

There are many results for just one hack
https://www.google.com/search?q=flexbox+aspect+ratio+padding-top+100%25
and eg https://css-tricks.com/aspect-ratio-boxes/

We need a real solution.

@ewanm89 wrote

How about a simple ew relative unit added that is percentage of element width?

Then we can just height: 100ew; to make something square or height: 56.25ew for a 16:9 box?

I think I like it.

@tobireif

This comment has been minimized.

Copy link

@tobireif tobireif commented Apr 13, 2018

Another aspect ratio ticket: #1173

@tabatkins tabatkins removed the css-grid-2 label Apr 30, 2018
@tobireif

This comment has been minimized.

Copy link

@tobireif tobireif commented May 11, 2018

@fantasai wrote:

Filing also under Grid, because it needs to be handled in a way that also works with grid-template-rows/cols.

The Grid label unfortunately has been removed. I hope it will get added back.

@SelenIT SelenIT added css-grid-2 and removed css-grid-2 labels May 11, 2018
@tabatkins

This comment has been minimized.

Copy link
Member

@tabatkins tabatkins commented May 11, 2018

We removed the label because it's not a blocker for Grid 2; it's a Sizing issue. We'll want to think about Grid when designing a solution, but in the meantime it's clogging up our view of what needs fixing for Grid. ^_^

@ewanm89

This comment has been minimized.

Copy link

@ewanm89 ewanm89 commented Jun 23, 2018

While I would agree with the principle, the sizing issue has been something that should have been fixed decades ago. And it is just getting more and more desperate without a fix in sight.

@tobireif

This comment has been minimized.

Copy link

@tobireif tobireif commented Jun 24, 2018

Having an element width "ew" unit would be so useful ... I already use it via EQCSS. An example from one of my projects:

@element .page {
  img[src$=".svg"] {
    width: 30ew;
  }
}

The nice thing is that if .page has a max-width, the effective ew value will stop growing after that max width. With vw the effective value would continue to grow with the viewport.

And it could be a nice way of specifying aspect ratios (as @ewanm89 wrote earlier), eg height: 100ew in order to get a 1:1 ratio / a square.

@jonjohnjohnson

This comment has been minimized.

Copy link

@jonjohnjohnson jonjohnjohnson commented Jun 24, 2018

width: 30ew;

This specific example of ew unit confuses me. Are you setting the img to 30% of the width of the .page element? So the img ew unit comes from the parents width? Or are you somehow wanting to set the width of the img to 30% of what the width of the img would compute to if left unset?

Regardless, I'd be more interested in a property or method (#820 (comment)) that comes with constraints on display and box, cleanly interacting with min/max-height/width and values like min/max-content/min()/max()/etc... something to more cleanly accomplish this... http://jsbin.com/yuvaka/9/edit?html,output

@tobireif

This comment has been minimized.

Copy link

@tobireif tobireif commented Jun 25, 2018

This specific example of ew unit confuses me.

It's code from an actual project, and it works 😀

The more typical element query would look like this, for example:

@element .page and (max-width: 422px) {
  /* Inside this block, the element-width unit "ew" is based on the .page element. */
}

Are you setting the img to 30% of the width of the .page element?

Yep, that's what this EQCSS-powered code does.

So the img ew unit comes from the parents width?

It comes from the .page element, which could be the parent of the image element, but it could also be a far higher ancestor for example.

The docs are at https://elementqueries.com/ -> "ew (element width)" "EW Units",
and (with more info) at https://tomhodgins.github.io/element-queries-spec/element-queries.html#ew .

Some more instances of "ew" units in use:
https://tobireif.com/demos/grid/view_demo_source/
-> search-in-page for all "ew;" .
(The demo itself is at https://tobireif.com/demos/grid/ .)

Regardless, I'd be more interested in a property or method [aspect-ratio specific]

Having a property (or set of properties) specifically for aspect-ratio would be great!

The "ew" unit is a fundamental part of element queries / container queries, and it could also be used for ensuring any aspect ratio:

@element #foo {
  #foo {
    height: 100ew;
  }
}

... but having one or more properties specifically for aspect-ratio would be even better (and I hope we'll get native element queries including element-width units in any case).

@Dan503

This comment has been minimized.

Copy link

@Dan503 Dan503 commented Aug 22, 2018

Are you setting the img to 30% of the width of the .page element?

Yep, that's what this EQCSS-powered code does.

That wouldn't be how an ew unit works in real CSS though.

I think if ew was used on the width property it would equate to the same as if you used %.

I'm glad the grid tag was removed. This is a unit that should be usable anywhere like the vw unit, not just on grid items.

Imagine how great it would be to be able to write font-size: 20ew,. Now you can have text that scales with the size of its container rather than the size of the viewport! (font-size: 20vw;)

@tobireif

This comment has been minimized.

Copy link

@tobireif tobireif commented Aug 22, 2018

That wouldn't be how an ew unit works in real CSS though.

It could be spec'd to work just as in EQCSS.

I think if ew was used on the width property it would equate to the same as if you used %.

@element .select-any-element-here-not-necessarily-the-parent and (max-width: 422px) {
  /*
  Inside this block, the element-width unit "ew" is based on the selected element.
  It can be any element.
  */
}

This is a later example from above:

@element #foo {
  #foo {
    height: 100ew;
  }
}

This is a unit that should be usable anywhere like the vw unit, not just on grid items.

Yes, sure!

Perhaps you want to open a new ticket for the ew unit? (there's isn't one yet)

Imagine how great it would be to be able to write font-size: 20ew,. Now you can have text that scales with the size of its container rather than the size of the viewport! (font-size: 20vw;)

In
https://tobireif.com/demos/grid/
https://tobireif.com/demos/grid/view_demo_source/
there is for example font-size: 57ew;.

But even better for that type of use case would be to be able to say "always fit this line of text in this container (by adjusting property foo eg font-size or letter-spacing), no matter what font is used".

Related: #2528

@SebastianZ

This comment has been minimized.

Copy link
Contributor

@SebastianZ SebastianZ commented Aug 23, 2018

This is a later example from above:

@element #foo {
  #foo {
    height: 100ew;
  }
}

This is a unit that should be usable anywhere like the vw unit, not just on grid items.

Yes, sure!

Perhaps you want to open a new ticket for the ew unit? (there's isn't one yet)

Why open a new issue? This issue is about adding a way to define an aspect ratio. And the ew unit is one possible solution for it, so it belongs in here.

What should be discussed separately is the @element rule defining the element things like the ew unit relate to.

Sebastian

@tobireif

This comment has been minimized.

Copy link

@tobireif tobireif commented Aug 23, 2018

Why open a new issue?

Because it's a potentially separate feature, and has many, many use cases beyond being one potential option for ensuring aspect ratios.

This issue is about adding a way to define an aspect ratio. And the ew unit is one possible solution for it, so it belongs in here.

Yes it sure can be discussed here! ... as far as it pertains to the use case of specifying aspect ratios.

And the ew unit has many other use cases so it would sure be sensible to open a separate ticket in addition to that.

This aspect ratio ticket here might well get closed as soon as there's a solution which doesn't involve or require "ew" units - then there'd be no ticket for all the use cases that the ew unit solves (eg specifying font-size based on an some element's with).

What should be discussed separately is the @element rule defining the element things like the ew unit relate to.

You wrote that the ew unit is one possible solution for it, so it belongs in here. All parts and aspects of one possible aspect ratio solution eg

@element #foo {
  #foo {
    height: 100ew;
   // eg plus minmax()
  }
}

can be discussed here as long as it specifies an aspect ratio (and people are working on element queries anyways, see https://github.com/tomhodgins/cq-usecases , so there's no need for a new ticket for that).

@jensimmons

This comment has been minimized.

Copy link

@jensimmons jensimmons commented Oct 22, 2018

This past week, we wrote a draft at: https://drafts.csswg.org/css-sizing-4/#ratios

@tobireif

This comment has been minimized.

Copy link

@tobireif tobireif commented Oct 22, 2018

This past week, we wrote a draft at: https://drafts.csswg.org/css-sizing-4/#ratios

From a quick look:

Very cool 👍

Regarding the options: option B "min-height: 1ar" is nicely descriptive, and it requires just one line (as opposed to option A).

@Archibald2

This comment has been minimized.

Copy link

@Archibald2 Archibald2 commented Oct 23, 2018

@nhoizey I'm coming round to thinking it would be better to use percentage lengths as with vw and vh. So here's another option:

div {
min-height: 100%w;
}
article {
max-width: 150%h
}
@tremby

This comment has been minimized.

Copy link

@tremby tremby commented Oct 24, 2018

Hopefully this isn't too dumb a question, but what is tr? I see it and can only think of "table row".

@tremby

This comment has been minimized.

Copy link

@tremby tremby commented Oct 24, 2018

Oh, never mind, it was a dumb question. Either the draft changed in the last day or so from ar to tr (it's "transfer ratio"), or I didn't read the draft thoroughly enough the first time!

@SelenIT

This comment has been minimized.

Copy link
Collaborator

@SelenIT SelenIT commented Oct 25, 2018

@tremby it changed: #3225

@Archibald2

This comment has been minimized.

Copy link

@Archibald2 Archibald2 commented Oct 25, 2018

With regard to the draft at https://drafts.csswg.org/css-sizing-4/#ratios, I think "Intrinsic Aspect Ratios" should be changed to "Specific Aspect Ratios". While an image for example has an intrinsic aspect ratio, my understanding is that proposed 'aspect-ratio' property will specify a fixed aspect ratio for an element.

@nigelmegitt

This comment has been minimized.

Copy link

@nigelmegitt nigelmegitt commented Oct 26, 2018

tldr:

Aspect ratio is a thing in video, and we shouldn't create new problems there. Encouraging the viewport to be a different aspect ratio to the content has an accessibility impact.

Longer version:

Just want to call out that there's a potential impact here on users of video, who might be confused by this. In video it is common for different aspect ratios to be used and to modify the size of the video element automatically based on the content being played.

If a video element is given a specific aspect ratio, and that does not match the aspect ratio of the video content being played, what should happen?

For example, video content aspect ratio is 16:9, video viewport is 4:3. Should the video get black bars top and bottom, or should the central 4:3 section be shown only, omitting the 12.5% on either side?

This is a big deal for subtitles and captions authored with specific positions in mind, if those positions are specified with respect to the video viewport. It is typical to position subtitles to avoid obscuring important action happening in the video, for example a person's face when they are talking, the ball in a sports game, etc. It is important to have a clear positioning model in this case.

At the very least, whatever the implementation does with the video in this case needs to be available to player js code so that it can try to get the positioning correct.

Apologies if this is not the right place to raise this question. It just seems that introducing aspect ratio to CSS may exacerbate this issue, or confuse users, even if it is already possible to set the size of a video element explicitly to whatever aspect ratio is needed. For example now, it is possible to set max-width: 100%; alone on a video element, and the height is resolved automatically based on the aspect ratio of the content.

@Dan503

This comment has been minimized.

Copy link

@Dan503 Dan503 commented Oct 26, 2018

@nigelmegitt set the height and width of the video using CSS to a square aspect ratio or something and see what happens.

It typically will display black bars but you can use object-fit to alter how the video is displayed.

@nigelmegitt

This comment has been minimized.

Copy link

@nigelmegitt nigelmegitt commented Oct 26, 2018

@Dan503 thanks, it may well be that all we need here is an informative note directing readers who think they've found the answer to their video aspect ratio problems to the correct place, i.e. CSS Images.

@ddamato

This comment has been minimized.

Copy link

@ddamato ddamato commented Oct 29, 2018

@jensimmons jensimmons added this to Discussion in Aspect Ratios Oct 31, 2018
@nhoizey

This comment has been minimized.

Copy link
Contributor

@nhoizey nhoizey commented Nov 5, 2018

Fluid video (that has an aspect ratio, like 16x9), with fixed-height controls running along the length of the video directly underneath. I remember this being super common in the days of flash player for video. I haven't seen this since people switched away from Flash, but perhaps it's still common.

@jensimmons I don't think it is still common indeed, but here is at least one example with LinkedIn Learning:
https://www.linkedin.com/learning/photoshop-cc-2019-new-features/photoshop-20-will-change-how-you-work

@astearns astearns removed the Agenda+ F2F label Nov 13, 2018
@eeeps

This comment has been minimized.

Copy link
Contributor

@eeeps eeeps commented Nov 13, 2018

Issue 4 in the spec asks:

aspect-ratio: attr(width px) / attr(height px);

[...]

Can we just slip this aspect-ratio rule into the UA default style sheet for images, so that they have an aspect ratio while they load? This would avoid the need for extra reflows after loading.

This is an interesting idea for how to solve the same problem that the proposed intrinsicsize attribute (on <img> and <video>) is attempting to solve. intrinsicsize solves it at a different level, by setting/overriding the image's intrinsic size (or aspect ratio), rather than establishing a default extrinsic ratio for it.

So I guess first of all – I just want to cc some intrinsicsize people who have thought through this problem – @tigt @ojanvafai @loonybear

Second – I have two questions about how the proposed rule may break existing content.

Specifying width and height as percentages was valid in HTML 4.01. Is there existing content that will break if those percentages are interpreted as px (I guess?) and fed into this rule?

Currently, in order to achieve fluid sizing without aspect-ratio distortion on an image with width/height, you have to "undo" the extrinsic size set in the cross axis by setting it to auto:

<img width="300" height="200" style="width: 100%; height: auto;" />
<!-- without `height: auto` this would be locked to a height of 200px, even as the width was fluid/variable -->

I suppose this new default would obviate that: a UA default aspect-ratio would trump the height="" presentational hint, so we could just write

<img width="300" height="200" style="width: 100%;" />

and get a 3:2 fluid img (that was 3:2 even before the image loaded and an intrinsic size was known). Yay! But... is there any existing web content that relies on or expects the previous behavior? Maybe, uh, spacer gifs?

@tigt

This comment has been minimized.

Copy link

@tigt tigt commented Nov 13, 2018

One could change the UA selector to be more like img:not([width*="%"], [height*="%"]), but I don't know if all CSS engines would run that performantly enough for every page.

Can attr() interpret as a CSS <length> falling back to px?

@loonybear

This comment has been minimized.

Copy link

@loonybear loonybear commented Nov 13, 2018

  1. Maybe I didn't understand your question. But if width and height are already specified (either in pixel or percentage), intrinsicSize does not change the aspect ratio for the layout, it will only override what naturalWidth and naturalHeight return.

  2. <img intrinsicsize="300 x 200" style="width: 100%;" /> maybe? I will test it and get back to you.

long story short, if intrinsicSize is not specified, nothing is changed (unless you turn on feature policy unsized-media policy, which set the default intrinsicSize to "300 x 150"); if intrinsicSize is used it doesn't do anything more than overriding the value of the intrinsic size of the image.

@eeeps

This comment has been minimized.

Copy link
Contributor

@eeeps eeeps commented Nov 13, 2018

@loonybear my fault for not really asking a question! I guess my first implicit question, which you answered, was "would there be any weird interactions between intrinsicsize and this default aspect-ratio rule?" (sounds like, no 🎉). My second question is, given what you understand about the problem space, are there any problems you forsee with the proposed UA default style? The intrinsicsize explainer calls a solution built on width and height out for being “not really backwards compatible” – I've tried to think through some reasons why that might be, above, but I'm asking if you or @ojanvafai can be more specific about what was meant by this.

@eeeps

This comment has been minimized.

Copy link
Contributor

@eeeps eeeps commented Nov 13, 2018

Maybe it would be weird to use height and width to set intrinsic sizes, but it's perfectly fine to re-use them globally to set extrinsic ratios. And, for the purposes of no-reflows-after-image-loading,

<img intrinsicsize="300x200" style="width: 100%;" />

and (in the presence of the proposed UA default style)

<img width="300" height="200" style="width: 100%;" />

are functionally equivalent – they're just two good ways to solve the same problem. In which case, great! (and sorry for all of the comments).

@jonjohnjohnson

This comment has been minimized.

Copy link

@jonjohnjohnson jonjohnjohnson commented Nov 17, 2018

Just wanted to make sure folks know of...

Both for commenters to learn from and for those involved then to feel free to chime in.

@loonybear

This comment has been minimized.

Copy link

@loonybear loonybear commented Nov 19, 2018

aspect-ratio works on all replaced elements whereas intrinsicSize so far only works on HTMLImageElement and HTMLVideoElement. The intention is for it to work well with feature policy 'unsized-media' which deals with problems that cause layout instability (content jumping around on the web page).

But if aspect-ratio could cover all the cases we need intrinsicSize for (being able to determine the layout size before downloading the image), then I don't think there's a need for intrinsicSize.

So how would aspect-ratio achieve the case of:

<div style="width: 75vw">
  <img src="my-image.jpg" aspect-ratio="4x3" style="max-width: 100%">
</div>

i.e. we want to set the image's width to min(width of container, intrinsic width of image). Is it possible for aspect-ratio to do so before downloading any image data.

Another question would be, how does it work with responsive images, how will the naturalWidth and naturalHeight be updated if an aspect-ratio is specified?

@fantasai

This comment has been minimized.

Copy link
Collaborator Author

@fantasai fantasai commented Jan 4, 2019

@eeeps So about your backwards-compat concerns in #333 (comment) ...

Specifying width and height as percentages was valid in HTML 4.01. Is there existing content that will break if those percentages are interpreted as px (I guess?) and fed into this rule?

I'm expecting this to be implemented in C++ rather than CSS, but in the case of CSS percentages would end up invalid here (invalidating the rule) and in C++ we would certainly want to do the same.

Currently, in order to achieve fluid sizing without aspect-ratio distortion on an image with width/height, you have to "undo" the extrinsic size set in the cross axis by setting it to auto:

Yes. I'm not proposing to change that: the width and height attributes would still map to the corresponding CSS properties. The proposal is simply that they would also map into an aspect-ratio property.

@fantasai

This comment has been minimized.

Copy link
Collaborator Author

@fantasai fantasai commented Jan 4, 2019

The main concern wrt Web compat is someone putting in width and height attributes that don't correspond to the image's actual aspect ratio, and then also overriding those width and height attribute values with different width and height CSS values one of which is auto.... I don't anticipate this being particularly common, but it could happen. :)

@bramus

This comment has been minimized.

Copy link

@bramus bramus commented Jun 25, 2019

With a huge chance of side-tracking this thread (due to not really knowing where exactly to post this reply) or the risk of proposing something that got proposed before, here goes:

Glad to see the addition of aspect-ratio being talked and discussed about, as the need is real (once wrote an extensive post on this myself).

Thinking further on this, this solution is somewhat limited: it only solves the aspect ratio problem, and nothing else outside of that.

A more broader solution – I think – could be the introduction of a val() function, which could be used to solving the aspect-ratio thing, but also other future things.

The val() function would work like the var() function (which reads the value of a custom property) but then for reading values from other properties. The val() function also differs from var() in such a way that it yields the computed value of the property. Recalculation would happen upon resize events and the like. Combine val() it with calc() and you're good to go.

In code, it would result in something like this:

.box {
  width: 100%;
  height: calc(val(width) * 16 / 9);
}

Of course it needs some more tweaking and thought: What if you want percentages (for use within rgba for example)? Perhaps a second argument that defines the requested unit (say you want percentages or ems instead of pixels) could be added? Or a whole different function that converts units could be introduced (unit() would be a nice one)? Or … — Things might easily get over-complicated, which is not really feasible I guess.

I know, it's a bit side-tracky this reply, but I do see a future for this kind of addition. Don't let this comment hinder the release of aspect-ratio though, the sooner it lands the better! Maybe it could later be retrofitted as an underlying part of aspect-ratio? Quite sure all the smart people involved will have a clear idea on this all, or will immediately see a lot of flaws in my brainfart above, as you've already pondered about it quite a lot.

@matthew-dean

This comment has been minimized.

Copy link

@matthew-dean matthew-dean commented Aug 27, 2019

@bramus

I think people have circled around permutations of this idea. I think where it starts to break down is combinations like:

.box {
  width:  calc(val(height) * 9 / 16);
  height: calc(val(width) * 16 / 9);
}

However, IIRC, custom properties have some sort of algorithm to break recursion, so that this is valid:

.box {
  --width:  calc(var(--height) * 9 / 16);
  --height: calc(var(--width) * 16 / 9);
}

I can't recall the algorithm, but I think it has something to do with figuring out the computed value first, so maybe this would work as well?

@matthew-dean

This comment has been minimized.

Copy link

@matthew-dean matthew-dean commented Aug 27, 2019

@bramus In short, though, I think your point is very valid. People have wanted an "element-relative unit" or some way to calculate the allocated height / width of an element for some time. I discussed it in this proposal: WICG/container-queries#12

However, in this comment, @dbaron addresses the performance penalty of "calculated units" (I proposed aw ah units, and in this thread, someone proposed something similar with ew / eh)

The introduction of ai, aw, etc. units causes the performance penalty in (1) every time they are used. So while these units may look cheap, they're actually a somewhat expensive feature that I'd be hesitant to make a unit for because I think developers have a reasonable expectation that a unit in CSS is something that's cheap to compute and doesn't introduce substantial performance penalties. (That said, we've broken this expectation before, but I think this case is worse.)

So, in short, the value of aspect-ratio over a unit or a calculation may be performance. But I don't know that it represents a substantially larger amount of math to do layout, since the ratio must be multiplied by the calculated width / height. And a unit value is that sum * ([unit]/100). It's one more operation, but..... 🤷‍♂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Aspect Ratios
Discussion
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.