See #3504
5.3 KiB
clamp()
: Draft 1
(Issue)
This proposal adds support for clamp()
as a CSS function with special parsing
support akin to min()
, max()
, and calc()
.
Table of Contents
Background
This section is non-normative.
CSS Values and Units 4 has introduced the clamp()
function as a way of
representing mathematical expressions that are evaluated by the browser at
render-time. Syntactically, it's closely-related to the existing calc()
function, which Sass has long supported as a special syntactic form that allows
almost any text within its parentheses. This proposal extends that syntax to
cover clamp()
as well.
According to caniuse, browser support for clamp()
first landed in Chrome in
December 2019, and at time of writing is supported in Edge, Firefox, Safari, and
Opera, covering 86.8% of users. Despite its wide availability, its use in Sass
doesn't seem too widespread yet judging by the lack of support requests and only
two 👍s on the issue in the issue tracker.
Summary
This proposal makes clamp()
essentially a synonym of calc()
, so that its
contents are parsed in the same liberal manner with interpolation as the only
valid use of Sass within them.
Design Decisions
This proposal implies that invocations like clamp($foo)
will not evaluate Sass
variables. This does represent a potential backwards-incompatibility for users
who have started using clamp()
with Sass's default function syntax, which
interprets all arguments as SassScript expressions. However, outside of obvious
cases like a single variable being used as an argument, it's difficult to
disambiguate Sass expressions and plain-CSS math expressions, so we'd like to
avoid needing to do so if at all possible.
It's worth noting that there is prior art for this disambiguation. When adding
support for plain-CSS min()
and max()
functions, we decided to
disambiguate the plain CSS versions from the Sass-syntax versions by first
parsing as the former and falling back to the latter if that parse failed. This
proposal intentionally avoids that approach for several reasons:
-
The disambiguation was necessary for
min()
andmax()
because those functions had existed as global Sass functions for many years.clamp()
, on the other hand, has only been usefully usable in CSS for less than a year, and it's not a built-in Sass functions so there's much less reason to pass Sass variables to it directly. In other words, the potential impact of a breaking change is low. -
Even with
min()
andmax()
, we're concerned that the double-parsing will be confusing to users who expect the same outer syntax to imply the same inner parsing. We'd like to avoid extending that confusion any more broadly than necessary. -
Attempting to parse a production one way and falling back on a different parse method is expensive in the parser. That said, Dart Sass's parser is generally not a bottleneck so this is a relatively smaller concern.
Definitions
Special Number String
clamp(
is added to the list of possible prefixes for a special number
string.
Syntax
SpecialFunctionName
The SpecialFunctionName
production will be changed to the following:
SpecialFunctionName¹ ::= VendorPrefix? ('calc(' | 'element(' | 'expression(') | 'clamp('
1: SpecialFunctionName
is matched case-insensitively and may not contain
whitespace.
Note that vendor prefixes are not supported for
clamp()
because no browser has ever shipped support for it guarded by a prefix.
CalcValue
The CalcValue
production will be changed to the following:
CalcValue ::= CalcValue (('+' | '-' | '*' | '/') CalcValue)+ | '(' CalcValue ')' | CalcFunctionName InterpolatedDeclarationValue ')' | CssMinMax | Interpolation | Number CalcFunctionName¹ ::= 'calc(' | 'env(' | 'var(' | 'clamp('
1: CalcFunctionName
is matched case-insensitively.
Deprecation Process
This proposal changes the way clamp()
function calls that are passed
SassScript expressions are parsed, which is backwards-incompatible. Despite
this, it does not call for a deprecation process. Because clamp()
is so young
and the use-cases for SassScript arguments so narrow, the impact of the
backwards-incompatibility is likely to be relatively minor. In addition,
delaying the release of full syntactic support for the duration of a deprecation
period is likely to cause substantial user pain as more users attempt to use
clamp()
going forward.
As such, I propose we treat this change as though it were a potentially-breaking bug fix rather than a full-fledged breaking change.