padding-top: 50% 不按父元素高度计算,因会引发“高度依赖 padding,padding 又依赖高度”的循环;CSS 规范强制其基于包含块宽度计算,且 display: table-cell 中该值直接被忽略为 0。

padding-top: 50% 为什么算出来不是父元素高度的一半
因为浏览器根本没拿父元素高度当基准——它连父元素高度是多少都可能还没算出来。在标准文档流中,一个 height: auto 的父容器,其高度由子内容 + padding + border 共同决定;如果此时子元素的 padding-top: 50% 又反过来依赖这个尚未确定的高度,就会陷入“高度依赖 padding,padding 又依赖高度”的死循环。W3C 规范(CSS2.1)明确要求:padding-top、padding-bottom、margin-top、margin-bottom 的百分比值“must be calculated with respect to the width of the containing block”。这不是 bug,是 layout 引擎能稳定收敛的唯一解。
包含块宽度 ≠ 父元素的 width 属性值
你以为给父元素写了 width: 300px,子元素的 padding-top: 20% 就是 60px?不一定。实际基准是“包含块的宽度”,而包含块未必是直接父元素:
- 若父元素是
position: static(默认),包含块通常是最近块级祖先的内容区宽度(不含 padding 和 border) - 若父元素设了
position: relative,而子元素是position: absolute,那包含块就跳转为该 relative 父元素的 padding box 宽度(含 padding,不含 border) - 在
display: flex或display: grid容器中,子项的包含块宽度 = 容器 content box 宽度,不是子项被分配到的尺寸,更不是容器 height
display: table-cell 里 padding 百分比完全不生效
这是 CSS2.1 明确规定的例外行为,所有主流浏览器一致执行:padding-top: 100% 在 display: table-cell 元素上会被当作 0 处理,连计算步骤都跳过。这不是渲染 bug,也不是兼容性问题。如果你看到它没反应,别调样式、别查 DevTools 计算值——直接换掉 display 类型,或改用像素值。
怎么快速验证当前 padding 百分比到底按谁算
别靠眼睛猜“看起来像不像”,用可测量方式定位包含块:
立即学习“前端免费学习笔记(深入)”;
- 给疑似父容器加
border: 1px solid red和padding: 1px,拖动窗口观察子元素padding-top是否随该容器宽度线性变化 - 检查该容器是否设置了
position: relative、absolute或fixed——这会让子元素的包含块向上跳转 - 在 DevTools 的 Computed 面板里看
padding-top的像素值,再反向除以你怀疑的宽度(比如容器 clientWidth),结果接近 100% 就确认了基准
真正容易被忽略的,是“包含块”可能隔着好几层祖先,尤其当用了 position、flex、grid 或 transform 时——这时第一反应不该是怀疑 CSS 写错了,而是打开 DevTools 逐层点开 computed 样式,盯住 “Containing Block” 这一行。


















