Back to Sass

Attr Type: Draft 2.0

accepted/attr-type.md

latest6.0 KB
Original Source

Attr Type: Draft 2.0

(Issue, Changelog)

Table of Contents

Background

This section is non-normative.

CSS Values and Units 5 defines the <attr-type> production, which includes two different productions that aren't valid in any other CSS expression context and as such which aren't currently valid SassScript. Specifically:

  • The <syntax> production, which mimics the CSS spec's own syntax for declaring syntactic productions and so involves characters like <, *, #, and +. Fortunately, this is always contained in a type() function call so is unambiguous in practice.

  • The <attr-unit> production, which is mostly just identifiers but also includes % as a value in its own right. This character is already used in SassScript as the modulo operator.

This is further complicated by the fact that the attr() function (in which the <attr-type> production appears) has been supported in browsers for a number of years with a more constrained syntax, so changing it to use a substantially different parsing schema would be a breaking change.

Summary

This proposal defines the type() function as a special function like expression() or element() which is parsed as an unquoted string. Because CSS doesn't use the type() function name elsewhere, we consider this relatively low-risk. However, because it will prevent authors from declaring their own functions named type(), it is a breaking change and will go through a standard three-month CSS compatibility deprecation period.

We will parse % as an unquoted string only in contexts where it's not potentially ambiguous with an operation. This will satisfy CSS compatibility because the only case where CSS currently allows it is in the attr() function, where it must appear before either a comma or a closing parenthesis. We don't anticipate that a single % will be widely used in other contexts, so we don't plan to deprecate the modulo operator, although that path is open in the future if CSS starts using this value more widely.

Definitions

Special Number

Add attr( to the list of unquoted string prefixes that qualify as special numbers.

Syntax

SpecialFunctionExpression

Change the SpecialFunctionName production to be:

<x><pre> SpecialFunctionName¹ ::= VendorPrefix? ('element(' | 'expression(') | VendorPrefix 'calc(' | 'type(' </pre></x>

No browser has yet supported type() with a vendor prefix, nor are they likely to do so in the future given that vendor prefixes are largely unpopular now.

SingleExpression

Add Percent as a production to SingleExpression with the following annotation:

If this is ambiguous with part of ProductExpression, parse ProductExpression preferentially. If this is followed by a Whitespace that contains a LineBreak, do not parse that Whitespace as part of an IndentSame or IndentMore production.

This effectively means that the unquoted string % is allowed everywhere except in a middle element of a space-separated list, since that would be ambiguous with a modulo operation. The whitespace clause ensures that a % at the end of a line in the indented syntax always looks at the next token, for backwards-compatibility with parsing it as an operator and so that whether the statement ends on that line or not doesn't depend on the first token of the next line.

Percent

<x><pre> Percent ::= '%' </pre></x>

Semantics

Percent

To evaluate a Percent, return an unquoted string with the value %.

@function

In the semantics for @function, add a bullet point below the second:

  • If name is case-insensitively equal to type, throw an error.

Unlike other forbidden function names, this doesn't cover vendor prefixes. This is for two reasons: first, we don't expect to add special parsing for type() with vendor prefixes. Second, "type" is a relatively common word, so it's likely for private function names to end with -type in a way that could be indistinguishable from a vendor prefix.

Deprecation Process

The deprecation process will be divided into two phases:

Phase 1

This phase adds no breaking changes. Its purpose is to notify users of the upcoming changes to behavior and give them a chance to move towards passing future-proof units.

Phase 1 does not change the syntax for SpecialFunctionName or the semantics for @function. Instead, if a function is defined with the name type, emit a deprecation warning named type-function.

Phase 2

Phase 2 implements the full changes described above. Per the Dart Sass compatibility policy, it won't be released until at least three months after the first release with the deprecation warning.