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.
Code
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
Why it works
A:has(+ B)looks ahead. It matches A when B follows it, so A adjusts its own bottom edge.A + Blooks back. It matches B when A precedes it, so B adjusts its own top edge.- 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.
:where()adds no specificity, so a default that depends on the neighbor stays easy to override.
Rules
- A section owns its default padding. Write a pair rule only for a meeting that looks wrong with the defaults.
- Never fix spacing with a spacer element, a per-page override, or a modifier class the template has to work out.
- Put the rule on the section whose edge changes. Look ahead to change a bottom edge and look back to change a top edge.
- Name sections by what they are, such as
.heroand.faq, never by the page they sit on. The pair rules depend on those names. - Keep the list short. When many pairs share a reason, such as two sections with the same background, write one rule for the reason.
- 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