CSS @property 实战:手把手带你写一个会动的渐变仪表盘

2026-08-13 0 180

最近写几个小动效,翻来翻去发现不得不提一下 @property,这玩意现在浏览器支持度越来越好了。以前咱们做动画全靠改数字、改颜色,但遇到渐变这种“复合值”就只能干着急。现在有了 @property,可以把自定义属性变成真正可以被浏览器理解的数据类型。

我说个更直白的例子:以前你想把 background 里的角度从 0deg 动画到 360deg,或者把一种颜色过渡到另一种颜色,浏览器根本做不到。因为 var() 替换出来是一堆字符串,它不知道是角度还是颜色。但你要是用 @property 提前把变量声明成 <angle> 或者 <color>,浏览器就知道怎么去插值了。

这篇文章不带废话,直接拿一个圆环进度仪表盘来演示,看看 @property 到底能解决啥问题。

1. 先搞个最基础的圆环

圆环用 conic-gradient 来画,原理很简单:一个圆柱体背景,中间用一层圆盖住,露出外圈。比如这样:

<div class="ring"></div>
.ring {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background: conic-gradient(#6e92fe 0%, #6e92fe 25%, #eee 25%, #eee 100%);
  display: flex;
  align-items: center;
  justify-content: center;
}

.ring::before {
  content: "";
  width: 160px;
  height: 160px;
  border-radius: 50%;
  background: white;
}

这种写法很容易理解:conic-gradient 从12点方向顺时针转,前25%用一个颜色,剩下75%用灰色。一眼看上去就是一个25%进度的圆环。

如果你只是静态显示没问题,但要做成动画就麻烦了。我最初想的是把百分比换成一个变量,然后让变量自动动起来。

.ring {
  --percent: 25%;
  background: conic-gradient(#6e92fe 0%, #6e92fe var(--percent), #eee var(--percent), #eee 100%);
}

.ring:hover {
  --percent: 80%;
}

你用 hover 改变 --percent,会发现那个颜色变化是“啪”一下跳过去的,没有过渡。这是因为 --percent 在浏览器眼里就是一个普通字符串,它不知道 50% 到 80% 之间该怎么过渡。

要是把 --percent 直接放进 transition 呢?

.ring {
  --percent: 25%;
  transition: --percent 0.5s;
  background: conic-gradient(#6e92fe 0%, #6e92fe var(--percent), #eee var(--percent), #eee 100%);
}

不好意思,没用。因为在注册之前,CSS 自定义属性就是不参与过渡的。哪怕你写 transition: all,它照样跳变。

2. @property 怎么解决

@property 就是给自定义属性加个“身份证”。你明确告诉浏览器:这个变量是一个 <percentage>,或者 <color>,或者 <angle>。浏览器知道了类型,自然就会算插值了。

我们要把 --percent 注册成 <percentage>,代码如下:

@property --percent {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 25%;
}

注意 syntax 的写法,要把类型尖括号放在引号里。这里表示这个属性只能填百分比值。如果写 0.25 这种小数,不符合语法,它就会退回初始值。

现在再把这个变量和动画结合起来。

2.1 基于 hover 的过渡

.ring {
  --percent: 25%;
  transition: --percent 0.6s;
  background: conic-gradient(#6e92fe 0%, #6e92fe var(--percent), #eee var(--percent), #eee 100%);
}

.ring:hover {
  --percent: 90%;
}

这样当鼠标悬停时,圆环就会顺滑地转到90%!没有 @property 这根本不可能实现。

2.2 做成循环动画

如果想让它像加载动画一样一直转呢?直接注册一个 --angle 变量,配合 @keyframes 来驱动。

HTML 还是那个圆环,但我们把背景写成可变的:

.ring {
  --angle: 0deg;
  background: conic-gradient(
      from var(--angle),
      #ff6b9d 0%,
      #6e92fe 30%,
      #eee 30%,
      #eee 100%
  );
  animation: rotate-ring 2s linear infinite;
}

@keyframes rotate-ring {
  from { --angle: 0deg; }
  to   { --angle: 360deg; }
}

同样,必须在上面加一条规则,告诉浏览器 --angle 是一个角度:

@property --angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

有了这玩意儿,浏览器才会一帧一帧地计算角度的中间值。如果你不写 @property,整个动画就不会生效,--angle 会直接从 0deg 跳到 360deg。

3. 完善一个渐变仪表盘

下面我们把刚才的技术串起来,做一个有点设计感的仪表盘。这个仪表盘由两个环组成:一个底环,一个动态高亮环。我还特意做了一点渐变,看起来更炫一点。

第一步:基础结构

<div class="gauge">
  <div class="gauge__track"></div>
</div>

第二步:注册变量

@property --p {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

第三步:外环样式

.gauge {
  width: 240px;
  height: 240px;
  border-radius: 50%;
  background: conic-gradient(
    from 180deg,
    #f64f59 0%,
    #c471ed var(--p),
    #e8e8e8 var(--p),
    #e8e8e8 100%
  );
  position: relative;
  transition: --p 0.8s;
}

.gauge__track {
  position: absolute;
  inset: 18px;
  border-radius: 50%;
  background: #1f1f1f;
}

我把 from 180deg 把起点放在左半圆,这样更有仪表盘的感觉。进度从红色渐变到紫色。动态部分用 --p 控制。

第四步:让变量可变

现在加一点交互,比如鼠标点击时进度到 75%。

.gauge {
  cursor: pointer;
}

.gauge:active {
  --p: 75%;
}

就这两行,配合前面的 transition: --p 0.8s,点击的时候就会看到进度环慢慢涨上去,而且颜色也会从 0% 的地方开始平滑过渡。

为了让第一次打开页面也能演示,我加了一个 animation

@keyframes load-gauge {
  from { --p: 0%; }
  to   { --p: 65%; }
}

.gauge {
  animation: load-gauge 2s ease-out forwards;
}

这个动画在页面加载时执行一遍,从一个空环变成65%的状态,非常丝滑。

4. 又一个真实用处:动画颜色

@property 不只能处理角度和百分比,还能处理颜色。比如你注册一个 --main-color 类型是 <color>,然后你就可以直接在 transition 里让颜色有个渐变过渡。以前用 filterbox-shadow 还得绕来绕去,现在直接改变量就行。

给你个简单例子:

@property --color-a {
  syntax: "<color>";
  inherits: false;
  initial-value: #4f79ff;
}

@keyframes color-pulse {
  0%   { --color-a: #4f79ff; }
  100% { --color-a: #ff4f4f; }
}

.btn {
  background: var(--color-a);
  animation: color-pulse 1s infinite alternate;
}

这个按钮的背景色会一直在蓝和红之间来回变化。要是没有 @property,就不能直接对 background 里的 var 值做插值。

5. 注意几个小坑

第一,@property 规则必须放在全局或者父级里吗? 不一定,它和常用的 @keyframes 一样,可以在任意 CSS 里写,但通常放在顶层,方便统一管理。它不属于任何选择器,就是管一个变量定义。

第二,inherits 字段到底啥意思? 其实就是说这个变量是否被子元素继承。如果你写 inherits: true,子元素可以直接用这个变量,并且如果子元素没有重新赋值,就会用父元素的值。如果你写 false,子元素不能继承,除非自己定义。我一般做组件都用 false,因为我只想这个组件内部用它。

第三,syntax 语法必须严格。 比如你要注册一个类型是颜色加透明度,就得写 "<color>",不能写 "<color>" <percentage> 这种,除非你使用组合语法,像 "<color> || <percentage>",但是浏览器支持还不完全。所以我平时就用最基础的类型:<length>, <percentage>, <angle>, <color>, <number>

第四,兼容性怎么看? 目前 Chrome、Edge、Opera 早就支持了,Firefox 也在今年(2024)版本里默认支持了。Safari 从16.4开始支持 @property。所以现在在移动端 WebView 里用也没什么问题。要是实在需要兼容老 Safari,可以这样写:底色的初始值直接写在 background 里,再用 @supports (background: paint(worklet)) 之类的功能检测。当然最好是直接用 @supports (--custom: 1)?其实也可以用 @supports (background: var(--p)) 来判断。

最实用的降级方案:老老实实写一个静态背景作为 fallback,再在支持 @property 的浏览器里覆盖。

.gauge {
  background: conic-gradient(#f64f59 65%, #e8e8e8 0);
}

@supports (--p: 0%) {
  .gauge {
    background: conic-gradient(
      #f64f59 0%,
      #c471ed var(--p),
      #e8e8e8 var(--p),
      #e8e8e8 100%
    );
  }
}

这样高级浏览器看动态,老年浏览器也能看到一张静态的图。

6. 最后说点实际的

我知道很多人看到新特性第一反应就是“又有新东西要学了,真累”。但 @property 这玩意儿,说白了就是让你之前绕了很多路的需求变得更加直接。以前想做圆环动画,要么用 SVG 的 stroke-dasharray,要么用一堆 JS 去改样式,现在用两行 CSS 就能搞定,它不香吗?

再加上现在浏览器迭代速度飞快,大部分用户都已经跑在支持 @property 的版本上了。所以放心地在个人项目、业务系统里用起来吧,至少做个加载动画不用再求 PM 换一个 GIF 了。

真到了不太行的时候,补一个 fallback 也只是几行代码的事。不亏。

对了,文章里这些代码我都跑过,放心抄作业。要是有啥奇怪的兼容性差异,欢迎在评论区一起讨论。

行了,这次就唠到这,下次我再搞点别的 CSS 新特性实战,等着。

CSS @property 实战:手把手带你写一个会动的渐变仪表盘
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请联系本站我们会及时删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 css CSS @property 实战:手把手带你写一个会动的渐变仪表盘 https://www.taomawang.com/web/css/2538.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务