写八年 CSS,每次改主题都要靠 JS 判断容器宽度还是媒体查询——今天发现 CSS 自己会了,if() 把条件判断彻底还给了属性值本身

写八年 CSS,每次改主题都要靠 JS 判断容器宽度还是媒体查询——今天发现 CSS 自己会了,if() 把条件判断彻底还给了属性值本身。

Chrome 129 开始,CSS 支持了一个听起来不可能的功能:属性值里写 if…else。

具体是这个语法:

.card {
  border-color: if(
    style(--status: success): #22c55e;
    style(--status: error): #ef4444;
    else: #e5e7eb;
  );
}

style() 是样式查询,括号里写自定义属性和目标值。第一个匹配的分支会生效,所有条件都不满足就走 else。这不是媒体查询,是直接写在属性值里的条件分支。

三种可用条件

style() 查询自定义属性——组件自己知道自己的状态,不需要父级传媒体查询:

.button {
  padding: if(
    style(--size: sm): 6px 12px;
    style(--size: lg): 16px 32px;
    else: 10px 20px;
  );
}

media() 查询媒体条件——不需要 @media 块,直接写在属性里:

.box {
  width: if(media(width > 768px): 50%; else: 100%);
}

supports() 查询特性支持——写渐进增强的天然语法:

.card {
  backdrop-filter: if(
    supports(backdrop-filter: blur(1px)): blur(8px);
    else: grayscale(50%);
  );
}

搭配容器查询才是完全体

style() 的真正威力在容器查询场景才能体现:组件不需要知道视口宽度,只需要知道自己被塞进了多宽的容器:

@container style(--theme: dark) {
  .card {
    background: #1f2937;
    color: #f9fafb;
  }
}

这个写法里,组件声明了它需要 –theme 这个自定义属性,父级只需设置这个属性,组件自己响应。不需要传 class,不需要写媒体查询断点。

实际项目中怎么用

拿一个典型的场景举例:表单输入框的错误状态。以前要这么写:

/* 必须靠 class 或者父级选择器 */
.input-error {
  border-color: #ef4444;
}
.input-success {
  border-color: #22c55e;
}

现在可以这样:

.input {
  border: 2px solid if(
    style(--state: error): #ef4444;
    style(--state: success): #22c55e;
    else: #e5e7eb;
  );
}

组件自己读自己的状态,父级只需要设置 --state 属性值,不需要额外的 class 命名。状态和样式彻底绑定在一起,改一个地方另外一个自动生效。

这个变化的核心价值不在于少写几行 JS,而在于把条件判断从「写在选择器外面」变成了「写在属性值里面」。CSS 终于有了一种可以在声明时就做条件分支的语法,而不是靠层叠优先级来决定最终样式。

浏览器支持情况: Chrome 129+、Edge 129+,Firefox 暂不支持。生产环境使用建议加回退值:

.input {
  border: 2px solid #e5e7eb; /* 回退 */
  border-color: if(
    style(--state: error): #ef4444;
    style(--state: success): #22c55e;
    else: #e5e7eb;
  );
}

不支持的浏览器会忽略 if() 函数但保留回退值,渐进增强没问题。

下一步

找一个现在靠 JS 判断来决定样式值的场景,把判断条件翻译成 style() 查询,写几个 if() 分支,感受一下「组件自己知道自己的状态」是什么体验。

评论区

0 条评论

登录后可评论。

小鹿·界面实验室 270 阅读