不同程度的自定义属性使用

Avatar of Chris Coyier
Chris Coyier

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

使用 自定义属性 的一种方法是将它们视为设计标记。颜色、间距、字体等等。您可以在页面的根目录设置它们,并在整个 CSS 中使用它们。非常有用,并且是不仅对于自定义属性,而且对于过去一百万年来的预处理器变量的经典用例。

另一种使用自定义属性的方法,除了设计标记方法外,还可以是更进一步地使用它们来设置任何给定元素上的每个主要独特样式选择。

想象一下,您有一个这样的卡片(为了演示,已简化)。

.card {
  background: hsl(200deg 15% 73%);
  border: 4px solid rgb(255 255 255 / 0.5);
  padding: 2rem;
  border-radius: 8px;
}
.card > h2 {
  margin: 0 0 1rem 0;
  border-bottom: 3px solid rgba(0 0 0 / 0.2);
}

很好。

但是,当您不可避免地对卡片进行变体时,您需要自己覆盖这些规则集。CSS 自定义属性方法可能类似于

.card {
  --card-background: hsl(200deg 15% 73%);
  --card-border: 4px solid rgb(255 255 255 / 0.5);
  --card-padding: 2rem;
  --card-border-radius: 8px;
  --card-title-margin: 0 0 1rem 0;
  --card-title-border: 3px solid rgba(0 0 0 / 0.2);

  background: var(--card-background);
  border: var(--card-border);
  padding: var(--card-padding);
  border-radius: var(--card-border-radius);
}
.card > h2 {
  margin: var(--card-title-margin);
  border-bottom: var(--card-title-border);
}

现在可能有点冗长,但是看看当我们想要进行变体时会发生什么

.card-variation {
  --card-background: purple;
  --card-padding-block: 2.5rem;
  --card-title-margin: 0 0 2rem 0;
} 

以下是立即显而易见的三个优势

  • 我只更改了我明确设置为更改的值。我的主要卡片原型保持了我想保留的完整性。
  • 我可以设置变体的子元素的样式,而无需正确地重新编写这些选择器。
  • 现在,我可以从 HTML 中的style属性传递样式覆盖,以进行快速的一次性变体。

更简洁的回退

与其在顶部声明自定义属性,然后在下方使用它们,不如这样同时进行

.card {
  background: var(--card-background, hsl(200deg 15% 73%));
  border: var(--card-border, 4px solid rgb(255 255 255 / 0.5));
  padding: var(--card-padding, 2rem);
  border-radius: var(--card-border-radius, 8px);
}
.card > h2 {
  margin: var(--card-title-margin, 0 0 1rem 0);
  border-bottom: var(--card-title-border, 3px solid rgba(0 0 0 / 0.2));
}

现在,如果--card-background之类的内容恰好被设置,它将覆盖此处的回退值。我不完全喜欢这种方法,因为它意味着位于.card上方的元素可以覆盖它。这可能正是您想要的,但它与一开始在.card级别声明值并不完全相同。这里没有强烈的意见。

进一步分解

这里的例子是,您可能想要单独控制填充。

.card {
  --card-padding-block: 2rem;
  --card-padding-inline: 2rem;
  --card-padding: var(--card-padding-block) var(--card-padding-inline);

  padding: var(--card-padding);
}

现在,如果我想要的话,变体可以控制填充的一部分

.card-variation {
  --card-padding-inline: 3rem;
}

您必须注意最大的问题。也就是说,如果您在根目录中声明所有这些,那么这将不起作用,因为这些嵌套属性已经解析了。但是,只要它首先在.card上声明,您在这里就可以了。

太远了?

假设您想对值的每个部分进行超级终极控制。例如

html {
  --color-1-h: 200deg;
  --color-1-s: 15%;
  --color-1-l: 73%;
  --color-1-hsl: var(--color-1-h) var(--color-1-s) var(--color-1-l);
  --color-1: hsl(var(--color-1-hsl));
}

有点酷,但可能太远了。颜色几乎肯定会是在根目录中声明并保持不变,因此最大的问题将使覆盖低级子属性成为不可能。此外,如果您有一个--color-1,那么您可能还有 2-9(或更多),这很好,因为颜色系统比简单地对颜色部分进行数学运算更精致的设计魔法。

可交付的设计系统?

毫无疑问,Tailwind 非常受欢迎。它使用原子方法,其中大量 HTML 类别分别控制一个属性。我认为它的一些受欢迎程度是由于,如果您从这些预配置的类别中进行选择,那么设计最终会非常不错。您无法偏离轨道。您只能从有限的选择中选择看起来不错的值。

我不会说基于自定义属性的样式化方法与之完全相同。例如,您仍然需要考虑一个类名抽象,而不是直接将样式应用于 HTML 元素。但是,它可能会享受 Tailwind 和其他原子类方法的相同约束/限制。如果您只能从一组预定义的--spacing-x值、--color-x值和--font-x值中选择,那么您可能会获得比以前更连贯的设计。

我个人发现,逐渐走向一个更依赖自定义属性的设计系统感觉很好——如果没有任何其他原因,也要使变体和覆盖更容易管理。

第三方设计系统将它们提供的内容作为… 仅仅是一组可以随意使用的自定义属性,怎么样?

Pollen

第三方可交付成果甚至不需要像这样成为整个厨房水槽。例如,Adam Argyle 的 transition.style 提供一个“Hackpack”,它只是过渡动画辅助程序的自定义属性。

可理解性成本

我听到的一个反对这种全面的自定义属性方法的观点是新人可理解性。如果您是编写该系统的人,那么它可能对您来说很有意义。但这是在 CSS 之上的一个额外抽象。所有的人都共享 CSS 知识,而定制系统知识只由积极参与其中的人共享。

新加入一个 heavily使用自定义属性的系统将会有很大的学习曲线。

视频