Houdini APIs - CSS Properties and Values API

Houdini API 提供了一组 API 允许在 Javascript 中处理 CSS 值,其中包含 :

  • CSS Properties and Values API
  • CSS Typed OM
  • CSS Painting API
  • Worklets

其中还有些功能处于初级阶段,后续还会有些变更,这里先介绍下 CSS Properties and Values API

CSS Properties and Values API

这个API允许注册自定义的CSS属性,允许检查属性的类型、默认值以及继承属性。

注册自定义属性

CSS.registerProperty

window.CSS.registerProperty({
  name: "--my-prop",
  syntax: "<color>",
  inherits: false,
  initialValue: "#c0ffee",
});

上面的 Javascript 代码注册了一个名为 --my-prop的自定义属性,其使用 CSS 的 color 语法,不可被继承,默认值为 #c0ffee

@property

@property --my-prop {
  syntax: "<color>";
  inherits: false;
  initial-value: #c0ffee;
}

同样在 CSS 中 可以使用 @property 构建相同的名为 –my-prop的自定义属性。

使用注册的自定义属性

如同 CSS variable 一样在 CSS 中使用自定义属性。

.registered {
  --registered: #c0ffee;
  background-image: linear-gradient(to right, #fff, var(--registered));
  transition: --registered 1s ease-in-out;
}

解决问题

目前 CSS variable 已经大量的项目中使用了,可以通过--前缀声明一个自定义的变量,并通过 var()函数使用自定义属性。CSS variable 简单易用,但变量更多的是替换的能力,并不能感知到替换的变量的类型。比如无法再 Animation 和 Transition 中使用变量来控制变化。

动画类型

Web Animation规范中主要定义了四种动画类型:

  • 不可动画化
    • 该属性不可动画
  • 离散的
    • 属性值不可加,插值从起始值交换到结束值。具体来说,用进度值50%表示:
      • 如果p < 0.5,那么V_result = V_start;
      • 如果p ≥ 0.5,那么V_result = V_end。
  • 按计算值
    • 使用该值类型的指定过程来组合计算值的相应各个分量。如果组件的数量或对应组件的类型不匹配,或者任何组件值使用离散动画并且两个对应值不匹配,则属性值组合为离散。
  • 可重复列表
    • 与计算值相同,只是如果两个列表具有不同数量的项目,则首先将它们重复到项目的最小公倍数。然后通过计算值组合每个项目。如果一对值无法组合或任何组件值使用离散动画,则属性值将作为离散组合。

每个 CSS 属性都可以在其定义部分查看到动画类型一栏。该值定义了此 CSS 属性在动画和过渡中的表现。该值的取值便为上面的几种(也有未涵盖到情况,比如 visiability)

而未经注册的自定义属性动画类型便是离散的,这意味着无法达到想要的连续动画效果。

而注册后的自定义属性则可以根据设定的语法类型来改变为按计算值的类型,从而达到连续动画的效果。

以一个可以旋转的渐变背景为例:

CSS variable

代码如下:

<!DOCTYPE html>
<html>

<head>
  <title>css-properties-and-valus-api</title>
  <style>
    body {
      margin: 0px;
    }

    .card::before {
      z-index: 1;
      filter: blur(20px);
    }

    .card::after {
      position: absolute;
      inset: 8px;
      background-color: #191c29;
      border-radius: inherit;
    }

    .card {
      --direc: 0deg;
      position: relative;
      width: 200px;
      height: 300px;
      margin: 100px auto;
      border-radius: 20px;
      color: red;
      font-size: 2rem;
      background-image: linear-gradient(var(--direc), #5ddcff, #3c67e3 43%, #4e00c2);
      animation: rotate 3s linear infinite;
    }

    @keyframes rotate {
      to {
        --direc: 360deg;
      }
    }
  </style>
</head>

<body>
  <div class="card"></div>
</body>

</html>

可以看到渐变背景是没有变化的,这是因为初始值和结束值是一样的表现,将结束值改为 –direc: 360deg; 即:

@keyframes rotate {
  to {
    --direc: 180deg;
  }
}

可以看到如下效果,渐变背景色在 0° 和 180° 两个离散值间跳动。

视频1 离散跳动

注册自定义属性

代码如下:

<!DOCTYPE html>
<html>

<head>
  <title>css-properties-and-valus-api</title>
  <style>
    body {
      margin: 0px;
    }

    .card::before {
      z-index: 1;
      filter: blur(20px);
    }

    .card::after {
      position: absolute;
      inset: 8px;
      background-color: #191c29;
      border-radius: inherit;
    }

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

    .card {
      --direc: 0deg;
      position: relative;
      width: 200px;
      height: 300px;
      margin: 100px auto;
      border-radius: 20px;
      color: red;
      font-size: 2rem;
      background-image: linear-gradient(var(--direc), #5ddcff, #3c67e3 43%, #4e00c2);
      animation: rotate 3s linear infinite;
    }

    @keyframes rotate {
      to {
        --direc: 360deg;
      }
    }
  </style>
</head>

<body>
  <div class="card"></div>
</body>

</html>

可以看到渐变背景现在是连续的从 0° 变换到了 360°:

视频2 连续动画

其中最关键的是将 CSS variable 注册成了自定义的属性:

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

属性的语法是和 CSS angle 相同,CSS angle 是个数值,便可以进行插值了。