重新思考 UI 状态:CSS Range Syntax vs Class Toggling

发布: (2026年2月27日 GMT+8 01:05)
4 分钟阅读
原文: Dev.to

Source: Dev.to

传统模式:JavaScript 控制视觉状态

想象一个日历,用户可以选择开始日期和结束日期。典型的实现方式如下:

days.forEach(day => {
  const value = Number(day.dataset.day);

  if (value >= start && value 12

现在 CSS 使用新兴的 Range Syntax 来进行比较:

.day-now {
  background-color: if(
    style(--day-start <= --day <= --day-end): #8b0000;
    else: rgba(255, 255, 255, 0.05);
  );
}

没有循环,没有类切换,也没有 DOM 变更。JavaScript 更新状态;CSS 负责呈现。

实时演示(CSS Range Syntax)

在此版本中,JavaScript 只更新 --day-start--day-end。CSS 直接评估范围条件。需要 Chrome 142+(实验性支持)。尝试在 JS 面板中更改 startend 的值,观察 UI 的响应。

为什么这在架构上有趣

JavaScript

  • 处理交互
  • 更新状态值

CSS

  • 评估视觉条件
  • 基于状态进行渲染

决定 外观如何 的逻辑位于它应在的地方——CSS。

DOM 重构变得不那么脆弱

在传统做法中,JS 可能依赖如下选择器:

document.querySelectorAll('.calendar .row .day');

重构 DOM 可能会破坏这段逻辑。而在 CSS 驱动的模型中,JS 并不关心结构;它只设置 --day-start--day-end。只要每个日期暴露 --day,样式就能正常工作,从而降低了结构耦合。

浏览器支持 — 以及实用的回退方案

Range Syntax 仍在发展中,尚未在稳定浏览器中得到完整支持。不过,这一架构模式本身并不依赖它。今天我们可以使用 clamp() 和自定义属性的算术运算来模拟类似的逻辑:

.day-now {
  --gte-start: clamp(0, calc(var(--day) - var(--day-start) + 1), 1);
  --lte-end:   clamp(0, calc(var(--day-end) - var(--day) + 1), 1);
  --in-range: calc(var(--gte-start) * var(--lte-end));

  background-image: linear-gradient(
    rgba(139, 0, 0, var(--in-range)),
    rgba(139, 0, 0, var(--in-range))
  );
}

发生了什么

  • 小于零的值会被 clamp 为 0,大于一的值会被 clamp 为 1
  • 乘法模拟了逻辑 AND
  • 结果控制不透明度。

这个回退方案比 Range Syntax 更冗长,但在今天是完全可行的。Range Syntax 主要提升了代码的可读性。

实时演示(Clamp 回退)

相同的架构模式——今天使用 clamp() 实现。JavaScript 仍然只更新状态值。

权衡与约束

该模式并非在所有情况下都更好。需要考虑:

  • 可读性 — 某些团队可能觉得类切换比 CSS 算术更直观。
  • 调试 — 在 CSS 中编写条件逻辑可能对习惯了命令式控制流的开发者来说不太熟悉。
  • 大规模状态 — 如果 UI 状态变得深度相互依赖或复杂,JavaScript 仍可能是更好的协调层。

关键不是“用 CSS 替代 JS”。而是重新定义每一层负责的职责。

更广阔的方向

自定义属性、容器查询、:has()、滚动驱动动画、进阶的 attr() —— CSS 正在不断获得表达能力。Range Syntax 正是这一路径的一部分。它并不会消除 JavaScript,但可以减少我们在视觉状态管理上对它的依赖。这值得我们重新思考。

0 浏览
Back to Blog

相关文章

阅读更多 »