Skip to content

[css-properties-values-api] Add @property. #847

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

Merged
merged 3 commits into from
Jul 22, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 212 additions & 21 deletions css-properties-values-api/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -911,37 +911,228 @@ and affects how the custom property calculates its [=computed value=].
return the result.
</div>

The <dfn>@property</dfn> rule {#at-property-rule}
=================================================

The ''@property'' rule provides an alternative way to register a custom property,
directly in a stylesheet
without having to run any JS.
Valid ''@property'' rules result in a [=register a custom property|registered custom property=],
as if {{registerProperty()}} had been called with equivalent parameters.

The semantics of registered properties are the same
regardless of the mechanism used to perform the registration.
This means that, once registered,
it does not matter whether the registration originated from {{registerProperty()}} or ''@property'':
the property has the same behavior either way.

The syntax of ''@property'' is:

<pre class="prod def" nohighlight>
@property <<custom-property-name>> {
<<declaration-list>>
}
</pre>

''@property'' rules require a 'syntax' and 'inherits' descriptor;
if either are missing,
the entire rule is invalid and must be ignored.
The 'initial-value' descriptor is optional
only if the syntax is the [=universal syntax descriptor=],
otherwise the descriptor is required;
if it's missing, the entire rule is invalid and must be ignored.

If an ''@property'' rule contains any unknown descriptors,
the entire rule is invalid and must be ignored.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tabatkins Ouch, my forwards compat! 😱

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I misread what you'd wrote there!


Issue(845): What happens when we have both an ''@property'' rule, and a
{{registerProperty()}} call for the same property?

Issue(846): What happens when ''@property'' appears inside a shadow tree?


The 'syntax' descriptor {#the-syntax-descriptor}
------------------------------------------------

<pre class='descdef'>
Name: syntax
Value: <<string>>
For: @property
Initial: n/a (see prose)
</pre>

Specifies the syntax of the custom property,
in the form defined by [[#syntax-strings]].
This descriptor is equivalent to the {{PropertyDescriptor/syntax|syntax}} member of {{PropertyDescriptor}}.

The 'syntax' descriptor is required for the ''@property'' rule to be valid;
if it's missing, the ''@property'' rule is invalid.

If the provided string does not successfully [=consume a syntax definition|parse as a syntax definition=],
the descriptor is invalid and must be ignored.


The 'inherits' descriptor {#inherits-descriptor}
------------------------------------------------

<pre class='descdef'>
Name: inherits
Value: true | false
For: @property
Initial: n/a (see prose)
</pre>

Specifies whether or not the custom property inherits.
This is equivalent to the {{PropertyDescriptor/inherits}} member of {{PropertyDescriptor}}.

The inherits descriptor is required for the ''@property'' rule to be valid;
if it's missing, the ''@property'' rule is invalid.


The 'initial-value' descriptor {#initial-value-descriptor}
----------------------------------------------------------

<pre class='descdef'>
Name: initial-value
Value: <<declaration-value>>
For: @property
Initial: the [=guaranteed-invalid value=] (but see prose)
</pre>

Specifies the [=initial value=] of the custom property.
This is equivalent to the {{PropertyDescriptor/initialValue}} member of {{PropertyDescriptor}}.

If the value of the 'syntax' descriptor is the [=universal syntax descriptor=],
then the 'initial-value' descriptor is optional.
If omitted, the initial value of the property is the [=guaranteed-invalid value=].

Otherwise,
if the value of the 'syntax' descriptor is not the [=universal syntax descriptor=],
the following conditions must be met for the the ''@property'' rule to be valid:

* The 'initial-value' descriptor must be present.
* The 'initial-value' descriptor's value must [=consume a syntax definition|parse successfully=]
according to the grammar specified by the [=syntax definition=].
* The 'initial-value' must be [=computationally independent=].

If the above conditions are not met, the ''@property'' rule is invalid.


Extensions to the {{CSSRule}} interface {#extensions-to-css-rule-interface}
------------------------------------------------------------------------------------

The {{CSSRule}} interface is extended as follows:

<pre class='idl'>
partial interface CSSRule {
const unsigned short PROPERTY_RULE = 18;
};
</pre>

The <dfn interface>CSSPropertyRule</dfn> interface {#the-css-property-rule-interface}
-----------------------------------------------------------------------------

The {{CSSPropertyRule}} interface represents an ''@property'' rule.

<pre class='idl' export>
[Exposed=Window]
interface CSSPropertyRule : CSSRule {
readonly attribute CSSOMString name;
readonly attribute CSSOMString syntax;
readonly attribute boolean inherits;
readonly attribute CSSOMString? initialValue;
};
</pre>

<dl dfn-for=CSSPropertyRule dfn-type=attribute>
<dt><dfn>name</dfn>
<dd>
The custom property name associated with the ''@property'' rule.

<dt><dfn>syntax</dfn>
<dd>
The syntax associated with the ''@property'', exactly as specified.

<dt><dfn>inherits</dfn>
<dd>
The inherits descriptor associated withthe ''@property'' rule.

<dt><dfn>initialValue</dfn>
<dd>
The initial value associated with the ''@property'' rule,
which may not be present.
</dl>


Examples {#examples}
====================

Example 1: Using custom properties to add animation behavior {#example-1}
-------------------------------------------------------------------------

<pre class='lang-markup'>
&lt;script>
CSS.registerProperty({
name: "--stop-color",
syntax: "&lt;color>",
inherits: false,
initialValue: "rgba(0,0,0,0)"
});
&lt;/script>

&lt;style>

.button {
--stop-color: red;
background: linear-gradient(var(--stop-color), black);
transition: --stop-color 1s;
}
<xmp class='lang-markup'>
<script>
CSS.registerProperty({
name: "--stop-color",
syntax: "<color>",
inherits: false,
initialValue: "rgba(0,0,0,0)"
});
</script>

.button:hover {
--stop-color: green;
}
<style>
.button {
--stop-color: red;
background: linear-gradient(var(--stop-color), black);
transition: --stop-color 1s;
}

&lt;/style>
.button:hover {
--stop-color: green;
}
</style>
</xmp>

Example 2: Using ''@property'' to register a property {#example-2}
------------------------------------------------------------------
<xmp class='lang-markup'>
<script>
CSS.paintWorklet.addModule('circle.js');
</script>
<style>
@property --radius {
syntax: "<length>";
inherits: false;
initial-value: 0px;
}

div {
width: 100px;
height: 100px;
--radius: 10px;
background: paint(circle);
transition: --radius 1s;
}

div:hover {
--radius: 50px;
}
</style>
<div></div>
</xmp>

<pre class='lang-javascript'>
// circle.js
registerPaint('circle', class {
static get inputProperties() { return ['--radius']; }
paint(ctx, geom, properties) {
let radius = properties.get('--radius').value;
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.arc(geom.width / 2, geom.height / 2, radius, 0, 2 * Math.PI);
ctx.fill();
}
});
</pre>

Security Considerations {#security-considerations}
Expand Down