With a modern layout using flex and grid, I see margin becoming a more explicit and incidental property for a specific use case. In general, I've stopped using margins to control positioning an element. This allows me to revisit the spacing model I use for design systems.
I consider two types of spacing:
I apply these types of spaces across four layers in a document.
- Context level
- Body or top-level element
Elements like an app or a main layout container
- Layout and content containers
footer, cards, etc.
- Content elements
buttons, headings, list items, labels, inputs, etc.
The context refers to the root of the light or the host of the shadow DOM. Do not touch either. Only, if needed, reset and normalise. Also, I do not touch the
border-box. Including padding in the width of an element has now become our friend. The context host is also where I set all the base font styles. I do not set any sizing values on the body.
The top-level control the layout for the rest of the page and sets its dimensions in
DVH. This can be the
body element, but in many cases, I only need to add a flex or grid to control the position of the underlying containers. I can also omit a top-level wrapping container with a subgrid based on the body to give a layout of nested elements. That would be one div less. The top-level container always uses
REM units for
gap values. However, I do not use logical values, as the reading direction isn't relevant here.
Containers have two types: layout and content containers. The Layout containers are actually outer content elements like
footer. These form the basis of any modern web page. Like the top-level container, directional
padding (top, right, bottom, left) and
gap with REM units are used.
Content containers like Cards, Modals, notifications, menubars, etc. I treat them on the whole like layout containers. Depending on the amount of text, they may have exceptions to their spacing properties. Otherwise, they are still part of the visual structure and not a type of content.
The content-level elements always use a mix of values based on reading directionality. I use the logical 'block' and 'inline' properties here.
For the rows and the block direction,
EX is used, and for columns and inline
CH is appropriate.
So, why all the fuss?
Well, the ability to use container queries further enables the autonomy of components. To have a genuinely autonomous feature, we should avoid reaching beyond the element visually with
margin like we shouldn't reach for parent elements beyond the component.