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 · 57 comments
Open

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

fantasai opened this issue Jul 20, 2016 · 57 comments

Comments

@fantasai
Copy link
Collaborator

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
Copy link
Collaborator Author

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

@fantasai
Copy link
Collaborator Author

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
Copy link

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
Copy link

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
Copy link

Another aspect ratio ticket: #1173

@tabatkins tabatkins removed the css-grid-2 Subgrid; Current Work label Apr 30, 2018
@tobireif
Copy link

@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 Subgrid; Current Work and removed css-grid-2 Subgrid; Current Work labels May 11, 2018
@tabatkins
Copy link
Member

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link

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
Copy link
Contributor

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
Copy link

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
Copy link
Contributor

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

@tobireif
Copy link

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).

@nigelmegitt
Copy link

@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
Copy link

ddamato commented Oct 29, 2018

This is a use-case that an aspect-ratio unit may be helpful in:
https://stackoverflow.com/questions/49525893/css-aspect-ratio-set-width-of-child-element-based-on-dynamic-parent-height

@nhoizey
Copy link
Contributor

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

@eeeps
Copy link
Contributor

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
Copy link

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
Copy link

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link

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
Copy link

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
Copy link
Collaborator Author

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
Copy link
Collaborator Author

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
Copy link
Contributor

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
Copy link

@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
Copy link

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..... 🤷‍♂

@fantasai
Copy link
Collaborator Author

Forgot to post an update: CSSWG adopted an aspect-ratio property in the CSS Sizing Level 4 Working Drafts. We encourage you all to have a look and file issues if you see something we should consider. :) This is still a work in progress, but it's being actively implemented in conjunction with the spec in Blink and Gecko.

@Dan503
Copy link

Dan503 commented Jul 13, 2020

@fantasai in Example 6 of the aspect-ratio minimum section, the width of the child boxes adds up to 200px but the spec says it adds up to only 150px. Also the boxes are display: inline-block which means that the size would be a little bit larger than 200px because there would be a space between the two boxes. It might be better to use display: flex with flex-wrap: wrap in that example rather than display: inline-block to avoid having to also mention the size that the space between the two boxes takes up.

https://www.w3.org/TR/css-sizing-4/#aspect-ratio-minimum

@fantasai
Copy link
Collaborator Author

@Dan503 That example is correct: the "min-content" width is the narrowest width it can take without overflowing, so 150px.

@bramus
Copy link
Contributor

bramus commented Oct 10, 2021

(stumbled upon this issue while searching for something else) This issue can be closed, no?

@sdsnatcher
Copy link

The specific WICG Aspect Ratio Incubator Project was closed and there's a message on its README.md file redirecting the discussion to this issue here.

I wonder why this was done, since the Pixel Aspect Ratio isn't restricted to CSS. I can't even post a new issue there.

I'm trying like to bring awareness to the problem that the Pixel Aspect Ratio (PAR) is still not rendered correctly by any of the current browsers I tested. This is a metadata present inside JPG, PNG and GIF files.

A lot of content was created in the 80's and 90's that had non-square pixels.

For example, many legacy pixel art based on rectangular pixels (*1) are being destroyed, as the use case is still present and the users are doing workarounds by artificially stretching the images via resize to have the desired aspect ratio. Once the image is stretched like this, it's nearly impossible to restore it without loss.

The same issue affects all images (stills and video) captured from SDTV. NTSC had an effective resolution of 720x480, which means that it's pixels aren't square. Just like pixel art, users have no alternative other than artificially stretch the image to adjust it for square pixels, creating artifacts that will be impossible to cleanup later.

Inspired by the HTML AcidTests, I created the Pixel Aspect Ratio Acid Test, that can be seen in the link below. It will check if the browser renders two sets of images correctly.

http://frs.badcoffee.info/PAR_AcidTest/

*1: Read C64, CGA, EGA, VGA (320x200), SNES, MSX, Amiga, TurboGrafx-16, NEC PC-88 and nearly the majority of devices from the 80s, when square pixels were still an expensive luxury.

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

No branches or pull requests