TL;DR
- grid-gap for grid layout
- If it's a flexbox, I want to use flex-gap (but Safari doesn't support it as of today).
- Specify the appropriate padding
- Stack component for multiple identical margins, Spacer component for the rest.
Child components should not know the "layout style" of the parent component
First of all, child component should not know the "layout style" of its parent component.
For example, let's say there is a component with multiple icons arranged like this.
There are margins between the icons at equal intervals.
Let's say you have defined this margin in the icon component as below.
.icon {
...
... margin-right: 15px;
}
Now, let's say you want to use this icon component on another page, and in that page it requires 100px margin on the right side of the icon. How would you style margin?
There are many ways to solve this problem, but no matter what your choice is, you will have to worry about the margin in this icon component. And I think it's easy to imagine that as such solutions pile up, we'll have more and more dirty CSS.
This is why child components should not be styled by their parents in terms of what layout they will be used in.
It's ok to have appropriate "padding"
I think it's okay to have components to have own "padding" as long as the padding is appropriate.
For instance, you may want to make the button component larger than it appears to be in order to increase area to accept click.
As long as you are aware of who owns the margins and make the right decisions, you should be fine.
Who owns margin?
As I mentioned above, as long as you are aware of who owns the margins and can make the right decisions, you should be fine.
So the question is "who owns margin between elements?"
I think it's either "parent" or "nobody".
Parent
The most obvious case is the grid layout, where the parent container describes the layout style. Margins can be specified with grid-gap
.
.grid {
display: grid;
grid-gap: 1rem;
}
Nobody
If the parent doesn't specify any structure for the layout, the margin can be considered as an independent entity, not belonging to anyone.
This should also be same as the way designers think of margins. When the designer decide a margin between two elements, he/she doesn't think "the margin is tied to this one", but rather "these are the same concept, so the margin should be smaller, and these are completely different, so let's separate them more", and so on.
They decide margin based on the "relationship" between those elements.
Therefore, margin does not belong to either of them, but is only responsible for one thing: having margin.
How to implementation
Let's dive into how to implement it.
Parent - Grid
As I mentioned earlier, for Grid Layout, we'll use grid-gap
. (If you don't add grid-
, it won't work in Safari).
https://developer.mozilla.org/en/docs/Web/CSS/gap
You can specify the vertical and horizontal direction respectively.
If you want to set different widths in the same row or column, you can nest them together to make it work.
parent - flexbox
I'd like to use gap
, but Safari doesn't support it at the time of this writing, so it will be difficult to adopt. I hope they will be implemented it soon!
https://developer.mozilla.org/en/docs/Web/CSS/gap
https://caniuse.com/flexbox-gap
Same margin between child elements
This is the case when using list elements such as ul
and ol
.
For this, use Stack
component.
As an example, let's look at the Stack in Chakra UI.
https://chakra-ui.com/docs/layout/stack
If you set the spacing
of the Stack
component like this, the value will be applied as the margin between elements.
In Chakra UI, children are mapped and wrapped with a component called StackItem to apply the margin style.
If you happen to have multiple values of the same margin for this Stack, you may want to use this method. (However, since it's not conceptually correct, you may have to break it down if you want to set a different margin for new elements in the future. So in that case, I think it's better to use Spacer.)
Nobody
Lastly, in the case that it doesn't belong to anyone, let's think about making a Spacer component.
If you want to make your own, you can specify the size
and axis
as follows.
(Referenced from https://www.joshwcomeau.com/react/modern-spacer-gif/)
import React from 'react';
const Spacer = ({
size,
axis,
style = {},
... .delegated,
}) => {
const width = axis === 'vertical' ? 1 : size;
const height = axis === 'horizontal' ? 1 : size;
return (
<span
style={{
display: 'block',
width,
minWidth: width,
height,
minHeight: height,
... . style,
}}
{... .delegated}
/>
);
};
export default Spacer;
The only props needed is size.
// It will be 16px x 16px
<Spacer size={16} />
If the width of the Spacer gets in the way in directions other than the one you want, you can specify the axis direction to keep it to a minimum.
// It will be 32px x 1px.
<Spacer axis="horizontal" size={32} />
Conclusion
Spacer may seem weird at first sight, but I personally think it makes a lot of sense, so let's make use of Stack and Spacer to get some nice margin styling💪
Reference
https://www.joshwcomeau.com/react/modern-spacer-gif/
https://mxstbr.com/thoughts/margin/
Top comments (0)