-
Notifications
You must be signed in to change notification settings - Fork 711
[css-values] Trigonometric functions #2331
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
Comments
My primary use case is for syncing rotation angles and scale factors or translation distances when I animate multiple elements such that corners/ edges match throughout the animation. In this demo, I need to sync the rotation angle of the bright yellow squares and the post-skew scale factor of the orange squares. This is achieved by doing the trigonometric computations in the JS and then setting the values to the custom properties used in the transform. A way to do it all from the CSS would be immensely useful. I can try to fake it with different timing functions for rotation angles and scale factors or translation distances as I did in this demo, but that's just hardcoding the cubic-bezier() for every case. |
Adding these would require a solution to enter π other than |
Um, why? (Yes, I did read the issue you linked to) |
Some awesome use cases in presentation by @askd: Triangle/* http://askd.rocks/pres/css/#triangle */
.triangle {
position: relative;
width: var(--w);
height: var(--h);
overflow: hidden;
}
.triangle::before {
--a: arctan(calc(var(--w) / var(--h)));
content: '';
position: absolute;
left: 100%;
width: 100%;
height: calc(100% / cos(var(--a)));
background: #000;
transform-origin: 0 0;
transform: rotate(var(--a));
} Parallelogram/* http://askd.rocks/pres/css/#parallelogram1 */
.parallelogram {
--w: 400;
--h: 200;
position: relative;
width: calc(1px * var(--w));
height: calc(1px * var(--h));;
}
.parallelogram::before {
--angle: arcsin(calc(var(--h) / var(--w)));
content: '';
position: absolute;
width: calc(100% - 100% * var(--h) / var(--w) * tan(var(--angle)));
height: 100%;
transform-origin: 0 100%;
transform: skew(calc(0 - var(--angle)));
background: #000;
} Diagonal background animation inside the button/* http://askd.rocks/pres/css/#example1 */
.button {
--h: 4em;
height: var(--h);
padding: 0 calc(var(--h) * tan(32deg));
font-size: 40px;
line-height: var(--h);
overflow: hidden;
text-align: left;
} |
@LeaVerou Because @tabatkins said so in #309 (comment) |
On Sat, 2018-02-17 at 13:45 -0800, Christoph Päper wrote:
@LeaVerou Because @tabatkins said so in https://github.com/w3c/csswg-
drafts/issues/309#issuecomment-330652717
Tab made a compelling case for wanting pi as a constant; others felt a
unit would be better. But even Tab admits it's not strictly
_necessary_. That is, you could add sin, cos, tan, atan, sqrt, pow,
exp, without adding numeric constants. And maybe --pi works for now.
…--
Liam Quin, W3C, http://www.w3.org/People/Quin/
Staff contact for Verifiable Claims WG, SVG WG, XQuery WG
Improving Web Advertising: https://www.w3.org/community/web-adv/
Personal: awesome vintage art: http://www.fromoldbooks.org/
|
I also periodically come across situations in CSS -- and very often in SVG -- where trig functions would be very helpful for converting between angles and x/y dimensions. In static markup, the solution is to hard-code approximate values, but that often leaves pixel gaps or discontinuities from rounding errors. In dynamic situations, as others have mentioned, the only solution is JavaScript (with lots of converting back and forth between radians for the JS functions and degrees or turns for my design and for SVG properties, which is the only time I usually need I would argue for adding the trig functions and then wait and see how much demand there is for pi constant, or a root-2 constant. As Liam notes, an author could always define an arbitrary-precision constant as a custom property. And most importantly, separating out the two features means that we could move ahead with functions without having to first decide the best syntax for constants. |
Which exact functions are proposed here? Several programming languages distinguish two arcus tangens functions: (A generic (square) root |
I use The MVP might be Authors and libraries can use these to define |
Why would anyone ever need to manually specify |
@ewilligers Yeah, that set looks useful as a first pass. More general roots and powers might be useful in the future, but we should wait and see what the uptake is on these; they cover the vast majority of what you want to do in trig. (I'd prefer the As @AmeliaBR suggests, we can leave off constants for now. I think it's probably best to address them thru the |
Moz has defined: sin, sinh, cos, cosh, tan, tanh, atan, atan2, atanh... Cr also. In JS. I think names for CSS can be the same. Easier to remember. |
|
The CSS Working Group just discussed
The full IRC log of that discussion<astearns> topic: trig<astearns> github: https://github.com//issues/2331 <fantasai> leaverou: We should keep it cos()/sin() maybe tan() and only accept angle <chris> atan2 though, surely <fantasai> leaverou: That would solve all the usecase I listed <fantasai> AmeliaBR: So initial proposal is to add simple trig functions in calc() <fantasai> AmeliaBR: Once you start doing graphical layouts involving arcs and stuff, you need trig functions to convert from width/height distances to angular distances <leaverou> s/That would solve all the usecase I listed/That would solve all the use cases listed in the issue/ <fantasai> AmeliaBR: Currently to do this you either have to do it either in a preprocessor, or if in dynamic variables have to do it in JS <fantasai> AmeliaBR: which is a pain <fantasai> AmeliaBR: JS only take radians, SVG only takes degrees, etc. <fantasai> AmeliaBR: Let's just do it in CSS which has everything <fantasai> AmeliaBR: I'd also like to get the arc functions <dbaron> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math might be an interesting source... <fantasai> AmeliaBR: CSS lengths, calculate angles, woudl be great <fantasai> AmeliaBR: You can't get a diagonal across the veiwport e.g. without this <fantasai> TabAtkins: There's a demo of the Taylor expansion of sin() using stacked variable :) <tantek> +1 dbaron get your trig funcs from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math <fantasai> leaverou: There's lots of examples of usage <fantasai> AmeliaBR: I asked anatudor about it the other day <leaverou> s/There's lots of examples of usage/We can look at preprocessors for usage stats, they've been supporting trig functions for years/ <fantasai> AmeliaBR: <quotes anatudor> <fantasai> TabAtkins: Very useful for transforms <fantasai> myles__: People are doing this already to day, and implementation burden is close to trivial <fantasai> myles__: If doing arc, maybe also want atan, but probably just those <fantasai> chris: atan2 deals with that <fantasai> TabAtkins: ... <fantasai> dbaron: Only add functions that are on the JS math object? Not all of them, but a subset. <fantasai> fantasai_: atan2? <fantasai> AmeliaBR: [explains the theory of atan] <TabAtkins> s/.../someone asked for hypot(), rather than having to do calc(sqrt(var(--x) * var(--x) + var(--y) * var(--y))/ <fantasai> dbaron: If you have x and y coords on a graph, you typically want the tangent of y over x <fantasai> dbaron: if you have x=1 y=1 you're in Q1, i fyou're x=-1 x=-1 your'e in Q3 <fantasai> dbaron: atan(x/y) gives you Q1 always. atan2() let's you get 270deg <dbaron> s/x\/y/y\/x/ <fantasai> myles__: so we gonna resolve on a list of functions? <fantasai> TabAtkins: resolve on a small list, and then maybe do more research to see if anything else needed <fantasai> TabAtkins: but can resolve on basic trigs right now <myles__> Sin() cos() tan() acos() asin() atan() atan2() <fantasai> emilio: angles calc... <fantasai> emilio: Don't want sin(calc(10px + 20%)) <AmeliaBR> and probably hypot(), sqrt(), and pow() <fantasai> emilio: what is the type of these functions? <fantasai> TabAtkins: I think the output is always numbers <fantasai> TabAtkins: radians are numbers <fantasai> fantasai_: not in CSS <fantasai> TabAtkins: Right. Inverse ones do need to return <angle> <cbiesinger> q+ <fantasai> TabAtkins: others return <number> <dbaron> sin() cos() tan() take an <angle> or a <number> (radians) and return a number <dbaron> asin() acos() atan() atan2() take a <number> (or 2, for atan2) and return an angle <fantasai_> chris: Surely you can do atan2(20px, 4em) lengths in general <fantasai_> ?: Yes, of course <fantasai_> leaverou: ... <xfq> ack cbiesinger <fantasai_> cbiesinger: You suggested that radians can be an input, but without a pi constant how do you type that in a CSS style sheet? <dholbert> s/.../in theory we can divide lengths and get numbers in CSS, but no browser supports that yet/ <fantasai_> TabAtkins: Use the turn unit. 0.5turn = pi <fantasai_> AmeliaBR: We don't radians much in CSS because we have better units <leaverou> s/leaverou: .../leaverou: (to Chris) yes, CSS in theory supports dividing lengths and it gives you a number. In practice, no UA supports this yet/ <fantasai_> AmeliaBR: But if you're calcuating it somewhere else, we can bring it in <dbaron> so atan2(<number>, <number>) or atan2(<length>, <length>) ? <fantasai_> TabAtkins: This is why I want to accept numbers (meaning radians) in addition to <angle> <fantasai_> myles__: So atan2() will accept lenghts and numbers? <fantasai_> TabAtkins: Yes <fantasai_> myles__: atan2(10px, 5) ? <fantasai_> TabAtkins: No, type has to match <fantasai_> dbaron: [repeats what's above] <fantasai_> dbaron: sin() cos() tan() take an <angle> or a <number> (radians) and return a number <leaverou> atan2(calc(45deg * 1px), 1em)? <fantasai_> dbaron: asin() acos() atan() atan2() take a <number> (or 2, for atan2) and return an <fantasai_> angle <fantasai_> AmeliaBR: ... <fantasai_> TabAtkins: Unit division calc() should be implemented. <dbaron> s/.../We need people to implement unit division in calc() so that people can use that as an argument to asin() and acos()/ <fantasai_> astearns: OK, I think we can resolve to add these things <fantasai_> astearns: Objections to dbaron's proposal? <fantasai_> TabAtkins: I think the 10 from dbaron and emilio are good <emilio> s/emilio/AmeliaBR <fantasai_> TabAtkins: hypot() sqrt() and ? <florian> s/?/powe/ <florian> s/?/pow/ <xfq> sin() cos() tan() acos() asin() atan() atan2() hypot() sqrt() pow() <fantasai_> TabAtkins: They would not adjust the unit, just multiply the magnitude <fantasai_> fremy: Can you use these directly, or has to be inside calc() <fantasai_> TabAtkins: Both <fantasai_> [discussion of edits] <fantasai_> fantasai: pow() is exponents, right? we don't want to use the ^ notation? <fantasai_> TabAtkins: JS uses **, others use ^, but everyone's function is called pow() <fantasai_> AmeliaBR: If you multiply two lengths together you still get a single-dimension length? <fantasai_> TabAtkins: Multiplying two lengths would give you squared unit, but pow() and sqrt() wouldn't <fantasai_> AmeliaBR points out inconsitency of this <tantek> +1 pow() http://php.net/manual/en/function.pow.php <fantasai_> TabAtkins: So maybe pow() and sqrt() should only take numbers <fantasai_> ... <fantasai_> myles__: If you pow(3.5, 4.7) what's the dimension in CSS? <tantek> do we need a unit(number, unit-name) function? <fantasai_> TabAtkins: Maybe go back to pow() and sqrt() only accept numbers. <fantasai_> AmeliaBR: and hypot() makes it easier to deal with the most common case <fantasai_> TabAtkins: Good argument to keep hypot() <fantasai_> AmeliaBR: So I could draft this up? <fantasai_> fantasai: Would be edits to css-values-4 <fantasai_> AmeliaBR: Matter of 1-2 days of writing things up now that we've hashed this out <fantasai_> RESOLVED: Add sin() cos() tan() acos() asin() atan() atan2() hypot() sqrt() pow() |
Canʼt I would hate to see |
atan2() is attested by that name in tons of languages; we think it's more valuable to match that usage than try to be clever in saving function names. sqrt() is just a convenience function; it's easier and more understandable than typing An important concern in our naming was to match JS's |
Is
Do we use |
Consistency is a reasonable argument I think ^_^. But also it means we get to avoid all the confusing evaluation rules; what's
|
On Wed, 2019-02-27 at 17:34 -0800, Tab Atkins Jr. wrote:
`pow(X, 2)`, on the other hand, is 100% unambiguous all the time.
It’s also easier to search for than ** for people trying to understand
a style sheet. I think that’s valuable when the feature is likely to be
used, es, but not so often that it’ll be familiar to everyone.
Liam
…--
Liam Quin, https://www.delightfulcomputing.com/
Available for XML/Document/Information Architecture/XSLT/
XSL/XQuery/Web/Text Processing/A11Y training, work & consulting.
Web slave for vintage clipart http://www.fromoldbooks.org/
|
Iʼm all for author convenience, e.g. I still want an angular It would probably be convenient to also have functions for cotangent, secant and cosecant, even if Javascript does not provide these reciprocal functions. A reciprocal function, 1/x, for just the value, i.e. without changing the unit, might be beneficial as well, but no actual use case comes to mind. |
Will commas ( More recently, I’ve seen slashes ( With a slash: width: pow(2% / 4);
/* becomes */
width: 16%; With a comma: width: pow(2%, 4);
/* becomes */
width: 16%; Neither feel especially wrong to me, but it looks a little funny when I add some inner calc. With a slash: width: pow(calc(2% / 4) / 4);
/* becomes */
width: 0.0625%; With a comma: width: pow(calc(2% / 4), 4);
/* becomes */
width: 0.0625%; |
How about spaces? width: pow(2% 4); |
By requiring commas, we allow the arguments to be Users can write |
Thanks for all the input everyone! (You're making my eventual job much easier.) A couple quick responses: @Crissov The consensus in the room was to match JavaScript's Regarding cotangent and so on: we're not saying they'll never be added, but they aren't the priority. JS has survived without them, so we think devs can work with what they're given. Again, until we start getting complaints about numerical imprecision causing real-world problems! @jonathantneal @valtlai The way I interpret the slash delimiter is that it is added for clarity if simple space separation is ambiguous because of optional values, and commas indicate lists of repeated compound values. But, we have lots of existing functions that use commas for The only functions (of those we're discussing at this point) that take multiple parameters are atan2, pow, and hypot. atan2 is interesting since it is conceptually a ratio/division, but we want the function to be able to keep track of whether the numerator or denominator or both are negative. But it would probably be weird to have a slash mean "conceptual division and separator" in this one function when it is simple division in the others. And we're never going to extend it to a list, so there's no ambiguity in using a comma. pow could be space-separated, but again there's no harm in making it a comma separator. hypot is more a list of values, especially if we allow it to work on more than 2 (I'd like to at least support 3 values, for 3D transform constructs). So comma works there quite naturally. @ewilligers I definitely like the idea of skipping the nested |
@jonathantneal this from #2331 (comment):
width: pow(2%, 4);
/* becomes */
width: 16%; disturbs me from a mathematical point of view. Isn't Is there a consensus that for |
To avoid this kind of ambiguities like
Then authors can choose Note this is not just about percentages, e.g. if |
Not only you! I brought this up at the end of the face-to-face discusssion, but maybe it didn't get clearly reflected in the minutes. All mathematical operations will need to apply to dimensions in a proper way, following the CSS Typed OM rules (which treat Powers and roots will need to cancel out to get regular CSS values. This is why numeric precision may become an issue. It is slightly annoying if powers and roots don't neatly cancel out on the value. But it is a big problem if they don't neatly cancel out on the unit! One suggestion at the end of the call was to limit |
Ah, sorry, I was just commenting on what I saw on this issue and haven't caught up with the minutes yet. Glad I'm not alone here! |
|
Another use case for trig functions ( https://www.smashingmagazine.com/2017/05/fluid-responsive-typography-css-poly-fluid-sizing/ |
Finally we will be able to have responsive Skewing using Example: https://stackoverflow.com/a/53446820/8620333 And some other responsive shapes that relies on https://stackoverflow.com/a/55149965/8620333 |
For future reference, https://test262.report/browse/built-ins/Math is the JS testsuite for Math, for when I'm writing the CSS tests. |
It's great news to hear that trigonometric functions are being considered for CSS. Bit of a shameless plug here but I use square root when calculating the typographic scale across different devices meaning sometimes the scale needs to change. This is easier to do by just changing one CSS variable and letting CSS calculate the sizes dynamically responsively. Having I created a workaround for now using PostCSS. Also created |
FYI @limitlessloop, but the trig functions and sqrt(), among others, aren't just being considered, they were already accepted and are in the spec. ^_^ |
@tabatkins even better, thanks for making me aware! |
I keep stumbling on use cases that need trigonometric functions to be solved, and I always have to resort to JS or a preprocessor for them, which is a pain. Basically almost any time you need to match two things and angles are involved.
Sadly I couldn't find most of my use cases, but here are two:
Also the following use sqrt (precomputed), but would need trigonometry in the general case :
(credits: @MeFoDy for collecting these from my book)
What do you think? Can we make it happen?
The text was updated successfully, but these errors were encountered: