为什么我们不能同时使用函数式 CSS 和常规 CSS?

Avatar of Robin Rendle
Robin Rendle

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

Harry Nicholls 最近写了一篇关于 使用函数式 CSS 简化样式 的文章,您一定要看看。 简而言之,函数式 CSS 是 原子 CSS使用“辅助”或“实用”类 的另一个名称,这些类只会处理 paddingmarginbackground-colorcolor 等。

Harry 完全喜欢在元素上添加多个这样的类。

所以,我在这里试图倡导的是利用其他人构建函数式 CSS 库所做的工作。 它们建立在设计的基础之上,人们花了许多时间思考这些库应该如何构建,以及哪些是最有用的类。

而且,不仅类有用,而且 Tachyons 背后的基本设计原则也有用。

这对我来说很有道理。 但是,Chris 指出,他还没有听说过函数式/原子 CSS 方法的缺点。

大规模重新设计会发生什么? 是相同的、时间和难度方面,还是您花更多时间拆除所有这些类? 当您需要一个不可用的样式时会发生什么? 自己写? 还是这会破坏所有这些的精神,把你置于危险的境地? 所有的类名可以有多复杂? 我可以想到我为其设计过样式的区域,这些区域有三个或更多媒体查询,它们会极大地重新设计元素。 将所有这些信息放在 HTML 中似乎会变得非常混乱。 一致性更难还是更容易?

这对我来说也很有道理,但问题是:我非常喜欢这两种方法,甚至将它们组合在同一个项目中。

在你生气之前,听我说

在 Gusto(我今天工作的公司),我一直在尝试设计一个使用这两种方法的系统,因为我真的相信它们可以彼此和谐共处。 它们各自解决了编写 CSS 的非常不同的用例。

以下是一个示例:假设我们在一个大型 React Web 应用程序中工作,并且我们的设计师交付了一个页面设计,其中一个段落和一个按钮需要在下方留出更多间距。 我们的代码如下所示

<p>Item 1 description goes here</p>
<Button>Checkout item</Button>

这正是函数式 CSS 解决的问题。 在 Gusto,我们会做类似的事情

<div class="margin-bottom-20px">
  <p>Item 1 description goes here</p>
  <button>Checkout item</button>
</div>

换句话说,我们使用函数式类来进行布局调整,这些调整可能特定于我们正在处理的特定功能。 但是! 该 Button 组件由一个普通的 CSS 文件组成。 在 btn.scss 中,我们有类似的代码,然后将其导入到我们的 btn.jsx 组件中

.btn {
  padding: 10px 15px;
  margin: 0 15px 10px;
  // rest of the styles go here
}

我认为为自定义组件创建全新的 CSS 文件比尝试使用大量类(例如 margin-*padding-* 等)来创建这些组件要容易得多。 虽然,我们也可以在 btn.jsx 组件中使用函数式样式,如下所示

const Button = ({ onClick, className, children }) => {
  return (
    <button
      className='padding-top-10px padding-bottom-10px padding-left-15px padding-right-15px margin-bottom-none margin-right-15px margin-left-15px margin-bottom-10px ${className}')}
      onClick={onClick}
    >
      {children}
    </button>
  );
};

这不是一个现实的例子,因为我们只处理两个属性,我们可能希望为该按钮的背景色、文字颜色、悬停状态等设置样式。 而且,是的,我知道这些类名有点复杂,但我认为即使将垂直和水平类结合在一起,我的观点仍然成立。

所以 我认为 通过在此特定实例中将自定义样式写入单独的 CSS 文件,我们用函数式 CSS 解决了以下三个问题

  1. 可读性
  2. 管理属性依赖项
  3. 避免视觉设计不喜欢数学的痛苦事实

如您在前面的代码示例中看到的,很难阅读并立即看到哪些类已应用于按钮。 更多的类意味着更难扫描。

其次,许多 CSS 属性/值对是相互关联的。 例如,position: relativeposition: absolute。 在我们的样式表中,我希望能够看到这些依赖关系,我相信用函数式 CSS 做到这一点更难。 CSS 通常依赖于 CSS 的其他部分,并且用注释或属性/值分组来查看这些连接很重要。

最后,视觉设计是一个问题。 许多视觉设计需要不完美的数字,这些数字无法正确缩放。 使用函数式 CSS 系统,您可能希望使用以 10 为底或以 8 为底的系统,其中每个值都基于该比例。 但是,当您在视觉上将项目对齐时,您可能需要以一种与这些值不对齐的方式进行对齐。 这被称为 光学调整,这是因为我们的大脑很奇怪。 在数学上合理的,在视觉上往往不合理。 因此,在这种情况下,我们需要在按钮下方添加更多底部填充,以使文本看起来像是在中心位置。 使用函数式 CSS 方法,至少根据我的经验,很难整洁地做到这一点。

在需要平衡可读性、依赖关系和光学调整的那些情况下,在传统的样式表中编写常规 CSS 仍然是我最喜欢的事情。 但是,函数式 CSS 仍然非常优雅地解决了大量其他问题。

例如,我们在 Gusto 使用函数式类试图防止的是创建大量样式表,这些样式表执行大量非常具体或自定义的事情。 回到前面关于两个元素下方间距的示例

<div className='margin-bottom-20px'>
  <p>Item 1 description goes here</p>
  <Button>Checkout item</Button>
</div>

过去,我们的团队可能会写类似的东西

<div className='cool-feature-description-wrapper'>
  <p>Item 1 description goes here</p>
  <button>Checkout item</button>
</div>

需要在我们的应用程序中创建一个名为 cool_feature_description_wrapper.scss 的新 CSS 文件,如下所示

.cool-feature-description-wrapper {
  margin-bottom: 20px;
}

我认为像这样的样式使我们的代码更难理解、更难阅读,并鼓励偏离我们的组件库。 通过将其替换为来自我们的函数式类库的类,它突然变得更容易阅读,并且将来更容易更改。 它还解决了我们特定需求的自定义解决方案,而无需分叉我们的样式库。

所以,我没有读到太多关于以这种方式平衡这两种方法的文章,尽管我认为有人已经深入地介绍了这个问题。 我真正相信,将这两种方法结合起来比尝试用一个技巧包来解决所有问题更有用。

我知道,对吧? 模棱两可的观点是最糟糕的。