使用CSS变量进行主题化:全局变量和局部变量

我想尝试将设计系统变量归结为两种类型: 全局变量和组件变量。 全局变量将使我们在组件间保持一致性。组件变量将给我们带来粒度和隔离。让我用一个相当简单的组件作为例子来告诉你怎么做。

使用CSS变量进行主题化:全局变量和局部变量
将CSS变量设置为设计系统的主题可能会有些棘手: 如果它们太显眼, 系统就会失去一致性。 如果它们太全局化, 你就会失去粒度。
也许我们可以解决这两个问题。 我想尝试将设计系统变量归结为两种类型: 全局变量和组件变量。 全局变量将使我们在组件间保持一致性。组件变量将给我们带来粒度和隔离。让我用一个相当简单的组件作为例子来告诉你怎么做。

全局变量

全系统变量是为了保持组件间的一致性而定义的一般概念。
作为一个例子,以一个.alert组件开始,假设我们希望保持页边空白和填充的所有空间的一致性。我们可以首先定义全局空间:

:root {
  --spacer-sm: .5rem;
  --spacer-md: 1rem;
  --spacer-lg: 2rem;
}

然后在我们的组件上使用:

/* Defines the btn component */
.btn {
  padding: var(--spacer-sm) var(--spacer-md);
}
/* Defines the alert component */
.alert {
  padding: var(--spacer-sm) var(--spacer-md);
}

这种做法的主要好处是:

  1. 它为分隔符创造了一个单一的真理来源,为作者使用我们的系统定制它提供了一个单一的点。
  2. 它达到了一致性,因为每个组件都遵循相同的间距。
  3. 它为设计者和开发者提供了一个共同的参考点。只要设计人员遵循相同的间距限制,代码的翻译就是无缝的

但这也带来了一些问题:

  1. 系统通过生成依赖树来失去模块性。由于组件依赖于全局变量,因此它们不再是孤立的。
  2. 它不允许作者在不覆盖CSS的情况下自定义单个组件。例如,要更改警报的填充而不产生系统范围的移动,他们必须覆盖警报组件:
.alert {
  padding-left: 1rem;
  padding-right: 1rem;
}

组件范围变量

组件变量被限定在每个模块中。如果我们用这些变量生成警报,我们会得到:

.alert {
  --alert-color: #222;
  color: var(--alert-color);
  border-color: var(--alert-color);
}

主要优点是:

  1. 它创建了一个带有隔离组件的模块系统。
  2. 作者可以在不覆盖组件的情况下精确控制组件,他们只是重新定义变量的值。

没有办法保持组件之间的一致性, 也无法按照这种方法进行全系统的更改。让我们看看我们如何才能获得两全其美!

双层主题系统

该解决方案是一个双层主题系统,其中全局变量始终通知组件变量。这些层中的每一层遵循一组非常具体的规则。

第一层: 全局变量

具有全局变量的主要原因是为了保持一致性,并且遵守这些规则:
它们以“全局变量”这个词为前缀,并遵循公式–global–concept–modifier–state–PropertyCamelCase

  1. concept就像一个spacer或main-title
  2. state类似于hover或expanded
  3. modifier就像sm,或lg
  4. PropertyCamelCase类似于BackgroundColor或FontSize

它们是概念,从不与任何元素或组件绑定

  1. 这是错误的: –global-h1-font-size
  2. 这是正确的: –global–main-title–FontSize

例如,全局变量设置将如下所示:

:root {
  /* --global--concept--size */
  --global--spacer--sm: .5rem;
  --global--spacer--md: 1rem;
  --global--spacer--lg: 2rem;
  /* --global--concept--PropertyCamelCase */
  --global--main-title--FontSize: 2rem;
  --global--secondary-title--FontSize: 1.8rem;
  --global--body--FontSize: 1rem;
  /* --global--state--PropertyCamelCase */
  --global--hover--BackgroundColor: #ccc;
}

第二层:组件变量

第二层的作用域为主题化组件属性并遵循以下规则:
假设我们在写BEM,它们遵循这个公式:–block__element–modifier–state–PropertyCamelCase

  1. block__element–modifier选择器名称类似于alert__actions或alert–primary
  2. state类似于hover或active
  3. 如果您不编写BEM类的名称,那么同样的原则也适用,只需用您的类名替换block__element–modifier
  4. 组件作用域变量的值总是由全局变量定义。
  5. 组件变量总是有一个默认值作为回退,以防组件不依赖全局变量。

例如:

.alert {
  /* Component scoped variables are always defined by global variables */
  --alert--Padding: var(--global--spacer--md);
  --alert--primary--BackgroundColor: var(--global--primary-color);
  --alert__title--FontSize: var(--global--secondary-title--FontSize);
  /* --block--PropertyCamelCase */
  padding: var(--alert--Padding, 1rem); /* Sets the fallback to 1rem. */
}
/* --block--state--PropertyCamelCase */
.alert--primary {
  background-color: var(--alert--primary--BackgroundColor, #ccc);
}
/* --block__element--PropertyCamelCase */
.alert__title {
  font-size: var(--alert__title--FontSize, 1.8rem);
}

您会注意到, 我们正在定义具有全局变量的局部变量。 这是系统工作的关键, 因为它允许作者将系统作为一个整体来主题。 例如, 如果他们想要改变所有组件的主色, 他们只需要重新定义–global–primary-color。
另一方面, 每个组件变量都有一个默认值, 因此组件可以独立存在, 它不依赖于任何东西, 作者可以孤立地使用它。
这种设置允许跨组件的一致性, 它在设计者和开发者之间生成一种共同的语言, 因为我们可以在 Sketch 中设置相同的全局变量作为设计师的缓冲器, 并且它给作者提供了细粒度的控制。

为什么这个系统工作?

在一个理想的世界里, 我们作为一个设计系统的创造者, 期望我们系统的”作者”或者用户在不作任何修改的情况下实现它, 当然, 世界不是理想的, 而且从来没有发生过。
如果我们允许作者在不需要覆盖 CSS 的情况下轻松地将系统主题化, 那么我们不仅可以让他们的生活更简单, 而且还能减少破坏模块的风险。 一天结束的时候, 一个可维护的系统就是一个很好的系统。
两层主题系统生成模块化和孤立的组件, 作者可以在全局和组件层面对它们进行自定义。 例如:

:root {
  /* Changes the secondary title size across the system */
  --global--secondary-title--FontSize: 2rem;
}
.alert {
  /* Changes the padding on the alert only */
  --alert--Padding: 3rem;
}

什么样的价值观应该成为变量?

CSS变量打开代码的窗口。我们允许作者越多,系统对实现问题就越脆弱。
为了保持一致性, 设置除布局值之外的全局变量; 你不希望作者打破布局。 作为一般规则, 我建议允许访问您愿意提供支持的所有组件。
对于下一个版本的 PatternFly, 一个我正在研究的开源设计系统, 我们将允许定制几乎所有与布局无关的东西: 颜色、空间、字体处理、阴影等等。

把所有东西放在一起

为了展示这个概念, 我创建了一个 CodePen 项目:
使用CSS变量进行主题化:全局变量和局部变量
全局变量依赖于_global-variables.scss。它们是保持整个系统一致性的基础, 并将允许作者进行全局变化。
有两个组件: 警报和按钮。 它们是独立的模块化实体, 具有范围变量, 允许作者对组件进行微调。
请记住, 作者将在他们的项目中使用我们的系统作为依赖。 通过让他们通过 CSS 变量来修改系统的外观和感觉, 我们正在创建一个可靠的代码库, 使系统的创建者更容易维护, 并且更好地使用系统来实现、修改和升级到作者。
例如, 如果作者想:

  1. 在整个系统中将原色改为粉红色;
  2. 只需在按钮上将危险颜色更改为橙色;
  3. 在只有在警告状态下,填充左侧更改为2.3rem
:root {
  // Changes the primary color on both the alert and the button
  --global--primary--Color: hotpink;
}
.button {
  // Changes the danger color on the button only without affecting the alert
  --button--danger--BackgroundColor: orange;
  --button--danger--hover--BorderColor: darkgoldenrod;
}
.alert {
  // Changes the padding left on the alert only without affecting the button
  --alert--PaddingLeft: 2.3rem;
}

我知道这只是一种方法, 我相信还有其他方法可以成功地在系统上设置变量。 请在评论中告诉我你的想法,我很想听听你在做什么, 并从中学习。

原创文章,作者:webstack,如若转载,请注明出处:https://www.webstacks.cn/tutorial/1207.html

发表评论

登录后才能评论