Skip to content
This repository has been archived by the owner on Jul 31, 2019. It is now read-only.

Working on an aspect-ratio polyfill #7

Open
tomhodgins opened this issue Nov 16, 2016 · 15 comments
Open

Working on an aspect-ratio polyfill #7

tomhodgins opened this issue Nov 16, 2016 · 15 comments

Comments

@tomhodgins
Copy link

tomhodgins commented Nov 16, 2016

Hi all, based on my comments in the other issue I have begun brainstorming and writing a polyfill for what an aspect-ratio property might look like. I currently have the logic figured out, and a regex that can extract this custom property from formatted CSS, I think I'm close to a working polyfill I just need to figure out how to list all CSS rules that affect a chosen element and determine if a width:; or height:; value has been assigned already in CSS before calculating the aspect ratio.

In thinking through how it should work, here's what I came up with:

Width Height Aspect-Ratio Calculated
height
height
width
nothing
✓ with !important nothing

This means any time there is both a width and height applied to the element in CSS, it would always take those values over the implied aspect-ratio, even if that aspect-ratio was marked !important.

For extracting values from formatted CSS. I have the following regex which will look for rules that contain -eq-aspect-ratio with the following syntax:

aspect ratio property = property name : width / height
property name = -eq-aspect-ratio
width = number with optional decimal and optional trailing digits
height = number with optional decimal and optional trailing digits

So here's the regex that will extract this and give us: a CSS selector, the width value, the height value:

/^(.*){.*-eq-aspect-ratio:\s*(\d*\.?\d+)\/(\d*\.?\d+)/gm

And here's my test with formatted CSS using one rule per line and some other simple transformations JavaScript can apply to any CSS to get it ready for extraction: https://regex101.com/r/kSMEeT/1

I wrote an almost working plugin yesterday on the plane - I'm going to keep toying around with it until I can get it working (by checking not the computed styles, but what CSS properties apply to each given element) but it's looking really hopeful and came together a lot faster than I thought it would!

Any thoughts on the precedence I have set in the table above?

Any comments on the prefix I have chosen for development -eq-aspect-ratio?

Any ideas about how such a plugin should be structured?

I'll post my polyfill here once I get it working!

@tomhodgins tomhodgins changed the title Working on an aspect-ratio polyfill Working on an aspect-ratio polyfill Nov 16, 2016
@gregwhitworth
Copy link
Contributor

I think this sums up my desire from an aspect ratio in CSS in regards to layout. I think a polyfill is a good first step at ensuring it all works like one would expect. I'm still not sold on the need for 16/9 or 4/3 type aspect ratios though. But for now I think we can keep it this way.

@gregwhitworth
Copy link
Contributor

@yoavweiss @zcorpan Do you all have any opinions on this - I know this aspect is firmly focused on the layout portion of aspect ratio but wanted to ensure you all are seeing this thread and if you have any opinions (eg: "this is preparser hostile" ;) ) on this before we go too far.

@gregwhitworth
Copy link
Contributor

@tomhodgins Have you done any spec work before? I think what you have above is enough to begin a specification and you can build your polyfill off of that spec. I'm happy to lend a hand if you need it, or we can get on skype/google hangout if that would help out.

@tomhodgins
Copy link
Author

Hey @gregwhitworth, when you say you're not sold on the need for 16/9 ratios or 4/3 do you mean that formatting with width/height as opposed to the calculated ratio in a value like 1.777 or 1.333, or do you mean the need for making elements match an aspect ratio?

Why I think the width/height ratio is nice is because most of the time a designer will be using this they will be aware of pixel dimensions of their video, image, or other content and may not be immediately aware that a video 513px x 384px is actually 4/3, but they could put 513/348 and be sure that no matter the actual resolution it shows up, the aspect ratio will be the same as the native resolution.

I'm hoping to have this working next week - I have to record a video before the end of this week so I won't have much more time to hack on it, but my current non-working WIP is at: http://codepen.io/tomhodgins/pen/YpGGVj?editors=1010

The parts I need to add are where the plugin lists all of the CSS rules that apply to an element in question and checks to see if there is a width:; or height:; applied to them, so it knows how to proceed with calculations, but this is the demo and demo HTML/CSS I will be building against!

@tomhodgins
Copy link
Author

@gregwhitworth Never done any spec work, I've been trying for almost 2 years now to either contribute to the RICG, inspire action within the RICG, or write an element query spec without the RICG for element queries as well and research and create a syntax that works for that, from which all my aspect ratio demos have been coming from lately.

I'm passionate and ready to help out, I just don't know how to move things from descriptions of behaviour and definitions of syntax with working demos and plugins and turn that into a draft, spec, proposal, or anything like that.

For now I've been having a lot of fun using these ideas but I would like it if where was a way we could standardize some of this behaviour — even if browsers weren't going to support it right away or ever — so at least those of us polyfilling and wanting to build tools to use in the meantime to do these things could have a common target to implement so the tools/code can be more interoperable and to reduce technical debt for early adopters.

My gmail is tomhodgins@gmail.com and you can find me on skype as user innovati :D

@gregwhitworth
Copy link
Contributor

I recommend we start with a shim - let's not worry about parsing out the CSS. This will make it much easier to design as you'll have to do this post layout anyways, mine as well not add the cost of parsing CSS in JS strings. I know shim doesn't sound as cool as polyfill - but it will be more performant and your code will be cleaner.

@tomhodgins
Copy link
Author

@gregwhitworth I'm a JS learner so I'm writing it in the way that I know how to make it work. Doing it as a shim sounds…shimpossible at the moment, but I'm willing to try ^_^ Where could I learn how to write this as a shim?

@gregwhitworth
Copy link
Contributor

I say, just do how you want it now - this is primarily for prototyping anyways, but if possible - abstract the logic as much away from the helper functions (CSS parsing, etc) as possible so that anyone looking at the logic can make sense of what is happening and comment on that and compare with the spec we write. This should be a pretty straight forward spec and polyfill so I wouldn't expect too much confusion or simple mistakes - but you never know :)

@tomhodgins
Copy link
Author

tomhodgins commented Nov 17, 2016

Hey @gregwhitworth, by isolating the logic do you mean making a demo like this: http://codepen.io/tomhodgins/pen/VmmMdO

<style>
  div {
    margin: 1em;
    color: black;
    background: lime;
  }
</style>

<div data-ratio=16/9>Ratio only</div>
<div data-ratio=16/9 data-width=200>Width supplied</div>
<div data-ratio=16/9 data-height=200>Height Supplied</div>
<div data-ratio=16/9 data-width=200 data-height=200>Width &amp; Height Supplied</div>

<script>
  var tag = document.querySelectorAll('[data-ratio]')

  for (i in tag) {

    var ratio = tag[i].getAttribute('data-ratio'),
        width = tag[i].getAttribute('data-width'),
        height = tag[i].getAttribute('data-height')

    if (ratio) {
      var rWidth = ratio.split('/')[0],
          rHeight = ratio.split('/')[1]
    }

    // Ratio
    if (ratio && !width && !height) {
      tag[i].style.height = tag[i].offsetWidth / (rWidth/rHeight) + 'px'
    }

    // Ratio + Width
    if (ratio && width && !height) {
      tag[i].style.width = width + 'px'
      tag[i].style.height = width / (rWidth/rHeight) + 'px'
    }

    // Ratio + Height
    if (ratio && !width && height) {
      tag[i].style.height = height + 'px'
      tag[i].style.width = height * (rWidth/rHeight) + 'px'
    }

    // Ratio + Width + Height
    if (ratio && width && height) {
      tag[i].style.height = height + 'px'
      tag[i].style.width = width + 'px'
    }

  }
</script>

@gregwhitworth
Copy link
Contributor

To some extent, I would do it a bit differently as you could still allow the width or height to be set via CSS and only set the aspect ratio stuff as data attr or javascript vars whatever method you prefer. Or, as you showed before you can go for the full polyfill, but put the helper functions in an external lib, Codepen is setup pretty good for this: https://blog.codepen.io/2013/05/28/new-feature-use-pens-as-external-resources/

@tomhodgins
Copy link
Author

Got the polyfill working a little bit - now to test :)

Preview: http://staticresource.com/aspect-ratio.html

Source: https://gist.github.com/tomhodgins/d7e8a16c93e47613e5625878f73363d5

@tomhodgins
Copy link
Author

FYI I've created a repository and started a spec with the information and behaviour mentioned in this thread: https://github.com/tomhodgins/aspect-ratio-spec

Here's a link to the work in progress: https://tomhodgins.github.io/aspect-ratio-spec/aspect-ratio.html

A syntax example: http://tomhodgins.github.io/aspect-ratio-spec/example/aspect-ratio.css

A JS plugin: http://tomhodgins.github.io/aspect-ratio-spec/plugin/aspect-ratio.js

And a demo page: http://tomhodgins.github.io/aspect-ratio-spec/demo.html

Hopefully this makes the work I've done so far more accessible as we're compiling a spec for this property 👍

@yoavweiss
Copy link

@gregwhitworth - I'm belatedly catching up with this. I have no objections from a preloader perspective and overall this seems ace 💃

@potch
Copy link

potch commented Dec 20, 2016

The one thing I've seen that helps is using calc(16 / 9) to avoid new unit syntax.

@tomhodgins
Copy link
Author

tomhodgins commented Dec 20, 2016

@potch the ratio unit is already specified in CSS in Media Queries level 3 and 4

The <ratio> value type is a positive (not zero or negative) <integer> followed by optional whitespace, followed by a solidus ('/'), followed by optional whitespace, followed by a positive <integer>. <ratio>s can be ordered or compared by transforming them into the number obtained by dividing their first <integer> by their second <integer>.

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

No branches or pull requests

4 participants