@property

Baseline 2024
新推出

自 ⁨2024 年 7 月⁩起,此功能可在最新的设备和浏览器版本上使用。此功能可能无法在较旧的设备或浏览器上使用。

@property CSS @ 规则CSS Houdini API 的一部分。它允许开发者显式地定义 CSS 自定义属性,从而可以进行属性类型检查、设置默认值,以及定义自定义属性是否可以继承值。

@property 规则表示直接在样式表中注册一个自定义属性,而无需运行任何 JavaScript。有效的 @property 规则会产生一个已注册的自定义属性,这类似于使用等效参数调用 registerProperty()

语法

css
@property --rotation {
  syntax: "<angle>";
  inherits: false;
  initial-value: 45deg;
}

自定义属性名是一个 <dashed-ident>,以 -- 开头,后跟一个有效的、用户定义的标识符。它区分大小写。

描述符

syntax

一个描述已注册自定义属性允许的值类型的字符串。可以是一个数据类型名称(如 <color><length><number> 等),可以带有乘数(+#)和组合符(|),或者是一个自定义标识符。更多详情请参阅 syntax 描述符页面。

inherits

一个布尔值,控制由 @property 指定的自定义属性注册是否默认继承。

initial-value

一个为属性设置初始值的值。

描述

@property 规则必须满足以下条件才有效

  • @property 规则必须同时包含 syntaxinherits 描述符。如果缺少任何一个,整个 @property 规则都将无效并被忽略。
  • 如果 syntax 描述符的值是通用语法定义(即 syntax: "*"),则 initial-value 描述符是可选的。如果 initial-value 描述符是必需的但被省略了,则整个 @property 规则都将无效并被忽略。
  • 如果 syntax 描述符的值不是通用语法定义,那么 initial-value 描述符必须是一个计算无关的值。这意味着该值可以被转换为计算值而无需依赖其他值,除了那些独立于 CSS 的“全局”定义。例如,10px 是计算无关的——它在转换为计算值时不会改变。2in 也是有效的,因为 1in 总是等于 96px。然而,3em 是无效的,因为 em 的值依赖于父元素的 font-size
  • 未知的描述符是无效的并且会被忽略,但不会使 @property 规则失效。

正式语法

@property = 
@property <custom-property-name> { <declaration-list> }

示例

使用 @property 注册和使用自定义属性

在这个例子中,我们定义了两个自定义属性,--item-size--item-color,我们将用它们来定义下面三个项目的尺寸(宽度和高度)和背景颜色。

html
<div class="container">
  <div class="item one">Item one</div>
  <div class="item two">Item two</div>
  <div class="item three">Item three</div>
</div>

以下代码使用 CSS @property @ 规则定义一个名为 --item-size 的自定义属性。该属性设置初始值为 40%,并将有效值限制为仅 <percentage> 类型的值。这意味着,当用作项目尺寸的值时,其尺寸将始终相对于其父元素的尺寸。该属性是可继承的。

css
@property --item-size {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 40%;
}

我们使用 JavaScript 而不是 CSS 来定义第二个自定义属性 --item-color。JavaScript 的 registerProperty() 方法等同于 @property @ 规则。该属性被定义为初始值为 aqua,只接受 <color> 类型的值,并且不可继承。

js
window.CSS.registerProperty({
  name: "--item-color",
  syntax: "<color>",
  inherits: false,
  initialValue: "aqua",
});

我们使用这两个自定义属性来设置项目的样式

css
.container {
  display: flex;
  height: 200px;
  border: 1px dashed black;

  /* set custom property values on parent */
  --item-size: 20%;
  --item-color: orange;
}

/* use custom properties to set item size and background color */
.item {
  width: var(--item-size);
  height: var(--item-size);
  background-color: var(--item-color);
}

/* set custom property values on element itself */
.two {
  --item-size: initial;
  --item-color: inherit;
}

.three {
  /* invalid values */
  --item-size: 1000px;
  --item-color: xyz;
}

两个自定义属性 --item-size: 20%--item-color: orange; 设置在父元素 container 上,覆盖了这些自定义属性定义时设置的 40%aqua 默认值。尺寸被设置为可继承;颜色则不是。

对于第一个项目,没有设置这些自定义属性。--item-size 是可继承的,所以使用了其父元素 container 上设置的 20% 值。另一方面,--item-color 属性是不可继承的,所以父元素上设置的 orange 值不会被考虑。而是使用了默认的初始值 aqua

对于第二个项目,为两个自定义属性都设置了 CSS 全局关键字,这些关键字对所有值类型都有效,因此无论 syntax 描述符的值是什么都是有效的。--item-size 被设置为 initial,并使用在 @property 声明中设置的 initial-value: 40%;initial 值意味着使用该属性的 initialValue 值。--item-color 被设置为 inherit,明确地从其父元素继承了 orange 值,尽管该自定义属性被设置为不可继承。这就是为什么第二个项目是橙色的。

对于第三个项目,--item-size 的值被设置为 1000px。虽然 1000px 是一个 <length> 值,但 @property 声明要求该值是 <percentage>,因此该声明无效并被忽略,这意味着使用了父元素上设置的可继承的 20% 值。xyz 值也是无效的。由于 registerProperty()--item-color 设置为不可继承,因此使用的是默认的初始值 aqua,而不是父元素的 orange 值。

为自定义属性值添加动画

在这个例子中,我们使用 @property 定义了一个名为 --progress 的自定义属性:它接受 <percentage> 值,并且初始值为 25%。我们使用 --progress 来定义 linear-gradient() 中颜色断点的位置值,指定绿色停止和黑色开始的位置。然后,我们在 2.5 秒内将 --progress 的值动画化到 100%,从而产生进度条动画的效果。

html
<div class="bar"></div>
css
@property --progress {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 25%;
}

.bar {
  display: inline-block;
  --progress: 25%;
  width: 100%;
  height: 5px;
  background: linear-gradient(
    to right,
    #00d230 var(--progress),
    black var(--progress)
  );
  animation: progressAnimation 2.5s ease infinite;
}

@keyframes progressAnimation {
  to {
    --progress: 100%;
  }
}

规范

规范
CSS 属性和值 API Level 1
# at-property-rule

浏览器兼容性

另见