探索 SMACSS:CSS 的可扩展和模块化架构

已发表: 2022-03-11

当我们在处理大型项目或与开发人员组一起工作时,我们经常会发现我们的代码很混乱、难以阅读、难以扩展。 随着时间的流逝,尤其如此,当我们回来重新审视它时,我们必须努力保持与我们写作时相同的心态。

所以很多人所做的是他们创建了 CSS 架构来帮助设计代码样式,从而使 CSS 变得更具可读性。 SMACSS — 即CSS可扩展模块化架构— 旨在做到这一点。 这是我采用的来自 Jonathan Snook 的一组特殊的 CSS 架构指南。

现在,SMACSS 的架构方法与 Bootstrap 或 Foundation 之类的 CSS 框架有点不同。 相反,它是一组规则,更像是一个模板或指南。 因此,让我们深入研究一些 CSS 设计模式,以了解如何使用它们来使我们的代码更好、更简洁、更易于阅读和更模块化。

每个 SMACSS 项目结构都使用五个类别:

  1. 根据
  2. 布局
  3. 模块
  4. 状态
  5. 主题

根据

在 SMACSS 中,基本样式定义了元素在页面任何位置的外观。 它们是默认值。 如果您使用重置样式表,这可以确保您生成的样式在各个浏览器中都是相同的,尽管它们内部的硬编码基本 CSS 默认值之间存在差异。

在基本样式中,您应该只包含裸元素选择器,或带有伪类的选择器,但不能包含类或 ID 选择器。 (您应该有充分的理由将类或 ID 放入其中,也许只有在您为第三方插件的元素设置样式并且您需要覆盖该特定元素的默认样式时。)

以下是基本文件单元的外观示例:

 html { margin: 0; font-family: sans-serif; } a { color: #000; } button { color: #ababab; border: 1px solid #f2f2f2; }

因此,它应该包括默认大小、边距、颜色、边框以及您计划在您的网站上使用的任何其他默认值。 您的排版和表单元素应该具有统一的样式,这些样式出现在每个页面上,并给人一种感觉和外观,它们是同一设计和主题的一部分。

不管是否使用 SMACSS,我强烈建议尽可能避免使用!important ,并且不要使用深度嵌套,但我将在本文后面详细讨论。 此外,如果您的实践是使用重置 CSS,那么您应该在此处包含它。 (我更喜欢使用 Sass,所以我只是将它包含在文件的顶部,而不必复制它或将它与每个页面的<head>元素分开引用。)

相关: Sass 主题化:SCSS 教程

布局

布局样式会将页面划分为主要部分——不是导航或手风琴等部分,而是真正的顶级部分:

示例 SMACSS 布局样式:页眉、侧边栏、内容/主文件和页脚

SMACSS 布局样式适用于页眉、侧边栏、内容/主要和页脚等主要部分。

这些布局将包含多个 CSS 模块,如框、卡片、无序列表、画廊等,但我将在下一节中详细讨论模块。 让我们考虑一个示例网页,看看我们可以分成哪些布局:

可以使用 SMACSS 组织成页眉、主页和页脚布局样式的示例网页

这里我们有页眉、主页和页脚。 这些布局在顶部的标题上有链接和徽标等模块,在主页面上有框和文章,在页脚有链接和版权。 我们通常给布局一个 ID 选择器,因为它们不会在页面上重复并且它们是唯一的。

此外,您应该在布局样式的规则前面加上字母l以将它们与模块样式区分开来。 通常在这里,您会设置特定于布局的样式,例如边框、对齐方式、边距等。页面该部分的背景也可能有意义,即使它看起来不像特定于布局。

以下是它的外观示例:

 #header { background: #fcfcfc; } #header .l-right { float: right; } #header .l-align-center { text-align: center; }

您还可以为对齐添加这些帮助器,您可以通过将适当的类添加到其子级或对齐其文本来轻松定位元素。

再举一个例子,您可以在布局框上使用一些默认边距,例如.l-margin的边距为20px 。 然后,无论你想为某个容器、元素、卡片或盒子填充什么,你只需将l-margin类添加到它。 但是你想要一些可重用的东西:

 .l-full-width { width: 100%; }

不是这样的内部耦合:

 .l-width-25 { width: 25px; }

我想花点时间谈谈 SMACSS 中的命名约定。 如果您从未听说过 CSS 中命名空间的概念,它基本上是将名称添加到另一个元素的开头,以帮助将其与其他元素区分开来。 但是我们为什么需要这个?

不知道你有没有遇到过下面的问题。 你正在编写 CSS 并且你有一个标签——你可以放入任何你喜欢的样式,并调用你的类.label 。 但是稍后您会遇到另一个元素,并且您也希望它是.label ,但样式不同。 因此,两个不同的事物具有相同的名称——命名冲突。

命名空间可以帮助您解决这个问题。 最终,它们在一个层面上被称为相同的东西,但它们有不同的命名空间——不同的前缀——因此可以代表两种不同的风格:

 .box--label { color: blue; } .card--label { color: red; }

模块

就像我之前提到的,SMACSS 模块是可在页面上重用的较小代码位,它们是单个布局的一部分。 这些是我们想要存储在一个单独的文件夹中的 CSS 的一部分,因为我们将在一个页面上有很多这些。 随着项目的发展,我们可以使用文件夹结构最佳实践进行拆分,即按模块/页面:

使用 SMACSS 和 Sass 的示例文件/文件夹层次结构

所以在前面的例子中,我们有一篇文章,它本身可以是一个模块。 这里应该如何构建 CSS? 我们应该有一个.article类,它可以有子元素titletext 。 因此,为了能够将其保留在同一个模块中,我们需要为子元素添加前缀:

 .article { background: #f32; } .article--title { font-size: 16px; } .article--text { font-size: 12px; }

您可能会注意到我们在模块前缀后使用了两个连字符。 原因是有时模块名称有两个单词或它们自己的前缀,如big-article 。 我们需要有两个连字符来区分子元素的哪一部分——例如将big-article-titlebig-article--titlebig-article--text进行比较。

此外,如果特定模块占据页面的大部分,您可以将模块嵌套在模块中:

 <div class="box"> <div class="box--label">This is box label</div> <ul class="box--list list"> <li class="list--li">Box list element</li> </ul> </div>

在这里,在这个简单的示例中,您可以看到box是一个模块,而list是其中的另一个模块。 所以list--lilist模块的孩子,而不是box的孩子。 这里的关键概念之一是每个 CSS 规则最多使用两个选择器,但在大多数情况下,只有一个带前缀的选择器。

这样,我们可以避免重复规则,也可以在同名的子元素上使用额外的选择器,从而提高速度。 但它也有助于我们避免使用不需要的!important样式规则,这是 CSS 项目结构不佳的标志。

好(注意单个选择器):

 .red--box { background: #fafcfe; } .red-box--list { color: #000; }

不好(注意选择器中的重复和重叠的参考方法):

 .red .box { background: #fafcfe; } .red .box .list { color: #000; } .box ul { color: #fafafa; }

状态

SMACSS 中定义的状态是一种描述我们的模块在不同动态情况下的外观的方式。 所以这部分真的是为了交互性:如果一个元素被认为是隐藏、扩展或修改的,我们想要不同的行为。 例如,jQuery 手风琴将需要帮助来定义您何时可以看到或不能看到元素的内容。 它帮助我们在特定时间定义元素的样式。

状态应用于与布局相同的元素,因此我们添加了一个额外的规则,它将覆盖以前的规则,如果有的话。 州规则具有优先权,因为它是规则链中的最后一条。

与布局样式一样,我们倾向于在这里使用前缀。 这有助于我们识别它们并给予它们优先权。 这里我们使用is前缀,如is-hiddenis-selected

 <header> <ul class="nav"> <li class="nav--item is-selected">Contact</li> <li class="nav--item">About</li> </ul> </header>
 .nav--item.is-selected { color: #fff; }

在这里,可以使用!important ,因为状态通常用作 JavaScript 修改而不是在渲染时使用。 例如,您有在页面加载时隐藏的元素。 单击按钮时,您要显示它。 但是默认类是这样的:

 .box .element { display: none; }

所以如果你只是添加这个:

 .is-shown { display: block; }

即使您通过 JavaScript 将.is-shown类添加到元素后,它仍将保持隐藏状态。 这是因为第一条规则有两层深并且会覆盖它。

因此,您可以像这样定义状态类:

 .is-shown { display: block !important; }

这就是我们将状态修饰符与布局修饰符区分开来的方式,后者仅适用于页面的初始加载。 现在这将起作用,同时保持最小选择器的优势。

主题

这应该是最明显的,因为它用于包含原色、形状、边框、阴影等的规则。 大多数是在整个网站上重复的元素。 我们不想在每次创建它们时重新定义它们。 相反,我们想要定义一个唯一的类,我们稍后只会将其添加到默认元素中。

 .button-large { width: 60px; height: 60px; }
 <button class="button-large">Like</button>

不要将这些 SMACSS 主题规则与基本规则混淆,因为基本规则仅针对默认外观,它们往往类似于重置为默认浏览器设置,而主题单元更像是一种样式,它提供最终外观,这种特定的配色方案是独一无二的。

如果站点有多个样式或者可能有几个在不同状态下使用的主题,主题规则也很有用,因此可以在页面上的某些事件期间轻松更改或交换,例如使用主题切换按钮。 至少,它们将所有主题样式保存在一个地方,因此您可以轻松更改它们并保持它们井井有条。

CSS 组织方法论

我已经介绍了这个 CSS 架构理念的一些关键概念。 如果你想了解更多关于这个概念的信息,你可以访问 SMACSS 的官方网站并深入了解它。

是的,您可能可以使用更高级的方法,例如 OOCSS 和 BEM。 后者几乎涵盖了完整的前端工作流程及其技术。 BEM 选择器可能对某些人很有效,但有些人可能会发现它们太长且难以使用,而且使用起来也太复杂。 如果您需要一些更简单、更容易掌握并融入您的工作流程的东西,并且还需要为您和您的团队定义基本规则的东西,那么 SMACSS 是完美的选择。

新团队成员不仅可以很容易地了解以前的开发人员做了什么,而且可以立即开始工作,而编码风格没有任何差异。 SMACSS 只是一个 CSS 体系结构,它按照它在锡上所说的去做——不多也不少。