CSS @property - 实验性
🤷♂️ 这是一个实验性技术,正如你所见,它兼容性目前糟糕。但是 Chrome 是在不断支持它的。
介绍
@property CSS 是 CSS Houdini api 的一部分,它允许开发人员显式定义 CSS 自定义属性,允许属性类型检查,设置默认值,并定义属性是否可以继承值。该规则直接在样式表中表示自定义属性的注册,无需运行任何 JS。有效的规则会生成一个已注册的自定义属性,就好像使用等效的 parameters.@property
调用了 CSS.registerProperty
一样
Houdini 是一组底层 api,它公开了 CSS 引擎的部分内容,使开发人员能够通过钩入浏览器渲染引擎的样式和布局过程来扩展 CSS。Houdini 可以让开发者直接访问 CSS 对象模型(CSSOM) ,使开发者能够编写浏览器可以解析为 CSS 的代码,从而创建新的 CSS 特性,而无需等待这些特性在浏览器中实现。
语法
@property --propery-name {
syntax: '<color>';
inherits: false;
initial-value: #c0ffee;
}
一个有效的规则表示自定义属性注册,属性名称是规则的 prelude.@property
中的序列化。
@property 规则需要语法(syntax)和继承描述符(inheritsdescriptor); 如果缺少其中一个,则整个规则无效,必须忽略。只有在语法是通用语法定义的情况下,初始值描述符才是可选的,否则就需要描述符; 如果缺少初始值描述符,则整个规则无效,必须忽略它。
未知的描述符无效并被忽略,但是不要使 rule.@property 无效。
注意:应该在选择器块外面声明
如果你仍然不是很明白,接下来我们创建一个自定义属性 --my-color:
@property --my-color {
syntax: '<color>';
inherits: false;
initial-value: #c0ffee;
}
syntax
:语法@property --my-color
:声明一个自定义属性 --mycolorinherits
:是否允许继承initial-value
:初始值
如果使用 Javascript 实现,等价于:
window.CSS.registerProperty({
name: '--my-color',
syntax: '<color>',
inherits: false,
initialValue: '#c0ffee',
});
例子
如果你经常使用 css 的 transition 属性,试着回想一下,是不是遇到过这种情况:在给某个属性添加 transition 时,却没有生效。看下面这段 css 代码:
.el {
background: linear-gradient(white, black);
/* this transition won't work */
transition: 1s;
}
.el:hover {
background: linear-gradient(red, black);
}
你可能认为这个渐变中的白色会随着过渡渐变为红色,但事实并非如此,这种过渡是不可能的。如果我们过去需要使用一些小技巧实现它,比如用新的渐变颜色在伪元素中褪色,或者用比元素渐变更宽的背景位置来伪造它。
但是现在我们可以这样做了:
@property --gradient-start {
syntax: "<color>";
initial-value: white;
inherits: false;
}
.el {
--gradient-start: white;
background: linear-gradient(var(--gradient-start), black);
transition: --gradient-start 1s;
}
.el:hover {
--gradient-start: red;
}
因为我们告诉 CSS 这个自定义属性是一个 <color>
,所以它可以被处理或者动画化。之前的颜色值是无法被动画化的。
这里有个有趣的示例:
实现思路很简单,使用 CSS3 border-image 属性设置边框颜色为渐变色,然后使用 animation 改变渐变方向。代码大概这样子:
<div class="wrapper">
<div class="box">
<p>圆锥形渐变</p>
</div>
<div class="box">
<p>径向渐变</p>
</div>
</div>
:root {
--angle: 90deg;
--gradX: 100%;
--gradY: 50%;
--d: 2500ms;
--c1: rgba(168, 239, 255, 1);
--c2: rgba(66, 106, 116, 0.1);
}
.box {
border-image: conic-gradient(from var(--angle), var(--c2), var(--c1) 0.1turn, var(--c1) 0.15turn, var(--c2) 0.25turn) 30;
animation: borderRotate var(--d) linear infinite forwards;
}
.box:nth-child(2) {
border-image: radial-gradient(ellipse at var(--gradX) var(--gradY), var(--c1), var(--c1) 10%, var(--c2) 40%) 30;
animation: borderRadial var(--d) linear infinite forwards;
}
@keyframes borderRotate {
100% {
--angle: 420deg;
}
}
@keyframes borderRadial {
20% {
--gradX: 100%;
--gradY: 50%;
}
40% {
--gradX: 100%;
--gradY: 100%;
}
60% {
--gradX: 50%;
--gradY: 100%;
}
80% {
--gradX: 0%;
--gradY: 50%;
}
100% {
--gradX: 50%;
--gradY: 0%;
}
}
此时,你会发现 border 上的渐变并不会因为设置了 animation 就动起来,这时候 @property 就排上用场了。
我们在 css 中先使用 @property 声明这几个需要变化的属性。
@property --angle {
syntax: '<angle>';
initial-value: 90deg;
inherits: true;
}
@property --gradX {
syntax: '<percentage>';
initial-value: 50%;
inherits: true;
}
@property --gradY {
syntax: '<percentage>';
initial-value: 0%;
inherits: true;
}
此时 border 才真正的“动起来”了。
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
box-sizing: border-box;
}
@property --angle {
syntax: '<angle>';
initial-value: 90deg;
inherits: true;
}
@property --gradX {
syntax: '<percentage>';
initial-value: 50%;
inherits: true;
}
@property --gradY {
syntax: '<percentage>';
initial-value: 0%;
inherits: true;
}
body {
font-family: Raleway, sans-serif;
text-align: center;
margin: 0;
padding: 1rem;
background-color: rgba(10, 12, 18, 1);
color: white;
min-height: 100vh;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
p {
margin: 0;
}
:root {
--angle: 90deg;
--gradX: 100%;
--gradY: 50%;
--d: 2500ms;
--c1: rgba(168, 239, 255, 1);
--c2: rgba(66, 106, 116, 0.1);
}
.wrapper {
min-width: min(40rem, 100%);
}
.box {
font-size: 3vw;
margin: max(1rem, 3vw);
border: 0.35rem solid;
padding: 3vw;
border-image: conic-gradient(from var(--angle), var(--c2), var(--c1) 0.1turn, var(--c1) 0.15turn, var(--c2) 0.25turn) 30;
animation: borderRotate var(--d) linear infinite forwards;
}
.box:nth-child(2) {
border-image: radial-gradient(ellipse at var(--gradX) var(--gradY), var(--c1), var(--c1) 10%, var(--c2) 40%) 30;
animation: borderRadial var(--d) linear infinite forwards;
}
@keyframes borderRotate {
100% {
--angle: 420deg;
}
}
@keyframes borderRadial {
20% {
--gradX: 100%;
--gradY: 50%;
}
40% {
--gradX: 100%;
--gradY: 100%;
}
60% {
--gradX: 50%;
--gradY: 100%;
}
80% {
--gradX: 0%;
--gradY: 50%;
}
100% {
--gradX: 50%;
--gradY: 0%;
}
}
</style>
</head>
<body>
<div class="wrapper">
<div class="box">
<p>圆锥形渐变</p>
</div>
<div class="box">
<p>径向渐变</p>
</div>
</div>
</body>
</html>
参考资料
本文作者:guangzan
本文链接:https://www.cnblogs.com/guangzan/p/14021662.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步