Open gregwhitworth opened 8 years ago
I've added some demos to a PR, including a few ways I have worked with aspect ratios using CSS and JS!
Over at the EQCSS project we have also wondered about making an aspect-ratio
property, but we realized that in order to do that, we would want/need CSS to be aware of things like nativeWidth
and nativeHeight
, and it sure would be helpful if there was a value like currentWidth
as well that was aware of each element's own width as CSS was being processed by the browser.
@tomhodgins can you expound on what you mean by nativeWidth/nativeHeight? Are you talking about the device, the intrinsic of a replaced element with no constraints? Regarding currentWidth, we definitely know that during layout, which is precisely where any form of aspect-ratio would be applied, whether it's declared in markup or CSS.
Sure! By nativeWidth
and nativeHeight
we were thinking of the native resolution of the content at 100%. So for this image:
The nativeWidth
and nativeHeight
would be equal to 200px. For a video like this the nativeWidth
would be 980px and the nativeHeight
would be 640px even though it's not specified anywhere.
The idea with something like currentHeight
would be for doing something like:
video {
width: 100%;
height: calc(currentWidth / (nativeWidth / nativeHeight));
}
I made a little video of playing around with responsive aspect ratios: Responsive Aspect Ratio in CSS using Element Queries to help illustrate the technique I'm talking about 😍
@tomhodgins Thanks for the video, cleared things up for me in what you were actually wanting because I was going to suggest max-content
but you're actually wanting the computedWidth
. It's worth noting, that this won't allow any usage of %s
or auto
s because you won't know this at cascade time, the only reason you can do this sufficiently in JS is because it's interacting on the used width.
That is a huge downside to this property. Take flex for example, at computation time, it may be 50px wide but the flexible space after layout may allow it to be 100px yet you're setting your height up to be proportional to 50px rather than that of the 100px. While it would be nice to have in CSS, I actually think this makes more since in JS since Layout has completed at that time, thus all styles are fully resolved and can be trusted as complete.
I've been experimenting with responsive aspect ratios a little more!
This morning I was thinking: “Wouldn't it be nice if elements could detect their own orientation, whether landscape or portrait?” I know @media
queries do this, but it would be really helpful when using element queries if it could do that. So I came up with this demo:
<style>
@element 'div' {
$this {
background: eval("
orient($it)=='square' ? 'blue'
: orient($it)=='portrait' ? 'red'
: 'lime'
")
}
}
</style>
<script>
function orient(el){
var square = el.offsetWidth == el.offsetHeight,
portrait = el.offsetWidth < el.offsetHeight,
landscape = el.offsetHeight < el.offsetWidth
return square? 'square' : portrait? 'portrait' : 'landscape'
}
</script>
This is a JavaScript function that can determine when an element is square
, portrait
, or landscape
and apply a value based on that - but as you can see the JS-in-CSS is a little gross to look at and you'd have to include a few lines like this in your CSS for each property where you wanted to set a different value based on the status of the element's orientation.
So I thought: "What if you could express the same thing as a container query set a style scoped to one element with a condition like (orientation: )
?"
So I got busy hacking on the EQCSS source and defined some new features. First is support for an (orientation:)
condition for scoped styles with a syntax like this:
@element "div" and (orientation: square) {
$this {
background: orchid;
}
}
@element "div" and (orientation: portrait) {
$this {
background: darkturquoise;
}
}
@element "div" and (orientation: landscape) {
$this {
background: greenyellow;
}
}
And then I really got to thinking, “What if there was a min-aspect-ratio
or max-aspect-ratio
that could apply as a container query to any element, not just as a @media
query to the browser itself?” So I came up with a couple more demos that allow a syntax like this:
@element "div" and (min-aspect-ratio: 16/9) {
$this {
background: greenyellow;
}
}
@element "div" and (max-aspect-ratio: 16/9) {
$this {
background: tomato;
}
}
This formats the aspect ratio in a so it's width/height, separated by a /
slash character. A ratio of 1/1 would be square, a ratio of 4/3 would be wider than it is tall, etc.
I'm pretty excited about these new features, but the most thrilling thing is that the polyfill works in all browsers IE8 and up! Check out browser testing in IE8 :D
Hopefully this helps us figure out responsive aspect ratios a little more! I can't wait to use these new aspect conditions this week - I have some responsive ads to design and this is going to come in handy for making one design that can adapt to all formats the ad might need to be displayed in (banner, square, skyscraper, etc).
Let me know any thoughts or if you have any questions about these demos!
We probably need to step back a little and think about the usecases we can think of and not think about syntax etc. (I just deleted all my response about how useful nativeWidth would be etc..)
Just a reminder I built this demo, perhaps we could build some similar ones that demo other use cases? https://jonathankingston.github.io/logical-sizing-properties/demo/index.html
After initial conversations with a designer (it was weeks ago and going from memory) we had where some may be duplicates:
We probably need to step back a little and think about the usecases we can think of and not think about syntax etc
This week I have some responsive ads to design so I'm only doing what I need to do and keeping you all posted. But whatever it is I'm doing, it shouldn't prevent anybody else from brainstorming in any direction they feel like!
The syntax I've been describing on elements ((orientation: )
and (min-aspect-ratio: )
and (max-aspect-ratio: )
) is already defined and currently supported on @media
queries..
(I just deleted all my response about how useful nativeWidth would be etc..)
…for what benefit?
Just a reminder I built this demo, perhaps we could build some similar ones that demo other use cases?
What other use-cases do you envision? I'm a designer, and when I started thinking about making responsive ads this week I wrote down a few things:
Here's the sheet of paper with my questions on it that motivated my experiments yesterday.
If I knew I needed a 250x250 version, and a 600x100 version of an ad I could already do different form factors with predefined dimensions, but that wouldn't help me if the ad needs to scale with a locked aspect ratio sometimes as well!
Imagine (like I have to design today) that you are building an ad that will go in the middle of an article of text. It will be advertising 1 of 6 books (I have 6 ads to make for this). If this were an image-based ad we would have to drop that into the page and scale it so its text was always legible. If it is the full-column-width for phone users that ad will have to be a certain height. If we visit the same page on desktop there's a lot more room. We would either need to:
max-width
and float or center it once it hits that max size (that's the text wrapping decisions, etc)…but I'm thinking, “What if we can design this ad so it can scale with a locked aspect ratio sometimes, but also allow it to be as wide as there is horizontal room, and still be able to target it with styles and layout changes based on the dimensions it finds itself with, instead of predefined widths”.
I think being able to sniff an element's (orientation:)
will come in handy, but not as useful as being able to define a range of responsive aspect ratios! So here's another demo, showing both a min-aspect-ratio
and max-aspect-ratio
showing how versatile aspect-ratio-detecting element queries can be!
This demo has an element you can resize. The element itself knows when it's roughly square
, very wide, or very tall. This is the use-case I had in mind yesterday!. Note that the 'square' aspect ratio in this demo isn't stricly 1/1
like (orientation: square)
would be, its what might be considered squareish and covers the range of aspect ratios near 1/1 from (min-aspect-ratio: .9/1)
to (max-aspect-ratio: 1.2/1)
:
It works, it's great, and it's exactly what I need. It's going to be a great week! 🤓🎨
I appreciate the enthusiasm, but I tend to agree with @jonathanKingston in this case. Not that I disagree with your goal here it's just you're expanding the scope drastically. Let's think about this in terms of versions, what is necessary for v1. Personally, I think for v1 a bool
should suffice; this doesn't keep us from evolving this, even within the same property but I think this will actually solve the most common use cases that I've seen where the padding hack is utilized. I by no means want to stop the experimenting though as when we say, "yes this is a common pattern" you may have already defined how best to solve it through implementing various JS approaches. Might I propose opening an issue, for each additional feature request you have, such as orientation and min/max, and even nativeWidth. There are valid things to solve, and should be done on their own thread.
From my experience as a Front-end Developer I think of the following use cases.
This is probably the biggest use case, especially on slow connections (often the norm not an exception), content shifting can get really annoying. I wrote more about this here . The most common method to solve this is the padding-bottom hack at the moment.
In many cases this could be avoided if we would have a aspect-ratio property in CSS,
.ratio-16-9 {
aspect-ratio: calc(16/9);
object-fit: cover;
}
In addition to aspect-ratio developers can use object-fit for media (eg. often the case for videos) which may not be exactly the defined aspect-ratio. This could be used for all kind of media: img, img with srcset, picture, video, iframe, embed, object
The CSS property can also be used for images inserted via CMS (assuming the CMS is *clever" and adds classes for the images based on the original size). For example, I could imagine Wordpress adding such classes, as they already output srcset now after inserting an image.
So, for all this cases a CSS-based solution would work, although surely not for every site (can't change the output of user input, not control over CMS....) but there is one case where a CSS-based solution will be hard to achieve. It is picture with art-direction with different aspect-ratio for different sources (eg. on big screens it is 16/9, on medium 2/1 and and small 9/16).
<picture>
<source media="(min-width: 750px)" srcset="large.jpg">
<source media="(min-width: 500px)" srcset="medium.jpg">
<img src="small.jpg" alt="Alternative text">
</picture>
Let's assume large.jpg has an aspect-ratio of 16/9 and medium.jpg of 2/1. In this case you would need to know the aspect-ratio for the different sources and you need to know the media attribute to get it working in CSS.
In this cases I think a HTML-based solution would be great:
<picture>
<source ratio="16/9" media="(min-width: 750px)" srcset="large.jpg">
<source ratio="2/1" media="(min-width: 500px)" srcset="medium.jpg">
<img src="small.jpg" alt="Alternative text">
</picture>
I am using ratio here as an attribute, but it is just an example to show you what I mean. So, in this cases the browser will define an aspect-ratio of 16/9 for the image if viewport > 750px and an aspect-ratio of 2/1 if between 500px and 750px.
A developer may however override this in CSS by setting aspect-ratio: none.
Apart from content shifting you may also want to use aspect-ratios in your design, eg. define a box with an aspect-ratio of 16/9. If the box is fullscreen this can already be achieved today with calc if the box is full width:
div {
width: 100vw;
height: calc(100vw / 16 * 9);
}
But it would be nice to get aspect-ratio for boxes smaller than 100vw.
Sorry for drifting into potential technical solutions but I thought it make sense here to show that both a CSS and a HTML-based solution will make sense for different use cases.
If you would like I can also build demos with all use cases I have in mind (maybe showing also the current hacks we use)?
Apart from content shifting you may also want to use aspect-ratios in your design, eg. define a box with an aspect-ratio of 16/9. If the box is fullscreen this can already be achieved today with calc if the box is full width:
Now you're talking my language again! I've just added element-based units to EQCSS that work much like the viewport units, except based on an element's dimensions instead of the viewport.
I added ew
, eh
, emin
, and emax
which could be really useful for your calc()
operations, since 100ew
would refer to the width of the element in pixels!
Your tech demo (that works today) would be as simple as:
<img src=http://staticresource.com/nebula.jpg>
<img src=http://staticresource.com/nebula.jpg style=max-width:50%>
<img src=http://staticresource.com/nebula.jpg style=max-width:25%>
<style>
img {
display: block;
margin: 0 auto;
width: 100%;
max-width: 100%;
object-fit: cover;
}
@element 'img' and (max-width: 500px) {
$this {
height: 25ew;
}
}
@element 'img' and (min-width: 500px) and (max-width: 700px) {
$this {
height: 50ew;
}
}
@element 'img' and (min-width: 700px) and (max-width: 900px) {
$this {
height: 75ew;
}
}
@element 'img' and (min-width: 900px) {
$this {
height: 100ew;
}
}
</style>
<script src=http://elementqueries.com/EQCSS.js></script>
And if you're wanting to write the ratio and calculate live like calc(16/9)
you could evaluate any calculation anywhere in EQCSS using eval("")
, so in this case eval("9/16*100")ew
will turn into -> 56.25ew
in the CSS, and then inside the element query something like 56.25ew
would be output as 281.25px
on the page if it were being applied to an element that was 500px
wide at the time, here's code just for one responsive aspect ratio element using ew
units and also using eval("")
in the code to retain the aspect ratio:
<img src=http://staticresource.com/nebula.jpg>
<style>
@element 'img' {
$this {
display: block;
width: 100%;
max-width: auto;
height: eval("9/16*100")ew;
object-fit: cover;
}
}
</style>
<script src=http://elementqueries.com/EQCSS.js></script>
@tomhodgins I really appreciate your work on EQCSS and would love to have ew
and eh
native in CSS but I think it will be hard to implement them and are out of scope for this proposal. So I think it makes sense to define an aspect-ratio
property and maybe an HTML attribute to solve 90% of the use cases today and add a separate proposal for ew
and eh
.
Maybe I am wrong and ew
and eh
are not so hard to implement and makes sense to implement together with aspect-ratio
.
I've been thinking about adding an aspect-ratio: ;
custom property to EQCSS, and I'll share where/how I'm stuck on implementing it, and why I'm reaching to other solutions other than aspect-ratio: ;
when I need to make responsive aspect ratios.
The three pieces of information you need to divine the correct dimensions are:
So let's say we have a iframe
that we want to be at a ratio of 1/1
(square, for easy math in the example) we may be able to do something like:
iframe {
width: 100%;
aspect-ratio: 1/1;
}
This gives us 3/3 of the pieces of information we need in order to say while the iframe is 500px
wide, the height should equal 500px
.
Likewise if we are supplied a height and the aspect ratio, we can guess its correct width:
iframe {
height: 250px;
aspect-ratio: 1/1;
}
Here again we have 3/3 pieces of information we need to calculate the aspect ratio so we can calculate it will be 250px
wide. Now consider these examples:
iframe {
width: 500px;
height: 200px;
aspect-ratio: 1/1;
}
We have 4/3 pieces of information, two are conflicting, and we need to find a way to set which rule 'wins' over the others. Should it be 500px
tall, or 250px
wide?
iframe {
width: 100%;
aspect-ratio: 1/1;
}
@media (min-width: 500px) {
iframe {
height: 300px;
}
}
Here we have a sometimes-present 4th piece of information - does it/should it win?
Since I haven't been able to figure out the answer to this I've been trying to find ways to have the aspect ratio calculate actual width
and height
values in my CSS, instead of trying to record the aspect ratio itself in CSS.
What do you think should win out between width
, height
, and a potential aspect-ratio
property? I'd love to see that syntax working, just haven't quite nailed it yet!
(One possibility is that aspect-ratio
wins over both width
and height
and only stops at max-width
and max-height
, but I'm not sure that's intuitive, or if that would be limiting, e.g. if iframe { width: 50px !important; aspect-ratio: 1/1; }
was a full-width square it would be a little confusing)
Did you see the draft, eg. example 3 covers some of your questions.
I'm not sure where in the draft it answers my questions, it seems to raise some of the same issues!
It is an early draft so there are open questions, but from what I understand from the draft it should work this way for your examples:
iframe {
width: 500px;
height: 200px;
aspect-ratio: 1/1;
}
Here it says in the spec: "If aspect-ratio is not none, but neither width nor height are underspecified for the element, aspect-ratio must have no effect."
So, in this case aspect-ratio would be ignored.
The other example:
iframe {
width: 100%;
aspect-ratio: 1/1;
}
@media (min-width: 500px) {
iframe {
height: 300px;
}
}
If the viewport is < 500px the iframe will have an aspect-ratio of 1/1 so if the 100% is 300px the height is also 300px. If the viewport is > 500px the aspect-ratio should probably also be ignored and the iframe would have a width of 100% and an explicit height of 300px.
Does this make sense for you?
Does this make sense for you?
I can comprehend what you're saying, but it doesn't really seem like a usable/viable solution for the problem we identify.
It seems like an aspect-ratio
that was so quick to not apply would be too easily 'cancelled' all the time during responsive styling, which would make depending on it a gamble and force you to either write even more code to ensure it never got cancelled, or to supply a non aspect-ratio
fallback for when/if it decides not to apply in a given situation.
Either way, I believe you can find the path forward when the solution is to write less code, not more code. Everything we add to CSS should reduce the complexity of the final output code and make it simpler for humans to read & write.
Edit: Here's an example where the element's width is used to set the height, and an example where the height is used to set the width:
<script src=http://elementqueries.com/EQCSS.js></script>
<img id=width src=https://s3-us-west-2.amazonaws.com/s.cdpn.io/67439/nebula.jpg>
<img id=height src=https://s3-us-west-2.amazonaws.com/s.cdpn.io/67439/nebula.jpg>
<style>
img {
display: block;
max-width: 100%
width: 100%;
object-fit: cover;
}
@element '#width' {
$this {
width: 200px;
height: eval("9/16*100")ew; /* set by element width */
}
}
@element '#height' {
$this {
height: 200px;
width: eval("16/9*100")eh; /* set by element height */
}
}
</style>
Any updates on how an aspect-ratio
property would pick between conflicting width
and height
declarations?
In the past week I've made a couple more demos, one is like @justmarkup's 100vw
example. A syntax like this would work in this demo: height: calc(100ew / 560 * 315);
if you were giving the values for width and height. If CSS was aware of the native width or height, perhaps you could make that something like height: calc(100ew / nativeWidth * nativeHeight)
. Currently you can also use EQCSS to grab the existing width=""
and height=""
attributes present in the embed code from youtube to get this dynamically with something like height: calc(100ew / eval("width") * eval("height"))
. Anyway, my demo uses eval("")
instead of calc()
which means this demo will work even in browsers where calc()
lacks support: http://codepen.io/tomhodgins/pen/wovGev
@element 'iframe' {
$this {
width: 100%;
height: eval("height/width*100")ew;
}
}
Also, today I was brainstorming ways that knowing the aspect ratio of an element could allow you to do art direction better. You can have responsive image holders, but change the focal point of the image so the action is always most prominent in the frame, here's my demo for that: http://codepen.io/tomhodgins/pen/ZBEmjq
@element 'div' and (min-aspect-ratio: 1.5/1) {
$this {
background-position: 25% 30%;
}
}
@element 'div' and (max-aspect-ratio: 1/1.5) {
$this {
background-position: 20% 25%;
}
}
Are there more use cases we can build out?
How can we move forward on the problem we have all identified with aspect-ratio
?
Where is the best place to discuss things like ew
units, or exposing things like native width and height (or width=""
and height=""
attributes) to CSS? Could that be something as simple as: attr(width)
and attr(height)
usable anywhere in CSS?
I'd love to do whatever I can to help push this forward!
EDIT: I just saw this Portuguese website using a very similar syntax: http://www.imobiliarialisboa.com in the file: http://www.imobiliarialisboa.com/assets/css/iLine.eqcss
@element ".iElmImg" {
$this {
height: eval('width/3*2')px;
}
}
@element ".col-xs-6 .iElmImg" {
$this {
height: eval('width/416*183')px;
}
}
@element ".col-xs-8 .iElmImg" {
$this {
height: eval('width/757.33*249')px;
}
}
So there's somebody using a similar technique 'in the wild'
Hello again fellow CSScientists!
I'm currently away on my honeymoon, but in the absence of any apparent activity here on this I'm preparing to make a polyfill/demo of an aspect-ratio property for CSS as soon as I get back home.
Here's what I'm thinking: to add provisional support for an aspect-ratio
property to experiment with how it might work. What I'm curious about is to find a solution to the problem where a width
, height
, and aspect-ratio
are all specified for an element - what wins?
I'm also curious about the right way to go about experimenting with this. I don't want to write a plugin that supports a naked aspect-ratio
property in code in case that property ever does get added to CSS - should I prefix with something like -eq-aspect-ratio
? Are there any forseeable reasons why that wouldn't be ideal, or problems I might run into? I've never written support for a prefixed property before!
Here is the code I want to get working:
/* should be a square 500x500 */
div {
width: 500px;
-eq-aspect-ratio: 1/1;
}
/* should be a square 500x500 */
div {
height: 500px;
-eq-aspect-ratio: 1/1;
}
/* full-width square */
div {
-eq-aspect-ratio: 1/1;
}
/* ??? */
div {
width: 100px;
height: 500px;
-eq-aspect-ratio: 1/1;
}
Does anybody have thoughts on what should happen in that last example? I've been wondering if there is/should be a logical precedence to the defined sizes versus the aspect ratio. My gut instinct is that aspect-ratio
should be weaker than width or height, so if both are applied, the aspect-ratio
fails. My question is if this still makes sense if the aspect-ratio
has !important
and the width
and height
do not.
I'll be hacking on this in a few days when I get home, so all comments are welcome in the meantime as I'm stewing over how to implement this!
(Also, we need to fix the links to Jonathan's demos, unless they have been permanently removed. Both the link in the README as well as in this issue no longer resolve…)
It may be safer to do the custom property --aspect-ratio
; after all, that's what it is!
Maybe the question is what causes the most desirable behavior in browsers that understand width
/height
but not aspect-ratio
. To me, it makes sense to have a conflicting aspect-ratio
to set height
to auto
.
Best backwards compat for both specified would likely be ignoring aspect ratio. Likely sites will have to feature detect for this anyway.
On Tue, 22 Nov 2016, 15:06 Taylor Hunt, notifications@github.com wrote:
It may be safer to do the custom property `--aspect-ratio; after all, that's what it is!
Maybe the question is what causes the most desirable behavior in browsers that understand width/height but not aspect-ratio. To me, it makes sense to have a conflicting aspect-ratio to set height to auto.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/WICG/aspect-ratio/issues/1#issuecomment-262248661, or mute the thread https://github.com/notifications/unsubscribe-auth/AAUsLPF3tkUrrfCTwmnWN1yUdM1lW5NBks5rAvaxgaJpZM4KLZjD .
I'm opening this based on the minutes from TPAC. @jonathankingston and myself will need to provide usecases for when people utilize aspect ratio in the readme. Jonathan, if you could provide the rough use cases, I'm going to do a crawl where I find how often the % padding hack is utilized and on what types of elements.