假设您有一个 <Card />
组件。它很可能不应该紧贴其他组件,周围没有间距。这对于几乎所有组件都适用。那么,如何在设计系统中处理组件间距呢?
您是否直接在 <Card />
上使用 margin 来应用间距?也许 margin-block-end: 1rem; margin-inline-end: 1rem;
使其从更多内容自然流动的两侧推开?这有点武断。也许卡片是在 <Grid />
组件内的子元素,并且网格应用了 gap: 1rem
。这很尴尬,因为现在 <Card />
组件的间距将与 <Grid />
组件的间距发生冲突,这很可能不是您想要的,更不用说间距是硬编码的了。

关于组件间距的不同观点
Eric Bailey 最近对此进行了研究 并查看了一些选项。
- 您可以将间距烘焙到每个组件中,并尽力使其尽可能聪明。(但这非常有限。)
- 您可以传入组件间距,例如
<Card space="xxl" />
。(这可能是一个好方法,可能需要多个属性,甚至可能每个方向一个,这非常冗长。) - 您可以不使用任何组件间距,并创建一个像
<Spacer />
或<Layout />
组件,专门用于组件之间的间距。(它很好地将组件的工作分解,但也可能很冗长并增加不必要的 DOM 权重。)
这场讨论的观点范围很广,有些观点甚至像 Max Stoiber 一样极端,他说 永远不要使用 margin
。这对我来说有点教条主义,但我喜欢它试图重新思考问题。我喜欢将间距和布局的工作从组件本身中分离出来的想法——例如,这些内容组件应该完全不关心它们在哪里使用,并让布局发生在它们之上。
Adam Argyle 几年前预测,随着 gap
使用量的增加,CSS 中 margin
的使用量会下降。他最终可能会说对了,尤其是在 flexbox 拥有 gap
并且开发者现在都喜欢在宏观和微观层面上几乎所有东西都使用 CSS Flexbox 和 Grid 的情况下。
对我来说,一切都是关于 组合布局 的。
让骨架布局处理大小和间距,那么组件放在哪里就无关紧要了。
对于卡片网格,我仍然使用 flex diplay,因为 grid 无法满足我的所有需求。
几年前,我写了自己的 less 代码,根据左侧减去的值来减去左侧的 margin,这样就不会强制出现滚动条。它也对 IE9 及更早版本(如果仍然需要)提供了简单的回退。
在其中,我有一个用于间距的变量,我设置了它。
这是我最喜欢的 Vue 的功能之一。您可以直接在组件上放置一个来自使用上下文中的类,它将落在组件的根元素上。无需为这种常见需求向所有组件添加新的
prop
。(这在 Vue 3 中随着多根组件的引入而略有变化,但它们仍然可以使用原生
class
属性明确绑定它。)哦,哇,感谢您的链接!我还想在这里表达一些其他想法。
gap
的正式 Grid 组件的组合作为他首选的方法。我非常喜欢gap
,希望在我们的 IE 支持问题消失后,最终能够在我们的设计系统中使用它。我也非常喜欢使用 Grid 组件来创建语义的、有意图的页面/视图整体布局的想法。在 HalalBooking,我们使用
:not(:last-child)
方法。因此,margin 只应用于组件的一侧,子元素不会影响父元素的 margin。例如
我们以两种方式应用它
– 直接应用于组件(如果页面上有 50 个以上的组件实例,这很好)
– 作为额外的 CSS 类/组件,例如
.vertical-section--xxl
。这让我们更容易处理。我绝对倾向于将组件本身与它所处的结构分开。
除非特别需要,否则组件没有大小(自然占用整个空间)也没有外部间距(没有 margin)。
然后,结构可以处理间距。无论是具有间距设置的网格,还是具有定义的 flexbox,这些定义可以对 flexbox 环境内的元素应用 margin。
允许作者在不同的环境和上下文中使用同一个组件构建页面,并仍然获得基于设计系统的适当间距。
现在,我在我们的设计/组件系统中做的事情与 Ben 在上面写的类似。
组件的间距由它所处的上下文定义。因此,组件本身不会处理它自己的 margin,而是父级(另一个组件或页面)会处理,并包含所有关于其子元素间距的逻辑。因此,没有组件本身具有任何外部 margin,但这些 margin 主要由其父级设置。