When I used to look at a design I would feel a kind of anxiety about how to implement the gaps. I would try to answer the question which element should this gap be a margin of?, and there was often no logically-justifiable answer. I recently came to the realisation that gaps don't have to be margin
s, and it's completely lifted that feeling of anxiety and refreshed how I look at designs. With a combination of spacer elements and gap
, the question simply doesn't come up any more, and the process of translating a design to a first draft of the markup is almost effortless.
Now, instead of trying to decide which element to attach a margin to, I just look at a design and write what I see:
<div id="header">
SomeText
</div>
<Gap heightEm={2}/> <!-- <div style="height: 2em"></div> -->
<div id="subtitle">
Subtitle
</div>
...
Having an actual element representing the gap also opens up functionality that can't be achieved with margins. Consider a design for a search page in its initial state: the main element is a large magnifying glass icon with the text "Start typing in the box to search" underneath. They're almost vertically centered but slightly closer to the top, and the gaps (above and below) should stay in proportion with each other as the page resizes -- down to a minimum size of 1em
. This is simply not possible with margins, but with spacer elements and grid
it's straight-forward and intuitive:
<div id="search">
<div></div> <!-- top margin -->
<div id="message">
<img src="magnifier.png">
<p>
Start typing in the box to search
</p>
</div>
<div></div> <!-- bottom margin -->
</div>
#search {
display: grid;
grid-template-rows: minmax(1em, 1fr) auto minmax(1em, 2fr);
}
If HTML were a procedural language -- with functions like renderDiv
instead of markup like <div></div>
-- CSS would be an advanced aspect-oriented programming system with the ability to do pattern-matching on the context and arguments of function calls, modify their behaviour, and insert preceding and following calls. This is great for all the things CSS is great for -- selecting groups of elements by attribute value and position in the DOM, and styling them accordingly -- but for the simple case of drawing a single box with a gap below it, just calling renderDiv
and then renderGap
(<div></div>
, <Gap/>
) is often the most logical and most maintainable solution.