我们可以很容易地在 CSS 中创建变量
:root {
--scale: 1;
}
我们可以在任何元素上声明它们
.thing {
transform: scale(var(--scale));
}
对于像这样的示例,一个更好的方法是在用户交互(例如 :hover
)上应用变量
:root {
--scale: 1;
}
.thing {
height: 100px;
transform: scale(var(--scale));
width: 100px;
}
.thing:hover {
--scale: 3;
}
但是,如果我们想在动画中使用该变量… 不行。
:root {
--scale: 1;
}
@keyframes scale {
from { --scale: 0; }
to { --scale: 3; }
}
/* Nope! */
.thing {
animation: scale .25s ease-in;
height: 100px;
width: 100px;
}
这是因为该变量被识别为字符串,而我们需要的是一个可以在两个数字值之间插值的数字。这就是我们可以调用 @property
的地方,它不仅将变量注册为自定义属性,还将它的语法定义为数字
@property --scale {
syntax: "<number>";
initial-value: 1;
inherits: true;
}
现在我们得到了动画!
您需要 查看浏览器支持,因为 @property
仅在 Chrome(从 版本 85 开始)中可用(截至本文撰写之时)。如果您希望使用 @supports
来嗅探它,我们目前不走运,因为它不接受 @ 规则作为值… 还没有。这将在 at-rule()
成为真正的东西 之后发生。
使用
@supports not (inherits: true)
将不起作用,因为 inherits 在任何浏览器中都不是有效的 CSS 属性,因此即使浏览器支持@property
,通知也会显示。inherits 是一个描述符,它仅在
@property
内部有效。为了测试支持,我们需要使用
at-rule()
,但它是一个尚未实现的新功能 (https://www.bram.us/2022/01/20/detect-at-rule-support-with-the-at-rule-function/)嗯!我以为我测试过了,但显然我错了!
太棒了!
使用它而不是直接使用数字有什么好处?如果有人能解释一下,我将不胜感激!
我认为这就是重点:自定义属性可以更新和插值,但我们必须首先将它们定义为数字;否则它们是字符串而不是被视为整数。
--my-var: 7;
执行 JS
getComputedStyle().getProperty('--myvar')
返回" 7"
– 带有前导空格的字符串。你不能用字符串进行计算。您可以独立地对属性值的各个部分进行动画处理,并使用不同的动画持续时间、延迟、时间函数等等。
例如,考虑一个带有旋转然后平移的简单
transform
链 - 这是在圆形上定位项目的常见技术。在半径为
5em
的圆形上均匀旋转一个项目可以通过以下方式实现但假设我们还想独立于旋转改变这个圆的半径。嗯… 在能够对自定义属性进行动画处理之前,我们无法做到这一点,除非添加一个额外的子元素或伪元素。这是因为 CSS 使用 CSS 动画对整个属性值进行动画处理,而不是对它们的各个部分进行动画处理,所以我们必须将
transform
值分解,将旋转应用到我们的项目,将平移应用到子元素或伪元素。自定义属性登场!它们是属性,因此如果我们注册它们,它们的属性值就可以进行动画处理。
我在 这篇文章 中详细介绍了更多示例。
类似地,我们可以对
linear-gradient()
的角度和停止位置进行不同的动画处理请注意,渐变无法 在任何当前浏览器中以任何其他方式进行动画处理(尽管 IE10+ 和 pre-Chromium Edge 可以对它们进行动画处理)。
或
clip-path
值的各个部分或
filter
值的各个部分关于 JS 部分:它们使得通过 JS 修改值的特定部分变得更加容易。例如,假设我们有一个使用
radial-gradient()
创建的跟随光标的聚光灯当光标移动时,我们通过 JS 更新
--x
和--y
值… 而不是编写整个像这样的代码
老实说,CSS 到现在还没有正式转换为脚本语言,这有点荒谬。
我的意思是,它的选择器语法和引擎已经取代了 DOM 方法!所以它已经处理了数组(基于 CSS 类别的节点)。
它显然具有 @ 规则的条件测试,甚至具有伪“else if”和“else”功能,通过将一组规则包装到针对不同设备参数的查询中,然后允许(我猜)一个“also”而不是一个“else”,并且所有其他规则也运行。
变量… 现在获得了严格的类型定义支持?
这比 JS 本身(至少默认情况下)要多,不是吗?这就是 TypeScript 存在的意义。
与此同时,我们有了 SASS,为什么不将 CSS 提升到类似 SASS 的功能,使其留在 W3C 的保护伞下呢?
嗯。
是的,我知道你们都在想什么:将样式、标记和行为清晰分离听起来很有道理。但这真的存在吗?也许比我们想象的要少得多。
我们可以测试和调整代码以支持
@property
,而无需@supports
。这是我用来以不同方式设置样式的方法
首先,注册一个
--houdini
自定义属性,并将它的初始值设置为1
。然后将一个支持标志作为自定义属性
--s
设置为--houdini
变量,并提供一个0
的回退值。如果不支持注册自定义属性,--s
将具有--houdini
的回退值 (0
)。如果我们支持注册自定义属性,--s
将采用我们为 Houdini 设置的初始值 (1
)。因此,--s
基本上是一个标志,在不支持的情况下为0
,否则为1
。此标志可用于根据我们所处的不同情况设置不同的数值。实时测试.
我们还可以使某些元素仅在
@property
支持的情况下显示我们也可以在其他情况下使用
--s
的否定我在 使用 CSS 变量进行 DRY 切换 文章中详细介绍了这些技术。