浅析 Bootstrap 的 CSS 类名设计

100人浏览   2024-09-08 10:47:48

When building a CSS design system like Bootstrap, it's important to keep things simple, durable, and flexible. This is no easy task, especially on larger teams and projects where the number of components can become quite high. To help improve this situation in a CSS design system, you might consider using prefixed classes instead of chained classes.

在构建类似 Bootstrap 这样的 CSS 系统时,保持系统的简单性、稳定性、灵活性是相当重要的。这并非易事,尤其对于大型团队和项目来说,组件的数量可能会变得相当庞大。为了改善这种状况,你不妨考虑用前缀式类名取代链式类名。

Taking the chained classes approach, your CSS selectors might look something like this for a given set of components:

在使用 链式类名 方案时,你可能会把一系列特定组件的 CSS 选择符写成这样:

.success { ... }
.btn.success { .. }
.alert.success { ... }

We have here a global base class, .success, that might house all the commonalities between successful buttons and alerts. Then, at the individual component level, we add on or override as necessary. However, this wide open class and chained approach exposes developers to a number of questions and potential paint points:

我们在这里设置了一个全局基础类 .success,它可能涵盖了成功按钮和成功提示框之间的所有共性。然后,在单个组件层面,我们又需要对它进行扩充或覆盖。但是,这种完全开放式的类名和链式风格令开发者面临一些困扰和潜在痛点:

  • What's that base class stand for
  • What elements will be affected at the root level
  • How many elements have .success chained onto them
  • Can it be extended further to more components
  • What if one instance of .success uses green text on a white background while another uses white text on a green background
  • 这个基础类到底代表什么
  • 哪些元素会在根层级受到影响(译注:啥意思?)
  • 哪些元素可以把 .success 类链到自己身上
  • 它是否可以被进一步扩展到更多的组件上
  • 假如一个 .success 的实例要用白底绿字,而另一个要用绿底白字,怎么办?

And those questions barely scratch the surface. This solution isn't necessarily bad, but when scale, brevity, and flexibility are your top requirements, it might not be the best idea. A better solution might be using prefixed classes.

而且这些问题还只是冰山一角。这种方案未必很差,但如果可扩展性、简单性和灵活性是你的最高需求,这可能就不是最好的办法。此时,前缀式类名方案可能更加适合你。

Prefixed classes guide developers towards a simpler and more maintainable direction for building an extensive CSS design system. Here's what we have if we take away the generic base class and scope things per component with prefixes:

前缀式类名 将开发者引入一种更简单、更易维护的方向,从而构建一个可扩展的 CSS 系统。当我们抛弃常规的基础类的方式,并将每个组件的样式用前缀限制起来时,我们的代码会变成这样:

.btn-success { ... }
.alert-success { ... }

This way, the base class is at the component level and not the entire system level. In other words, our base classes have become .btn and .alert, not .success. There's no bleeding of styles or behavior from one component to another here because we treat components in a "successful state" as an idea across the design system. That is to say, we have a shared idea of what "success" looks for buttons and alerts, but the execution is scoped entirely to each independent component. No questions of where common styles are used and no concern of unintended effects, making each component more durable and flexible.

这样一来,基础类被设定在组件级别,而不是整个系统级别。换句话说,我们的基础类变成了 .btn 和 .alert,而不是 .success。所有组件之间都不会出现样式和行为上的相互干扰,因为我们把组件具备“成功状态”视为贯穿整个系统的一种概念。这就是说,每个组件在“成功”状态下的样式,只有在 概念 层面才是相通的;而对于如何 实现 这个样式,是被约束在每个独立的组件内部的。不用操心通用的样式还会在哪里使用,也不用顾虑不可意料的副作用,这种方式使得每个组件更加稳定和灵活。

While a very tactical and detail-oriented practice, building components that inherently isolate themselves for improved modularity and customization in a system like Bootstrap makes for better code and a more enjoyable project down the line.

构建组件是一项非常具有策略性并且注重细节的工作,在一个类似 Bootstrap 的系统中,组件需要天生具备独立性,以提高模块分离度和可定制性。我们通过这种方式来打造更好的代码和一个令人愉悦的项目。


我的体会

作者视角

我自己在 CMUI 第一版中,基本上使用的是文章开头所说的“链式类名”风格。比如说,一个大号按钮的结构可能是这样的:

<button type="button" class="cmBtn cmLarge">Large button</button>

而在 Bootstrap 中,类似的元素是这样的:

<button type="button" class="btn btn-lg">Large button</button>

最开始我并没有觉得这两者有什么不同——前一个类名用于挂载框架预定义的按钮样式,后一个类名用于指定按钮的尺寸。把 Bootstrap 源码中所有的 .btn-lg 替换成 .cmBtn.cmLarge,不就跟我的 CMUI 一样了嘛?我甚至觉得 Bootstrap 的类命名有点啰嗦,.btn 和 .btn-lg 中的 btn- 不是重复了吗?还是 CMUI 干净利落啊!

然而,看完这篇文章,我似乎体会到 Bootstrap 这种设计的好处。我的理解可能并不是原作者的出发点,但也不妨列举出来,仅供参考。

用户视角

这两种类名风格的差异并不在于源码是怎么写的,而是在于开发者(这里指使用 Bootstrap 制作网页的开发者)在看到类名时的反应。我的理解是,不同的命名风格,对开发者的暗示是不同的。

开发者们并不总是会按照组件文档的示例来编写组件的结构代码。比如说,某些时候他们手边没有文档(或不想找文档),又或者他们所期望的样式在文档中并没有列出。他们可能会抱着一种试试看的心态,尝试修改或组合手头的几个类名,以期产生某种新的样式效果。

如果类名是宽泛的(比如 CMUI 中的 .cmLarge),就很容易被拿来尝试——比如开发者会给一个 ul.cmList 元素增加 .cmLarge 类并期望得到一个大号的列表,但实际上 CMUI 并没有提供这种组合!这破坏了开发者的预期,导致心理受挫,以致最终放弃这个组件库(夸张了点哈)。

但如果类名是被一个“组件级”前缀限定的(比如 Bootstrap 中的 .btn-lg),那么它被开发者拿去组合到其它组件身上的可能性就相当低。即使某个异想天开的开发者试图把 .btn-lg 改成 .dropdown-lg并应用到一个下拉菜单上,当他失败时,他应该也已经做好心理准备了罢。

结语

这样看来,Bootstrap 的做法确有它的好处,我的 CMUI 2.0 不妨也试试看。

希望本文能帮助到您!

点赞+转发,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓-_-)

关注 {我},享受文章首发体验!

每周重点攻克一个前端技术难点。更多精彩前端内容私信 我 回复“教程”

原文链接:
https://github.com/cssmagic/blog/issues/45

相关推荐