Entry 01

Section spacing that depends on its neighbors

Use it on any page built from reorderable sections, above all in a CMS where an editor decides the order. When two particular sections meet, the spacing between them changes on its own.

Open
Move the sections with the arrows. Where a named pair meets, the sulphur padding between the two shrinks and the readouts change: logos before features, features before cta, logos after hero, faq after features. Logos gets a line on top only straight after hero. Every other edge keeps 96px.
Code CSS · 9 lines
section { padding-block: 6rem; }

.logos:has(+ .features) { padding-block-end: 2rem; }
.features:has(+ .cta) { padding-block-end: 0; }

.hero + .logos { padding-block-start: 2rem; }
.features + .faq { padding-block-start: 3rem; }

.logos:where(.hero + *) { border-block-start: 1px solid; }
Why it works, the rules and the credits 4 reasons · 6 rules · support · credits

Why it works

  1. A:has(+ B) looks ahead. It matches A when B follows it, so A adjusts its own bottom edge.
  2. A + B looks back. It matches B when A precedes it, so B adjusts its own top edge.
  3. The rules describe pairs, not pages. Whatever order an editor picks, each pair that meets gets its spacing and every other section keeps its default.
  4. :where() adds no specificity, so a default that depends on the neighbor stays easy to override.

Rules

  1. A section owns its default padding. Write a pair rule only for a meeting that looks wrong with the defaults.
  2. Never fix spacing with a spacer element, a per-page override, or a modifier class the template has to work out.
  3. Put the rule on the section whose edge changes. Look ahead to change a bottom edge and look back to change a top edge.
  4. Name sections by what they are, such as .hero and .faq, never by the page they sit on. The pair rules depend on those names.
  5. Keep the list short. When many pairs share a reason, such as two sections with the same background, write one rule for the reason.
  6. Where the authoring system has no sibling selectors, keep these few rules in a plain stylesheet.

Support

:has() in Chrome 105, Firefox 121, Safari 15.4. The + combinator works everywhere.

Credits

Borrowed from: house pattern, used on production CMS sites · Kevin Powell, The adjacent sibling combinator · Jen Simmons, Using :has() as a CSS Parent Selector and much more, 2022-08-18