CSS Switch-Case 条件

Avatar of Yair Even Or
Yair Even Or

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费额度!

除了 `@media` 查询的特定性质和一些使用 CSS 自定义属性的 高级技巧 之外,CSS 还没有 `switch` 规则或条件 `if`。 让我们看看如果我们有了它为什么有用,并看看一个今天就可以使用的技巧来实现它。

关于可能性的最新讨论

虽然这些东西在今天都不能使用,但在过去的一年中,关于通用条件 CSS 概念的讨论还是不少的。

所以,是的。对条件 CSS 的需求是存在的。

想象一下条件 CSS 为什么有用

也许是在滚动一定距离后进行视觉更改。 数值输入在一定范围内后的视觉更改。 具有少量状态的组件。

有一整类非常流行的用于 UI 的 JavaScript 库(例如 React、Vue 等),它们本质上是用于基于状态构建 UI 的。 显然,这是开发人员的需求。 如果我们可以将基于状态的样式移动到 CSS,那么我们可能需要更少的 JavaScript——并且可能会有更好的关注点分离。

一个共同的主题

我们已经在 CSS 中拥有了自定义属性,我们可以基于它们来构建状态更改逻辑,并将样式块的更改作为自定义属性更改为特定值的副作用。

确实,我们已经有了更改样式块的机制。 我们可以通过 JavaScript 更改 `class`,并且该 `class` 可以应用我们想要的任何 CSS。 但这并不意味着基于状态的 CSS 样式没有用。 我们并不总是能够或可能不想为此编写任何 JavaScript,而是以其他方式更改自定义属性(例如媒体查询、HTML 更改等)。 在 CSS 中执行此操作意味着有助于分离业务逻辑和视觉样式逻辑。

一个技巧!使用 `@keyframes` 进行状态切换

CSS `@keyframes` 可用于 `switch` 特定更改。 通过 `animation` 属性的力量,可以打开一个选择要显示的确切帧的可能性,并使其精确地暂停在该帧上,有效地模拟 switch-case 语句或基于状态的样式。

让我们通过使用 `animation-delay` 属性来看一下它的实际效果。

以下是该 Pen 中发生的情况

  • `animation-delay`:负延迟值 强制特定帧(或帧之间)生效(正值不起作用)。 我们将使用此技巧来强制状态。
  • `animation-play-state: paused`:我们实际上并没有动画任何东西,所以动画将保持暂停状态。
  • `animation-duration`:实际持续时间无关紧要,它只需要一个,以便存在一个时间跨度来保存不同的关键帧。 我们将使其成为一个像 `100.001s` 这样的值,以便如果我们延迟 `100s`,最后一个关键帧仍然有效。 持续时间需要长于延迟值。

第一个范围输入将 `animation-delay` 修改为 `-100s` 和 `0s` 之间的范围。

一个现实世界的用例

在我们直接跳入工作示例之前,值得更详细地讨论一下这个技巧,因为有一些细微差别需要注意。

首先,该技巧仅适用于数值。 因此,颜色值或字符串,因为它严格执行数学运算。

其次,有布尔技巧。 考虑一个变量 `--value: 10`,它可以取 0 到 100 之间的任何数值。 如果值大于 5,我们想要应用颜色。 我们如何知道值是大于还是小于 5? 即使我们知道,这如何帮助我们呢?

--is-above-5: clamp(0, var(--value) - 5, 1)
--value--is-above-5结果
000 – 5 = -5,`clamp()` 强制值为不小于 0
202 – 5 = -3,`clamp()` 强制值为不小于 0
505 – 5 = 0
717 – 5 = 2,`clamp()` 强制值为不大于 1

`clamp()` 就像一个更智能的 `calc()`,因为它允许我们在声明理想值的同时将计算出的值严格限制在范围内。 该范围是实现布尔变量所需的一切。

在 `clamp()` 的第二个参数中编写任何数学运算,这将输出 0(或以下)或 1(或以上)。 确保不要编写任何可能导致 0 到 1 之间数字的数学运算。

以下是它的工作原理

范围输入的唯一作用是通过为 `--value`、`--min` 和 `--max` 定义值来“广播”其值,然后使用 `oninput` 事件修改 `--value`。 这是在 CSS 中获得类似状态行为的最简单方法。 不需要 JavaScript。

使用 CSS 数学函数,可以从相同的变量推断出进度条的“完成”百分比。

--completed: calc((var(--value) - var(--min) ) / (var(--max) - var(--min)) * 100);

现在,我们知道值是否超过某个百分比,这给了我们另一种根据状态进行更改的方法。

--over-30: clamp(0, var(--completed) - 30, 1);
--over-70: clamp(0, var(--completed) - 70, 1);
/* ...and so on... */

好的,很好,但是我们如何使用它来选择特定的关键帧呢? 通过使用 `max()` 函数。

--frame: max( 
    calc(1 - var(--over-30)), 
    var(--over-30) * 2, 
    var(--over-70) * 3, 
    var(--is-100)  * 4 
);

CSS 布尔值的问题在于,有很多方法可以使用它们来实现某个目标,并且必须发挥创造力,找到一个简短易读的公式。

在上面的公式中,如果布尔值为 `1`,则布尔值将“切换”帧号。 由于我们使用的是 `max` 函数,因此最大的切换帧号将是 `--frame` 的计算值。

请注意,颜色更改有一个轻微的过渡。 我们可以在填充区域使用 `background: currentColor;` 来实现这一点,它继承自父元素的颜色,但我选择使用 CSS Houdini 来说明通过声明其 `type` 将过渡分配给 CSS 变量的功能。

以下 Pen 中展示了一个被广泛使用的 **CSS 布尔技巧** 的示例,它是一个纯 CSS 组件,具有许多变量,允许广泛的自定义。

我相信这个小技巧还有很多其他用例,并且很高兴看到社区的创造力还能实现什么。