@property 是一个新特性,支持主流浏览器,它允许开发者显式地定义他们的CSS 自定义属性, 允许进行属性类型检查、设定默认值以及定义该自定义属性是否可以被继承,通过一个简单的案例为大家介绍一下@property规则的用法,详细的介绍文档可以点击链接查看。 developer.mozilla.org/zh-CN/docs/…
前言
上图是UnoCSS文档内一个比较酷的效果,背景采用了线性渐变,文字和背景的渐变呼应,页面中所有的按钮基于渐变的主色调,效果还是比较酷的,大家感兴趣可以去UnoCSS官方文档查看这个效果。 unocss.dev/
这个效果采用的是纯css完成的,结合了animation动画、@keyframes定义关键帧、--css自定义属性、linear-gradient()线性渐变等知识模块。
源码实现起来比较复杂,主要是对@keyframes定义关键帧太过复杂,然后让animation按照这个动画进行轮播,给大家贴一下他的关键帧定义,如果你要是按照他的方法定义,应该会把你给直接劝退。
源码内,关键帧是0%一直定义到100%,每间隔1.25定义一下颜色,如果不配合一些自动化工具或者AI协助,那工作量相当庞大,而且配出来的颜色还不一定好看。
所以我一直尝试,有没有更加渐变的方法实现这个效果,下面是我开发的项目,大家可以微信小程序搜索“鸡汤来喽”小程序,就可以看到我简化后的效果,如图所示:
下面就一步步的给大家介绍,我是如何实现的。
一、自定义属性,AI按需生成关键帧配色
在CSS中通过--标识符定义自定义属性(CSS变量),通过var()函数引用,如下代码示例:
:root {
--main-color: #3498db; /* 定义全局变量 */
}
.element {
--font-size: 16px; /* 定义局部变量(仅作用于该元素及其子元素) */
}
.element {
color: var(--main-color); /* 直接引用 */
font-size: var(--font-size, 14px); /* 设置默认值(当变量未定义时生效) */
}
1.给deepseek AI提示词生成css代码(仅作参考)
@keyframes colorChange {
0% {
--color1: 颜色1;
--color2: 颜色2
}
}
从0% - 100% 间隔10个为一组,要求color1生成明亮的漂亮的16进制颜色,要求color1的颜色范围广一些能够包含赤橙红绿青蓝紫,
color2根据color1生成邻近色,color2和color1在保持邻近色的同时,
color1和color2邻近色颜色差异调到最大,要求0%和100%能拼接起来,要求100%颜色和0%一样。
最终生成了如下代码,如果想要过渡更好看,可以将关键帧设置的再多一些,这里就生成了10组配色,当然生成之后,不能满足你的需求,你可以简单的进行微调。
@keyframes colorChange {
0%, 100% {
--color1: #ff0000; /* 红色 */
--color2: #ff8000; /* 橙色 */
}
10% {
--color1: #ff8000; /* 橙色 */
--color2: #ffff00; /* 黄色 */
}
20% {
--color1: #ffff00; /* 黄色 */
--color2: #80ff00; /* 黄绿色 */
}
30% {
--color1: #80ff00; /* 黄绿色 */
--color2: #00ff00; /* 绿色 */
}
40% {
--color1: #00ff00; /* 绿色 */
--color2: #00ff80; /* 青绿色 */
}
50% {
--color1: #00ff80; /* 青绿色 */
--color2: #00ffff; /* 青色 */
}
60% {
--color1: #00ffff; /* 青色 */
--color2: #0080ff; /* 蓝色 */
}
70% {
--color1: #0080ff; /* 蓝色 */
--color2: #0000ff; /* 深蓝色 */
}
80% {
--color1: #0000ff; /* 深蓝色 */
--color2: #8000ff; /* 紫色 */
}
90% {
--color1: #8000ff; /* 紫色 */
--color2: #ff00ff; /* 紫红色 */
}
}
2.设置animation属性,让动画动起来
:root{
--color1: #ff0000;
--color2: #ffd700;
--background-gradient: linear-gradient(-45deg, var(--color1), var(--color2));
animation: colorChange 8s linear infinite;
}
.element{
width: 300px;
height: 300px;
background: var(--background-gradient);
}
如上代码:
-
给全局:root设置自定义属性--color1和--color2的默认颜色;
-
然后设置自定义属性--background-gradient设置线性渐变linear-gradient,线性渐变倾斜45度,第一个颜色是color1,第二个颜色是color2;
-
设置animation动画,指定关键帧是上面定义的colorChange,花费8秒钟跑完0%-100%的关键帧,匀速的重复循环播放;
-
给要展示的DOM设置背景色,即为刚刚定义的全局属性--background-gradient。
你可以以为这样就实现,可惜效果如下图所示,根本没有颜色融合,而是一帧帧的生硬播放。
这就很奇怪了,如果你使用过animation肯定知道,animation动画是可以对颜色进行融合的,如下图代码演示一下,动画对颜色的融合。
@keyframes boxColorChange{
0%{
background: #ff0000;
}
25%{
background: #8000ff;
}
50%{
background: #00ffff;
}
75%{
background: #00ff00;
}
100%{
background: #0000ff;
}
}
.box{
width: 360px;
height: 360px;
animation: boxColorChange 8s linear infinite;
}
然后将单色改成线性渐变,测试下过,如下代码所示:
@keyframes boxColorChange{
0%{
background: linear-gradient(#0000ff,#0080ff);
}
25%{
background: linear-gradient(#00ff00,#00ff80)
}
50%{
background: linear-gradient(#ff0000,#ff00ff);
}
75%{
background: linear-gradient(#ff8000,#ffd700);
}
100%{
background: linear-gradient(#ffff00,#00ff80);
}
}
.box{
width: 360px;
height: 360px;
animation: boxColorChange 8s linear infinite;
}
给背景设置单独颜色,帧动画是可以对颜色融合的,但是设置成渐变色之后将不会融合,知道问题之后就好办了。 第一种方案: 按照UnoCSS定义关键帧的方法,从0%按照递增1.25%的方式手动设置,这种方案显然是费事费力的,即使使用了AI给自动生成,结果需要分三次才能完整生成这个keyframes关键帧。
第二种方案: 使用实验性技术@property,这个规则比较新,但好在目前主流浏览器都支持这种写法。
3.@property注册自定义属性
@property --property-name {
syntax: "<color>";
inherits: false;
initial-value: #c0ffee;
}
一个有效的 @property 规则代表一项自定义属性的注册,使用自定义属性名作为规则内代码序列的序部。
@property 规则中 syntax 和 inherits 描述符是必需的; 如果其中任何一项缺失,整条规则都将失效并且会被忽略。 initial-value 描述符仅在 syntax 描述符为通用 syntax 定义时是可选的,否则initial-value也是必需的——如果此时该描述符缺失,整条规则都将失效且被忽略。 详情文档:developer.mozilla.org/zh-CN/docs/…
syntax该属性所允许的语法结构
syntax: "<color>"; /* 接收一个颜色值 */
syntax: "<length> | <percentage>"; /* 接收长度或百分比参数,但是二者之间不进行计算合并 */
syntax: "small | medium | large"; /* 接收这些参数值之一作为自定义标识符 */
syntax: "*"; /* 任何有效字符 */
inherits自定义属性注册是否默认继承
true 该属性默认继承。
false 该属性默认不继承。
initial-value为属性设置初始值
initial-value: #c0ffee;
通过上面对@property规则的说明,可以将我们定义的自定义属性--color1和--color2增加@property规则,代码如下:
@property --color1 {
syntax: "<color>";
inherits: true;
initial-value: #ff0000;
}
@property --color2 {
syntax: "<color>";
inherits: true;
initial-value: #ffd700;
}
然后,可以设置当前元素的模糊度,还可以给文本设置同样的渐变要过,如果觉得颜色太亮,可以使用filter: brightness(70%)滤镜,压一下暗色,给p标签制定单一的颜色--color1,最终的效果及完整的源码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="container">
<div class="element"></div>
<img src="https://cdn.qingnian8.com/project/chicken/chicken_color.png" class="logo">
<h1>@property自定义属性规则</h1>
<p>有趣的css专题-咸虾米</p>
</div>
</body>
</html>
<style>
@keyframes colorChange {
0%, 100% {
--color1: #ff0000; /* 红色 */
--color2: #ff8000; /* 橙色 */
}
10% {
--color1: #ff8000; /* 橙色 */
--color2: #ffff00; /* 黄色 */
}
20% {
--color1: #ffff00; /* 黄色 */
--color2: #80ff00; /* 黄绿色 */
}
30% {
--color1: #80ff00; /* 黄绿色 */
--color2: #00ff00; /* 绿色 */
}
40% {
--color1: #00ff00; /* 绿色 */
--color2: #00ff80; /* 青绿色 */
}
50% {
--color1: #00ff80; /* 青绿色 */
--color2: #00ffff; /* 青色 */
}
60% {
--color1: #00ffff; /* 青色 */
--color2: #0080ff; /* 蓝色 */
}
70% {
--color1: #0080ff; /* 蓝色 */
--color2: #0000ff; /* 深蓝色 */
}
80% {
--color1: #0000ff; /* 深蓝色 */
--color2: #8000ff; /* 紫色 */
}
90% {
--color1: #8000ff; /* 紫色 */
--color2: #ff00ff; /* 紫红色 */
}
}
@property --color1 {
syntax: "<color>";
inherits: true;
initial-value: #ff0000;
}
@property --color2 {
syntax: "<color>";
inherits: true;
initial-value: #ffd700;
}
:root{
--color1: #ff0000;
--color2: #ffd700;
--background-gradient: linear-gradient(-45deg, var(--color1), var(--color2));
animation: colorChange 20s linear infinite;
}
.container{
display: flex;
flex-direction: column;
align-items: center;
margin: 60px auto;
width: fit-content;
position: relative;
}
.element{
width: 300px;
height: 300px;
background: var(--background-gradient);
border-radius: 50%;
filter: blur(60px);
}
.logo{
position: absolute;
width: 150px;
top:100px;
}
h1{
margin-top:60px;
background: var(--background-gradient);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
filter: brightness(70%);
}
p{
margin:0;
color:var(--color1);
}
</style>