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.

Open
In both boxes the first child touches the top padding and the last child the bottom padding, with no space left over at either end. The fields are 1rem apart. In the article each heading has twice the space above it and half the space below it.
Code CSS · 11 lines
.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 5 reasons · 5 rules · support · credits

Why it works

  1. A margin describes the relation between two neighbors, so the element itself is the wrong place for it. A paragraph with margin-block-end leaves that margin behind when it is the last child of a padded box.
  2. gap puts space between flex items only. Nothing is left above the first child or below the last.
  3. * + * matches every child that has a sibling before it, so the first child gets no margin. Heydon Pickering named the selector the lobotomized owl.
  4. The fallback in var(--flow-space, 1em) is in em, so the space above each element follows that element's font size.
  5. 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

  1. 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.
  2. A flex column stretches its children, so a button or link that is a direct child becomes full width. Set align-self: start on it.
  3. 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.
  4. Keep the >. Without it the rule reaches every nested element, list items included.
  5. The margin form counts a hidden child, so a hidden first child leaves a space at the top. gap ignores 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