Entry 02
Space between siblings set by the parent
Use it wherever elements sit one above another, such as form fields, the parts of a card or the blocks of an article. The parent sets one space between its children, and no child carries a block margin of its own.
Code
.fields {
display: flex;
flex-direction: column;
gap: 1rem;
}
.prose > * { margin-block: 0; }
.prose > * + * { margin-block-start: var(--flow-space, 1em); }
.prose > :is(h2, h3) { --flow-space: 2em; }
.prose > :is(h2, h3) + * { --flow-space: 0.5em; }Why it works, the rules and the credits
Why it works
- A margin describes the relation between two neighbors, so the element itself is the wrong place for it. A paragraph with
margin-block-endleaves that margin behind when it is the last child of a padded box. gapputs space between flex items only. Nothing is left above the first child or below the last.* + *matches every child that has a sibling before it, so the first child gets no margin. Heydon Pickering named the selector the lobotomized owl.- The fallback in
var(--flow-space, 1em)is inem, so the space above each element follows that element's font size. - A custom property on a child changes the space above that child alone. A heading asks for more room above itself, and whatever follows a heading asks for less.
Rules
- Use the flex form in a component whose children you know. Use the margin form for content you do not control, such as CMS or Markdown output, because flex turns every child into a flex item.
- A flex column stretches its children, so a button or link that is a direct child becomes full width. Set
align-self: starton it. - In the margin form, zero the children's block margins first. Without that line the browser's default margins stay above the first child and below the last.
- Keep the
>. Without it the rule reaches every nested element, list items included. - The margin form counts a hidden child, so a hidden first child leaves a space at the top.
gapignores hidden children.
Support
gap in flex layout in Chrome 84, Firefox 63, Safari 14.1. :is() in Chrome 88, Firefox 78, Safari 14.
Credits
Borrowed from: Heydon Pickering and Andy Bell, The Stack, Every Layout · Heydon Pickering, Axiomatic CSS and Lobotomized Owls, 2014-10-21 · Andy Bell, My favourite 3 lines of CSS, 2023-02-06. Both authors keep the margin form everywhere. This version uses gap in components.
Docs: MDN: gap · MDN: next-sibling combinator