-
Notifications
You must be signed in to change notification settings - Fork 645
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-values] Native interpolation function in CSS #581
Comments
Intriguing idea. The name |
@keithjgrant Yes, that's exactly why I added (Not like Sass maps). This type of function is often called map, although not always. In D3 for example it is called a scale but it's described as a function that "maps" an input domain to an output range. |
Bikeshedding here, but I'm also against calling this |
I feel like this is doing two different things. If we break this down into its component parts, it:
It would seem more generally useful to me if we could split those two concerns apart. For the second part, what if it just took a number from 0 to 1.0 & did the calculation based on that. Then, assuming a syntax something like
...At this point, it's not all that different from a keyframe animation, but the value acts as a way to "scrub" through the animation, or pause it at a specific point. (Is this sort of thing already possible w/ keyframes, in pure CSS, or would it require JS?) The other piece of the puzzle would be constructing that value from the viewport. Something that asks, “where are we between the bounds of 400px and 800px” and returns a result from 0 to 1.0. As you said, this can be done with |
@keithjgrant “where are we between the bounds of 400px and 800px” and returns a result from 0 to 1.0. As you said, this can be done with calc() -- The reason I'm proposing this is it can't universally be done with calc() or in a way that can be applied to anything other than a length value. |
Important point here is that I'm not sure if it makes a difference in this specific situation, but it may be more in line with existing techniques to be trying to solve for specific 'mapping' of width and viewport with a single existing attribute rather than a broader-spectrum low level one like |
@MadeByMike To clarify: I’m not disagreeing with the need/utility this provides. What I mean is it’s tied to one particular use-case: fluid responsive typography. I’m trying to see if there’s a more general use case/solution to tease out that would be beneficial for a broader spectrum of problems. You did mention other things like color, but making a color respond to viewport width seems... not very useful. It would be more flexible, I think, to break the problem apart: generate a multiplier value based on X (e.g. viewport size between a min/max), and apply a multiplier to Y (e.g. font-size between min/max). Then again, I’m having a hard time coming up with other use cases anyway, so maybe the more general solution isn’t needed. |
@keithjgrant Yes, I can't see why you would want to tie color to the viewport width either. Maybe once just for fun :) If there is a good way to specify something other than the viewport width, that would be great. However I'm not sure that can be easily done. Not without another function or feature that resolves the "where are we between the bounds of x and y", and I guess it should do this regardless of whether x and y are: 400px and 800px, red and blue, or 1 and 25. I don't know how this might work or if it is a good idea, but I'm happy to explore it. There would be a correct mathematical term for this but I'm not sure what it is. I'll call it scale and maybe I can update the example later: To use your example:
or the
I'm not sure this is necessarily better than assuming the |
@jpamental Thank you, I updated the example to reflect your comment. |
Thanks @MadeByMike ! They'll likely be somewhat interchangeable, but I only learned recently that the reason I've had to use |
Sounds like you really want easing-function(minvalue, maxvalue, actualvalue [, curve-name]) returning a number between 0 and 1. It's hard for me to see wanting fonts to get bolder based on the device or window size, but font-optical-sizing being a continuous function of the viewport size would make a lot of sense. |
So like this?
And:
That is also a valid option. |
I agree with others - the primitive you want here is a naked The viewport-responding stuff you're talking about is, I presume, the concept referred to as "CSS Locks"? It's pretty cool (especially with Variable Fonts on the horizon), and I agree that it's way more difficult/limited than it needs to be right now. I think the proper solution for this is something we already have plans to do - being able to do unit algebra. That way, you can express the fraction you want in terms of viewport sizes. For example, your first example (interpolate between 18px and 24px as the viewport goes from 400px to 800px wide) could be done as:
That The calc() expression above actually does the full linear interpolation for you, because lengths are calc-able. It's possible more readable to use the
While this isn't quite as direct as your original proposal, it has exactly the same power (particularly if |
@tabatkins I thought that because of how calc works Also using animation-timing functions would be super nice. It opens a world of non-linear options. |
No, right now |
Sorry if this may be trivial; but where in this formula is the 800px limitation? Wouldn't you need a media query surrounding that calc-function to ensure that it doesn't get applied to The way I see it the formula alone won't handle it: Please, enlighten me :) |
@katerlouis In this example the formula is simplified. Expanded it would be: @tabatkins ^^ I like what you are suggesting, what happens with the case of a viewport with of 400px, i.e. :| If so we're getting back to a point where this is probably not simplifying things for authors as much as we might like. |
Your example is dividing 0 with 400, i.e. not a divide by 0 error. It just returns 0. |
Nah, fallback in divide-by-zero doesn't work well; it means we're dealing with an open range, which CSS correctly avoids in designing things. Switching to a fallback means that whatever the behavior was as it got really close to zero, it'll suddenly ignore and switch to your fallback, which isn't guaranteed to do the same thing. Handling divide-by-zero properly means letting calc() handle infinities (via standard float rules), and defining what happens when they escape the calc() (probably just "largest value the implementation can support for that property"). |
I tried to emulate this in Sass: https://www.sassmeister.com/gist/beac01f68da4f9ef3007c0d17f72d8c6 This could also be related to a recent issue to add easing function to colour stops #1332 it has some similar ideas about exposing the easing function in a different context to animation. |
Coming super late to this discussion I know but I really like Tab's variation on the original proposal. I think you can do pretty much anything you need with it, correct?
The form would be |
I just got directed here and thought it might be helpful to share two functions I did in SASS a while ago. (which do translate to plain css calc syntax)
the actual example with the whole code: https://codepen.io/Manuel87/pen/GqzXdV PS: @geelen .. the slider stuff looks interesting! :) |
I think that one is the one that should be duped to this, it's a different topic originally, it's got way less discussion and information, and isn't even filed against css-values. |
@mirisuzanne and I propose the following syntax for this “generic interpolation function” that the CSSWG decided to add but didn't decide on syntax for:
Note: As @tabatkins noted at one point, a generic interpolation function for CSS needs to use semicolons instead of commas, because commas can be part of the value space of various properties. (Since one key use case for the generic interpolation function is used to represent intermediate states in the OM, it has to be able to represent the interpolation of any two values on any two properties. See #2854.) Note: This is part of rethinking various features for animation timelines and interpolation and how to fit them all together. See particularly our proposal for extensions to |
I generally love it. It's short, simple, and supports easing functions. Great. My only objection is semicolons. Introducing semicolons in CSS is going to break a lot of highlighters, naive parsers etc, even scanning of single-line CSS by humans and we should try to avoid it. What about introducing an entirely new character? Or using parentheses around values that may include commas? |
The semicolon has also been proposed in #5055, so if we use something else it would be good to cover other cases too. I think it should also work in |
It might have been worthwhile to use the semicolon in But yeah, there's a very limited set of characters that are suitable for separating values, and we're already using several of them in CSS. Whatever we choose is then locked out from ever being used in CSS as a top-level token in a property value. Semicolon is one of those, and it's already guaranteed to never be used as a top-level CSS value, so it's 100% future-safe. |
To avoid the semicolon, how about at-keywords as in |
That should work from a parsing standpoint, but it feels a lot worse than semicolons, to me. |
CSSWG RESOLVED to accept proposal in #581 (comment) at today's vF2F. |
This is now published in CSS Values and Units Level 4: https://www.w3.org/TR/css-values-4/#mix I've opened two follow-up issues:
Closing this one out, please open a new issue for refining details or anything not covered here! |
Note: I originally suggested a name of
map
rather thaninterpolate
for this function. I thought it might be clearer for some people. I was wrong about this. So I've updated the issue to be clearer and incorporate other comments received.I think CSS is in need of a native interpolation function. Break-points don't necessarily match the intentions of designers and interpolation will become a more significant feature of web design with the introduction of variable fonts, and an increasing adoption of viewport units and more dynamic layouts.
A interpolation function could be the glue that brings it all together.
In many cases it makes good sense to adjust font properties directly in relation to the viewport width. We can currently do this for some properties with calc(). i.e.
The above example will interpolate a font-size between 18px and 24px when the viewport is between 400 and 800px. This has already proven to be very useful but it has limitations. It's linear, not interoperable, it only works with some unit-types, it doesn't work with real numbers or percentages and it's also somewhat difficult to understand.
I'm concerned that many cases axis of variation in variable fonts, won't be able to be transitioned in the same way (because they are unitless values) which for me is one of the main use-cases for variable fonts.
A
interpolate()
function could be used as component value. Similar to calc() it could be used wherever<length>
,<frequency>
,<angle>
,<time>
,<percentage>
,<number>
, or<integer>
values are allowed. But equally it could work for<color>
values and any other values that can be interpolated or animated.One possible syntax of a
interpolate()
function is:interpolate(
<initial-value>
,<target-value>
,<percentage-completion>
, [<timing-function>
])The interpolate() function interpolates between the min-value and the max-value, across the specified viewport-width range and according to the easing function. The default timing function should be linear, and accepts CSS
transition-timing-function
values.Here are some examples of how a interpolate() could be used with
font-weight
:Whilst we could change the percentage completion with media queries, smooth interpolation requires setting a value relative to something else such as the view-port. It was suggested that unit algebra might be a solution for this, but I think the result is at least as complicated and with calc():
I think a
percentage
could be a better outcome:If container queries or new features provide additional unit types percentage function could work with these also.
More detailed thoughts: https://madebymike.com.au/writing/interpolation-without-animation/More
The text was updated successfully, but these errors were encountered: