| 项目 | 描述 |
|---|---|
| MDN | 官方文档 |
| 搜索引擎 | Bing |
| 稀土掘金 | 田八 |
| 项目 | 描述 |
|---|---|
| Edge | 109.0.1518.61 (正式版本) (64 位) |
Houdini 是一组底层 API,它们公开了 CSS 引擎的各个部分,从而使开发人员能够通过加入浏览器渲染引擎的样式和布局过程来扩展 CSS。
Houdini 是一组 API,它们使开发人员可以直接访问CSS 对象模型 (CSSOM),使开发人员可以编写浏览器可以解析为 CSS 的代码,从而创建新的 CSS 功能,而无需等待它们在浏览器中本地实现。
@property CSS Houdini API 的一部分,它允许开发者显式地定义他们的 CSS 自定义属性, 允许进行属性类型检查、设定默认值以及定义该自定义属性是否可以被继承。
@property 是一个正在实验的功能,部分浏览器完全不知持该属性,请注意。
目前,各浏览器对 @property 的支持可见下表。

一个有效的 @property 规则代表一项自定义属性的注册。@property 的规则大致如下:
@property 自定义变量的名称{syntax: '语法结构';initial-value: '初始值';inherits: '是否允许该属性被继承';
}
注:
自定义变量的名称需要以 -- 开头。
syntax 在 @property 规则中是必须的,它描述了该属性所允许的语法结构。
可用的语法结构有(仅部分):
| 项目 | 描述 |
|---|---|
| 允许使用任何有效的 长度 。 | |
| 允许使用任何有效的 数值 。 | |
| 允许使用任何有效的 颜色 。 | |
| 允许使用任何有效的 图片 。 | |
| 允许使用任何有效的 链接 。 | |
| 允许使用任何有效的 整数值 。 | |
| 允许使用任何有效的 角度值 。 | |
| 允许使用任何有效的 时间值 。 |
你可以通过向提供给 syntax 描述符的值中添加一些符号来使得自定义变量能够接收多个值或同时接受多个语法结构。
| 项目 | 描述 |
|---|---|
| # | 使自定义变量能够接受以逗号分隔的多个值。 |
| + | 使自定义变量能够接受以空格分隔的多个值。 |
| | | 使自定义变量能够接受多个语法结构。 |
示例:
/* 允许自定义变量接受以逗号分隔的颜色值列表。*/
syntax: ''; /* 允许自定义变量接受以空格分隔的长度值列表。 */
syntax: '';/* 允许自定义变量接受单个颜色值或者以空格分隔的长度值。 */
syntax: '';
initial-value 描述符用于指定自定义属性的默认值。
initial-value 依照 syntax 描述符定义,必须可以正确地解析。因此,如果 syntax 描述符为
inherits 描述符用于指定该自定义属性是否可以被其他元素所继承,你可以通过布尔值 true 或 false 为该描述符赋值。
下面我们来定义规则以注册一个自定义属性:
@property --color{syntax: '';initial-value: #f40;inherits: false;
}
效果:
该 @property 规则定义了一个名为 –color 的自定义属性,你必须使用 颜色值 为该自定义变量赋值,该自定义变量的默认值为 #f40 ,该自定义变量不可以被其他元素所继承。
你可以通过 JavaScript 来创建 CSS 的自定义属性,两者的使用方法十分相似。
window.CSS.registerProperty({name: '--color',syntax: '',inherits: false,initialValue: '#f40',
});
在 CSS 中,与自定义属性最为相似的应该是 CSS 变量了。接下来,我们将探索 CSS 变量与自定义属性的区别以及适合使用自定义属性的部分场景。
使用 CSS 变量时:
CSS 变量与自定义属性
效果:
最终,#card 元素使用了距离更近的父级元素提供的 --color 变量中的值。

CSS 中支持简单的背景色的过渡动画,就像这样:
CSS 变量与自定义属性
*{/* 去除 HTML 带有的部分默认属性 */margin: 0px;padding: 0px;box-sizing: border-box;
}body{min-height: 100vh;display: flex;justify-content: center;align-items: center;background-color: #131323;
}#card{height: 30vw;width: calc(30vw / 1.618);background-color: aqua;border-radius: 0.5vw;/* 使当前元素的 background 属性具有时长 1s 的过渡效果 */transition: background 1s;
}/* 在鼠标悬浮于当前元素之上时,过渡改变当前元素的背景颜色 */
#card:hover{background-color: pink;
}
效果:

CSS 不支持具有渐变色彩的背景的过渡动画,如果我们将前一个示例(简单的背景过滤动画)中的 CSS 部分中的 #card 及 #card:hover 选择器修改为如下内容:
#card{height: 30vw;width: calc(30vw / 1.618);background: aqua;border-radius: 0.5vw;/* 使当前元素的 background 属性具有时长 1s 的过渡效果 */transition: background 1s;
}/* 在鼠标悬浮于当前元素之上时,过渡改变当前元素的背景颜色 */
#card:hover{/* 设置渐变背景颜色 */background: linear-gradient(45deg, rgb(229, 91, 91), rgb(232, 69, 177), rgb(171, 86, 229));
}
效果:

可以看到并没有产生过渡效果。
此时,我们可以使用 @property 来绕过该限制。
/* 定义自定义属性 --color */
@property --color{syntax: '';initial-value: aqua;inherits: false;
}#card{height: 30vw;width: calc(30vw / 1.618);background: var(--color);border-radius: 0.5vw;/* 使当前元素的 background 属性具有时长 1s 的过渡效果 */transition: --color 1s;
}/* 在鼠标悬浮于当前元素之上时,过渡改变当前元素的背景颜色 */
#card:hover{/* 设置渐变背景颜色 */--color: linear-gradient(45deg, rgb(229, 91, 91), rgb(232, 69, 177), rgb(171, 86, 229));
}
注:
上述代码并不能实现预期效果(鼠标悬浮于 #card 元素之上后,#card 元素的背景颜色无任何改变),该代码仅做示范使用。
分析:
上述代码没有生效的原因在于,我们并没有为 --color 自定义属性提供正确的值,--color 需要的是颜色值,而 linear-gradient(45deg, rgb(229, 91, 91), rgb(232, 69, 177), rgb(171, 86, 229)) 给出的值不一般(猜测),因此没有生效。
既然 --color 无法直接接受 linear-gradient() 函数返回的值,那我们就渗透到 linear-gradient() 函数中来达到相同的效果。
/* 定义自定义属性 */
@property --color-red{syntax: '';initial-value: rgb(229, 91, 91);inherits: false;
}
@property --color-pink{syntax: '';initial-value: rgb(232, 69, 177);inherits: false;
}
@property --color-purple{syntax: '';initial-value: rgb(171, 86, 229);inherits: false;
}#card{height: 30vw;width: calc(30vw / 1.618);background: linear-gradient(45deg, aqua 100%, #fff);border-radius: 0.5vw;/* 使当前元素的 background 属性具有时长 1s 的过渡效果 */transition: background 1s;
}/* 在鼠标悬浮于当前元素之上时,过渡改变当前元素的背景颜色 */
#card:hover{/* 设置渐变背景颜色 */background: linear-gradient(45deg, var(--color-red), var(--color-pink), var(--color-purple));
}
效果:
该示例也没有实现过渡效果,在鼠标悬停在 #card 元素中时,背景颜色将直接发生变化。
分析:
在 #card:hover 选择器以及 transition 属性中我们使用的都是 background,似乎并没有指定需要过渡的属性是自定义属性。在该示例中,自定义属性似乎只起到了传递值的功能。
在仔细分析前面两次失败的经验,我将给出如下的正确方案:
/* 定义自定义属性 */
@property --color-red{syntax: '';initial-value: aqua;inherits: false;
}
@property --color-pink{syntax: '';initial-value: aqua;inherits: false;
}
@property --color-purple{syntax: '';initial-value: aqua;inherits: false;
}#card{height: 30vw;width: calc(30vw / 1.618);/* 使用自定义属性定义背景颜色 */background: linear-gradient(45deg, var(--color-red), var(--color-pink), var(--color-purple));border-radius: 0.5vw;/* 为多个自定义属性定义过渡效果 */transition: --color-red 2s, --color-pink 2s, --color-purple 2s;
}/* 在鼠标悬浮于当前元素之上时,以过渡的方式改变自定义属性的属性值 */
#card:hover{--color-red: rgb(229, 91, 91);--color-pink: rgb(232, 69, 177);--color-purple: rgb(171, 86, 229);
}
效果:
为了便于观察过渡的效果,我在该示例中将过渡时间改为了 2s。

由于 transition 仅支持属性的过渡变化,所以 CSS 变量并不能实现该效果。