CSS @property
@property - CSS: Cascading Style Sheets | MDN
At 规则 - CSS:层叠样式表 | MDN
Custom properties (--*): CSS variables - CSS: Cascading Style Sheets | MDN
CSS Houdini - Developer guides | MDN
📚 什么是@property?
@property
CSS at-rule 是 CSS Houdini API [🔗] 的一部分,它允许开发者显式地定义他们的CSS 自定义属性, 允许进行属性类型检查、设定默认值以及定义该自定义属性是否可以被继承**。
- @property 规则 提供了一个直接在样式表中注册自定义属性的方式,而无需运行任何 JS 代码。
- 有效的 @property 规则会注册一个自定义属性,就像 【CSS.registerProperty🔗】 函数被使用同样的参数调用了一样。
在过去,我们使用CSS自定义变量(CSS Variables)来存储和复用值,但它们并不具备类型检查和默认值设定的功能。
而CSS @property则弥补了这一空白,使得自定义属性更加功能丰富和强大。
💎 语法
css
@property --property-name {
syntax: "<color>";
inherits: false;
initial-value: #c0ffee;
}
--property-name
: 自定义属性名称syntax
: 定义了自定义属性接受的值的类型。- CSS 基本数据类型 - CSS:层叠样式表 | MDN
- 可能是(长度)、(数字)、(百分比)、(长度百分比)、(颜色)、(图像)、(URL地址)、(整数)、(角度)、(时间)、(分辨率)、(变换函数)或(自定义标识符),或者是这些数据类型和关键字值的列表。
+
(空格分隔)和#
字号(逗号分隔)的乘法器表示期望的是一个值的列表,- 例如
<color>#
意味着期望的语法是一个以逗号分隔的<color>值列表
。
- 例如
- 竖线(|)可以为预期的语法创建"或"条件,
- 例如
<length> | auto
接受<length>或auto
,而<color># | <integer>#
期望的是以逗号分隔的<color>值列表
或以逗号分隔的<integer>值列表
。
- 例如
inherits
: 指定该自定义属性是否可以被子元素继承,默认为 false。initial-value
:设置自定义属性的默认值。
@property 规则中 syntax
和 inherits
描述符是必需的;
如果其中任何一项缺失,整条规则都将失效并且会被忽略。
initial-value
描述符仅在 syntax 描述符为通用 syntax 定义时是可选的,否则initial-value也是必需的------如果此时该描述符缺失,整条规则都将失效且被忽略。
未知的描述符自身都是无效的,且会被忽略。但是不会造成整条@property规则的失效。
例子 1:
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>
- 定义两个自定义属性,
--item-size
和--item-color
,用它们来定义三个子元素item
的宽度和高度以及背景颜色。
css
/* --item-size and --item-color */
@property --item-size {
syntax: "<percentage>";
inherits: true;
initial-value: 40%;
}
@property --item-color {
syntax: "<color>";
inherits: false;
initial-value: aqua;
}
- 自定义属性
--item-size
:- 该属性接受的值的类型只是百分比
<percentage>
; - 初始值设置为40%;
- 属性是可继承的,这意味着,当用作项目大小的值时,它的大小将始终相对于其父级的大小。
- 该属性接受的值的类型只是百分比
- 自定义属性
--item-color
:- 该属性接受的值的类型 只是
<color>
类型 - 初始值是 关键字
aqua
- 属性不继承
- 该属性接受的值的类型 只是
css
.container {
display: flex;
height: 200px;
border: 1px dashed black;
/* 使用自定义属性 */
/* 在父元素 设置了自定义属性的值 */
--item-size: 20%;
--item-color: orange;
}
/* 使用自定义属性 设置 item的 宽高 和背景颜色 */
.item {
width: var(--item-size);
height: var(--item-size);
background-color: var(--item-color);
}
/* 设置自定义属性在元素自己身上的值 */
.two {
--item-size: initial;
--item-color: inherit;
}
.three {
/* 无效值 */
--item-size: 1000px;
--item-color: xyz;
}
🍀 分析:
-
两个自定义属性
--item-size: 20%
和--item-color: orange;
设置在父级容器container
上,覆盖了定义时设置的默认值:--item-size:40%
和--item-color:aqua
。其中--item-size
为可继承;--item-color
不可继承。 -
对 class 为
item
的子元素,通过自定义属性设置了 宽高 和背景颜色。- 这个时候,宽高的值是 相对于父容器的宽的
20%
。因为,父容器重新设置--item-size
的值。
- 这个时候,宽高的值是 相对于父容器的宽的
-
对于
one
,没有设置这些自定义属性。--item-size
是可继承的,因此使用其父容器上设置的值20% 。--item-color
是不可继承的,因此不考虑父级上的orange
。而是使用默认的初始值 aqua。
-
对于
two
,对两个自定义属性--item-size
、--item-color
设置了 CSS全局关键字,这两个属性对于所有值类型都是有效值,因此无论语法描述符的值如何都是有效的。--item-size:initial
: 使用该属性的初始值。在 @property 声明中设置的初始值initial-value
为40%
;--item-color:inherit
: 表示从其父元素(也就是container
)继承orange
。即使自定义属性被设置为不被继承,也要显式地从其父级继承orange
。
-
对于
three
,--item-size
和--item-color
都是无效值。--item-size
值为1000px
。虽然1000px
是一个<length>
值,但是@property 声明时要求该值是一个<percentage>
类型。因此该声明无效并被忽略,这意味着使用了父级上可继承的20%
。--item-color
值为xyz
也是无效的。- 首先,值
xyz
不是 CSS 数据类型[<color>🔗](https://developer.mozilla.org/zh-CN/docs/Web/CSS/color_value)
的关键字<color-name>
的有效值。所以会被忽略,所以直接显示的是item
定义的样式。 - 其次,
--item-color
不能被继承,因此使用aqua
的默认值,也不使用父级的值orange
。
- 首先,值
例子 2:使用 CSS @property 实现背景色渐变动画
css
@property --colorA {
syntax: "<color>";
inherits: false;
initial-value: red;
}
@property --colorB {
syntax: "<color>";
inherits: false;
initial-value: yellow;
}
@property --colorC {
syntax: "<color>";
inherits: false;
initial-value: blue;
}
.box {
width: 300px;
height: 300px;
background: linear-gradient(45deg,
var(--colorA),
var(--colorB),
var(--colorC));
animation: animate 3s linear infinite alternate;
}
@keyframes animate {
20% {
--colorA: blue;
--colorB: #F57F17;
--colorC: red;
}
40% {
--colorA: #FF1744;
--colorB: #5E35B1;
--colorC: yellow;
}
60% {
--colorA: #E53935;
--colorB: #1E88E5;
--colorC: #4CAF50;
}
80% {
--colorA: #76FF03;
--colorB: teal;
--colorC: indigo;
}
}
html
<div class="box"></div>
例子3: 使用自定义属性完成图片切换
html
<div class="section">
<div class="box bg mask1"></div>
<div class="box bg mask2"></div>
</div>
css
$img1: 'https://game.gtimg.cn/images/yxzj/img201606/skin/hero-info/191/191-bigskin-6.jpg';
$img2: 'https://game.gtimg.cn/images/yxzj/img201606/skin/hero-info/191/191-bigskin-8.jpg';
$mask1: linear-gradient(45deg, #000 0, #000 var(--per), transparent calc(var(--per) + 10%), transparent);
$mask2: conic-gradient(#000 0, #000 var(--per), transparent calc(var(--per) + 10%), transparent);
@property --per {
syntax: '<percentage>';
inherits: false;
initial-value: -10%;
}
.section {
width: 100%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.section div {
margin: 20px;
}
.section {
.box {
width: 600px;
height: 300px;
}
.bg {
background: url($img1);
background-repeat: no-repeat;
background-position: 50%;
background-size: cover;
position: relative;
&::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: url($img2);
background-size: cover;
background-position: 50%;
animation: animate 2s ease-in-out infinite alternate;
}
}
.mask1 {
&::after {
mask: $mask1;
}
}
.mask2 {
&::after {
mask: $mask2;
}
}
}
@keyframes animate {
0% {
--per: -10%;
}
100% {
--per: 100%;
}
}