position: sticky; bottom: 0 inside a padded overflow:auto panel stops at the padding edge, leaving content visible underneath
Pinning a CTA bar to the bottom of a scrolling modal panel (.panel { max-height: 85vh; overflow-y: auto; padding: 22px 20px 18px }). The bar is the panel's last child: .ctas { position: sticky; bottom: 0; margin: 16px -20px -18px; padding: 12px 20px 18px; background: <panel bg> }, with the negative margins meant to make it span edge to edge over the panel's padding. Scrolled to the end it sits flush, but while the content overflows (bar stuck), an 18px strip of the scrolling content shows below the bar, between the bar and the panel's bottom border. Measured in Chrome 151 (chrome-headless-shell): bar.getBoundingClientRect().bottom was 18px above panel.getBoundingClientRect().bottom while stuck. Adding z-index and an opaque background didn't help; the bar simply isn't reaching the panel's edge.
The sticky inset is measured from the scroll container's scrollport reduced by its padding (the 'sticky view rectangle' excludes the container's padding), so bottom: 0 parks the element at the panel's content edge, 18px above the border here. The negative margin only moves the element's in-flow position; it doesn't change where sticking happens.
Fix: make the inset equal the negative of the container's padding on that side, and keep the bar's own padding for breathing room:
.ctas {
position: sticky;
bottom: -18px; /* = scroll container padding-bottom */
z-index: 1;
margin: 16px -20px -18px; /* span the panel's padding edge to edge */
padding: 12px 20px 18px;
background: var(--panel-bg);
}
.ctas::before { /* optional: fade the content into the bar */
content: ''; position: absolute; left: 0; right: 0; bottom: 100%; height: 16px;
background: linear-gradient(to bottom, transparent, var(--panel-bg));
pointer-events: none;
}Verified: with bottom: -18px the stuck bar's bottom equals the panel's inner bottom both mid-scroll and at scroll end (getBoundingClientRect comparison), and document.elementFromPoint at the button center returns the button without scrolling. Alternative: move the padding off the scroll container onto an inner wrapper, then bottom: 0 works as-is.