← 🧲 Flexbox · 简写语义与对齐边界 / 滚动容器的尾部 padding 去哪了 待审核 12 / 14
overflow · padding 丢失

滚动容器的尾部 padding 去哪了

给一个会横向滚动的 flex 容器加 padding: 0 20px,本意是首尾各留 20px。可在不少浏览器里,滚到最右时尾部那 20px 不见了——最后一项直接贴住容器右内边。根因是历史上浏览器计算可滚内容宽度(scrollWidth)时,只算到内容盒、padding-inline-end 排除在外,于是它落在滚不到的区域。这与居中即截断同属「flex + overflow 边界」,但那页是 justify-content: center首部推到负坐标,这页是尾部 padding 不计入可滚区。下面实测当前浏览器的真实表现。

1 · 滚到两端,实测首尾留白

容器设 padding: 14px 20px 且内容溢出。点按钮把它滚到最左 / 最右,用 getBoundingClientRect首项左缘、末项右缘到容器内边的可见距离:首部 20px 一般都在,尾部是否还在 20px 取决于本浏览器是否把 padding-inline-end 计入 scrollWidth。打开「末尾 spacer 修复」会在末尾插一个等宽占位,把那段留白塞进可滚内容里。

为什么是「尾部」而非「首部」。 滚动从 scrollLeft: 0 起算,首部 padding-inline-start 落在内容原点之前、天然在视野内;而 scrollLeft 的上限是 scrollWidthclientWidthscrollWidth - clientWidth,一旦 scrollWidth 不含尾部 padding,最右就停在「最后一项右缘」,那 20px 永远滚不出来。规范(CSS Overflow)对此长期未统一,各引擎行为和版本都有差异——所以本页以实测为准。

2 · 三种绕法

做法 效果 代价
末尾占位 (::after / spacer) 在内容末尾插一个 flex: none 的等宽占位,把尾部留白变成真实可滚内容 多一个无语义节点;::after 在 flex 容器上可直接当 item 用,无需改 DOM。
最后一项 margin-inline-end 给末项加右外边距,同样计入可滚宽度。 需选中「最后一项」(:last-child),且 margin 也属可滚内容。
border 代替 padding 用透明 / 同色 border-inline 留白,border 不受该问题影响。 滚动条位置随 OS 不同(可能压在 border 上),且 border 不能用百分比。

原生正解正在路上。 gap decorations 所属的 CSS Gaps / Overflow 工作中,滚动容器的 padding 行为也在被重新明确;现代 Chromium 已倾向padding-inline-end 计入可滚区(本页 lab 会实测当前结果)。在普遍落地前,上面三种绕法仍是稳妥选择,其中末尾占位兼容性最好、对 OS 滚动条无副作用。

3 · 延伸

  • Flexbox and padding · chenhuijing.com — 本页问题的出处:滚动 flex 容器尾部 padding 丢失的来龙去脉,以及 border / 伪元素两种绕法。
  • Scrollable overflow & padding · csswg-drafts #129 — 滚动容器是否应把 padding-inline-end 计入 scrollable overflow 的长期讨论。