使用 CSS 函数减少样式重复

Web 功能: @function

维护大型样式表通常会导致逻辑重复,尤其是在处理渐变或响应式布局模式等设计体系令牌时。

借助 CSS @function at 规则,您可以将此逻辑封装到可重用的参数化函数中,从而使 CSS 更易于维护、更一致且更 DRY(不重复)。

@function 语法

自定义函数使用 @function 规则进行定义,后跟一个带短划线的名称和一个参数列表。该函数会使用 result 属性返回值。

@function --my-function(--input1 <length>, --input2: default-value) returns <length> {
  /* Logic goes here */
  result: var(--input1);
}

关键概念

  • 参数:必须以双短划线 (--) 开头。
  • 默认值:您可以使用英文冒号 (:) 提供默认值。
  • 结果:result 属性决定了函数返回的值。函数正文中最后声明的 result 胜出。
  • 作用域:在函数内部定义的形参和变量具有局部作用域。
  • 类型:您可以使用括号表示法(例如 <color>)要求参数和返回值与 CSS 类型匹配,并使用 type 函数(例如 type(<number> | <percentage>))允许使用多种类型。

实际示例

1. 设计体系令牌(渐变)

通过封装渐变逻辑,确保整个应用中的颜色渐变效果保持一致。--angle 提供了一个默认值,以提供可被覆盖的一致性。

@function --fancy-gradient(--start-color <color>, --end-color <color>, --angle: 98deg) returns <image>{
  result: linear-gradient(in oklab var(--angle), var(--start-color), var(--end-color) );
}

.card {
  background: --fancy-gradient(#ed73d7, #5d87e9);
}

2. 条件布局逻辑

您可以直接在函数中使用 @media 或其他查询,以便根据环境返回不同的值。在函数中使用条件逻辑时,请注意,@function 不会在 result 的第一个值处“返回”,而是遵循 CSS 级联,并解析为根据屏幕尺寸、容器尺寸或其他查询匹配的最后一个值。

@function --grid-template(--count <number>){
  /* MANDATORY: Put default value first. */
  result: 1fr; /* Default: stack */
  @media (min-width: 800px) {
    result: repeat(var(--count), 1fr); /* Grid on larger screens */
  }
}

main {
  display: grid;
  grid-template-columns: --grid-template(2);
}

最佳做法

  • 使用带短划线的名称:始终在函数名称和参数名称前加上 --。
  • 提供默认值:通过提供合理的默认值,使函数更加稳健。
  • 力求简单:仅对实际重复或复杂的逻辑使用函数。不要过度设计简单的属性值对。
  • 使用类型:确保参数和返回值符合预期类型。
  • 考虑使用预编译的替代方案:对于不依赖于用户输入、媒体查询或其他客户端变体的函数,请考虑使用 CSS 预编译器,以避免在客户端上执行不必要的工作。

后备策略

在不支持 CSS 函数的浏览器中,使用 CSS 函数设置的值将无效。如需支持其他浏览器,请先为该属性提供后备值。在支持 CSS 函数的浏览器中,此设置将被覆盖。

.card {
  /* Provide fallback, in this case a solid color. */
  background: #5d87e9;
  background: --fancy-gradient(#ed73d7, #5d87e9);
}

main {
  /* Provide fallback, in this case a simple stacked default. */
  grid-template-columns: 1fr;
  grid-template-columns: --grid-template(2);
}

如果需要减少样式重复,同时支持其他浏览器,请考虑使用具有函数的 CSS 预编译器,例如 Sass。