CSS @property(CSS 自定义属性)
- 参考
- 描述
- @property
- Houdini
- @property
- 兼容性
- 描述符
- 规则
- syntax
- 扩展
- initial-value
- inherits
- 示例
- 描述符的注意事项
- 使用 JavaScript 来创建自定义属性
- CSS 变量与自定义属性
- 重复赋值
- 过渡
- 简单的背景过渡动画
- 更复杂的背景过渡动画
- 错误示范(一)
- 错误示范(二)
- 正确使用
- CSS 变量
参考
项目 | 描述 |
---|---|
MDN | 官方文档 |
搜索引擎 | Bing |
稀土掘金 | 田八 |
描述
项目 | 描述 |
---|---|
Edge | 109.0.1518.61 (正式版本) (64 位) |
@property
Houdini
Houdini 是一组底层 API,它们公开了 CSS 引擎的各个部分,从而使开发人员能够通过加入浏览器渲染引擎的样式和布局过程来扩展 CSS。
Houdini 是一组 API,它们使开发人员可以直接访问CSS 对象模型 (CSSOM),使开发人员可以编写浏览器可以解析为 CSS 的代码,从而创建新的 CSS 功能,而无需等待它们在浏览器中本地实现。
@property
@property CSS Houdini API 的一部分,它允许开发者显式地定义他们的 CSS 自定义属性, 允许进行属性类型检查、设定默认值以及定义该自定义属性是否可以被继承。
兼容性
@property 是一个正在实验的功能,部分浏览器完全不知持该属性,请注意。
目前,各浏览器对 @property 的支持可见下表。
描述符
规则
一个有效的 @property 规则代表一项自定义属性的注册。@property 的规则大致如下:
@property 自定义变量的名称{
syntax: '语法结构';
initial-value: '初始值';
inherits: '是否允许该属性被继承';
}
注:
自定义变量的名称需要以 -- 开头。
syntax
syntax 在 @property 规则中是必须的,它描述了该属性所允许的语法结构。
可用的语法结构有(仅部分):
项目 | 描述 |
---|---|
<length> | 允许使用任何有效的 长度 。 |
<number> | 允许使用任何有效的 数值 。 |
<color> | 允许使用任何有效的 颜色 。 |
<image> | 允许使用任何有效的 图片 。 |
<url> | 允许使用任何有效的 链接 。 |
<integer> | 允许使用任何有效的 整数值 。 |
<angle> | 允许使用任何有效的 角度值 。 |
<time> | 允许使用任何有效的 时间值 。 |
扩展
你可以通过向提供给 syntax 描述符的值中添加一些符号来使得自定义变量能够接收多个值或同时接受多个语法结构。
项目 | 描述 |
---|---|
# | 使自定义变量能够接受以逗号分隔的多个值。 |
+ | 使自定义变量能够接受以空格分隔的多个值。 |
| | 使自定义变量能够接受多个语法结构。 |
示例:
/* 允许自定义变量接受以逗号分隔的颜色值列表。*/
syntax: '<color#>';
/* 允许自定义变量接受以空格分隔的长度值列表。 */
syntax: '<length+>';
/* 允许自定义变量接受单个颜色值或者以空格分隔的长度值。 */
syntax: '<length | length+>';
initial-value
initial-value 描述符用于指定自定义属性的默认值。
initial-value 依照 syntax 描述符定义,必须可以正确地解析。因此,如果 syntax 描述符为 <color>,那么初始值必须是一个有效的 颜色值 。
inherits
inherits 描述符用于指定该自定义属性是否可以被其他元素所继承,你可以通过布尔值 true 或 false 为该描述符赋值。
示例
下面我们来定义规则以注册一个自定义属性:
@property --color{
syntax: '<color>';
initial-value: #f40;
inherits: false;
}
效果:
该 @property 规则定义了一个名为 –color 的自定义属性,你必须使用 颜色值 为该自定义变量赋值,该自定义变量的默认值为 #f40 ,该自定义变量不可以被其他元素所继承。
描述符的注意事项
- 在 @property 规则中 syntax 和 inherits 描述符是必需的。如果其中任何一项缺失,整条规则都将失效并且会被忽略。
- initial-value 描述符仅在 syntax 描述符为通用 syntax 定义时是可选的,否则 initial-value 也是必需的,如果此时该描述符缺失,整条规则都将失效且被忽略。
- 未知的描述符自身都是无效的,且会被忽略。但是不会造成整条 @property 规则的失效。
- 在需要使用自定义变量的地方,你需要通过 CSS 的内置函数 var() 来对该变量的值进行获取。
使用 JavaScript 来创建自定义属性
你可以通过 JavaScript 来创建 CSS 的自定义属性,两者的使用方法十分相似。
window.CSS.registerProperty({
name: '--color',
syntax: '<color>',
inherits: false,
initialValue: '#f40',
});
CSS 变量与自定义属性
在 CSS 中,与自定义属性最为相似的应该是 CSS 变量了。接下来,我们将探索 CSS 变量与自定义属性的区别以及适合使用自定义属性的部分场景。
重复赋值
使用 CSS 变量时:
- 如果你在 CSS 中的另一个选择器(不指向本元素)创建该变量的同名变量,则该变量并不会覆盖先前的同名变量,这两个变量将同时存在,他们并不相同。选择器在通过多个变量共同的变量名获取对应的值时,将遵循就近原则,使用离本元素距离更近的那个变量。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS 变量与自定义属性</title>
<link rel="stylesheet" href="./index.css">
<style>
*{
/* 去除 HTML 带有的部分默认属性 */
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
body{
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: #131323;
}
/* 父级元素(淘宝红) */
#parent{
--color: #f40;
}
/* 祖父级元素(淡蓝色) */
#grandparent{
--color: aqua;
}
/* 本元素 */
#card{
height: 30vw;
width: calc(30vw / 1.618);
background-color: var(--color);
border-radius: 0.5vw;
transition: all 1s;
}
</style>
</head>
<body>
<div id="grandparent">
<div id="parent">
<div id="card"></div>
</div>
</div>
</body>
</html>
效果:
最终,#card 元素使用了距离更近的父级元素提供的 --color 变量中的值。
- 使用自定义属性时,如果你重复对该属性进行赋值(不论在哪一个选择器中对自定义属性重新进行赋值),改变的将是同一个属性。在自定义属性发生改变后,所有使用该属性的元素将发生相应的变化。
过渡
简单的背景过渡动画
CSS 中支持简单的背景色的过渡动画,就像这样:
- HTML 部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS 变量与自定义属性</title>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<div id="card"></div>
</body>
</html>
- 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: '<color>';
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: '<color>';
initial-value: rgb(229, 91, 91);
inherits: false;
}
@property --color-pink{
syntax: '<color>';
initial-value: rgb(232, 69, 177);
inherits: false;
}
@property --color-purple{
syntax: '<color>';
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: '<color>';
initial-value: aqua;
inherits: false;
}
@property --color-pink{
syntax: '<color>';
initial-value: aqua;
inherits: false;
}
@property --color-purple{
syntax: '<color>';
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。
CSS 变量
由于 transition 仅支持属性的过渡变化,所以 CSS 变量并不能实现该效果。