Entry 02

Scroll area between a fixed header and footer

Use it for the body of a modal, a chat list, a drawer or a sidebar. The panel grows with its content up to a limit, then the middle scrolls and the header and footer stay put.

Open
Each panel is at most 80% of the frame's height. Its header and footer stay put and the list between them scrolls. The second panel has a form between the panel and the list, and behaves the same. Scroll a list to its end: the page behind does not move. Press Fewer rows: both panels shrink to their content and the scrollbar goes.
Code CSS · 19 lines
.panel {
  display: flex;
  flex-direction: column;
  max-block-size: 80dvh;
}

.panel-body {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
}

.panel-wrap {
  flex: 1;
  min-block-size: 0;
  display: flex;
  flex-direction: column;
}
Why it works, the rules and the credits 5 reasons · 5 rules · support · credits

Why it works

  1. A flex item will not shrink below its content. A scroll container is the exception, with a minimum of zero, so the body shrinks to the space left and scrolls.
  2. An element between the panel and the body, such as a form, is not a scroll container. It keeps the height of its content and pushes the footer out of the panel. min-block-size: 0 gives it the same zero minimum.
  3. auto shows a scrollbar only when there is overflow.
  4. scrollbar-gutter does not inherit. The reset's declaration on :root covers the page and no inner scroller.
  5. overscroll-behavior: contain stops the scroll from passing to the page at the end of the list.

Rules

  1. The panel needs a limit, either max-block-size or a height. With no limit nothing overflows.
  2. .panel-wrap is only for an element that sits between the panel and the body. Leave it out when the body is a direct child.
  3. A header or footer with a set height shrinks to its content when the body overflows. Give it flex: none, or size it with padding.
  4. Keep min-height: 0 out of the reset. On every element it lets each item of a fixed-height column shrink under its own text.
  5. The gutter takes the scrollbar's width on a short list as well. That is the price of no shift.

Support

scrollbar-gutter in Chrome 94, Firefox 97, Safari 18.2. overscroll-behavior in Chrome 63, Firefox 59, Safari 16. dvh in Chrome 108, Firefox 101, Safari 15.4.

Credits

Borrowed from: Ahmad Shadeed, Defensive CSS, the tips Scrollbars on demand, Scrollbar gutter, Scroll chaining and Minimum content size in flexbox. He gives the four declarations one by one, and the panel around them is added here.

Docs: MDN: scrollbar-gutter · MDN: overscroll-behavior · MDN: min-height