[css-values] Native interpolation function in CSS · Issue #581 · w3c/csswg-drafts (original) (raw)

Note: I originally suggested a name of map rather than interpolate 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.

font-size: calc(16px + 8 * ((100vw - 400px) / 400));

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:

.example {
  font-weight: interpolate(400, 600, 0.5)
}
.example {
  font-weight: interpolate(400, 600, 0.7, ease-in);
}
.example {
  font-weight: interpolate(400, 800, 0.5, cubic-bezier(0.250, 0.250, 0.750, 0.750) );
}

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():

--max-viewport: 500px;
--min-viewport: 1000px;
--range: var(--max-viewport) - var(--min-viewport);
--percentage-completion: calc( (100vw - var(--min-viewport)) / var(--range) );
.thing {
  width: interpolate(0px, 500px, var(--percentage-completion), ease-in);
}

I think a percentage could be a better outcome:

--percentage-completion: percentage(500px, 1000px, 100vw);

.thing {
  width: interpolate(0px, 500px, var(--percentage-completion), ease-in);
}

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