最稳方案是padding-bottom配合position: relative/absolute:外层设padding-bottom百分比(如50%)撑高,内层absolute+top/left/right/bottom:0拉满,box-sizing:border-box保障内边距不溢出;aspect-ratio为现代简化写法但需兼容性fallback。

padding-bottom + position: absolute 是最稳的组合
直接用 width: 100%; height: 100% 行不通——因为 height 的百分比值是相对于父容器高度计算的,而父容器往往没设明确高度,结果就是高度塌陷为 0。真正能跨浏览器稳定生效的,还是靠 padding-bottom 撑高:它按父元素宽度计算,和 width 同源,天然同步缩放。
但光有 padding-bottom: 100% 还不行:内容会把容器往下顶,破坏正方形结构。必须让内容脱离文档流,所以得加 position: relative 在外层、position: absolute 在内层。
关键点:
- 外层容器不能有内容高度(即不写文字、不设
height、子元素不参与正常流) -
padding-bottom值必须等于width的百分比(如width: 50%→padding-bottom: 50%) - 内层内容需用
top: 0; left: 0; right: 0; bottom: 0拉满整个 padding 撑出的空间
内边距(padding)要算进正方形尺寸里,就得用 box-sizing: border-box
如果你在正方形内部还要加内边距(比如图片四周留白),直接给内容元素加 padding 会导致它超出容器边界——因为默认 box-sizing: content-box 下,width 和 height 不包含 padding。
正确做法是把 box-sizing: border-box 落到内容层(即绝对定位的那个元素),这样你设 padding: 1rem,它的可视区域仍严格占满整个正方形空间,只是内容被往里缩了。
示例结构:
.square {
width: 30%;
padding-bottom: 30%;
position: relative;
background: #eee;
}
.square > * {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
box-sizing: border-box;
padding: 1rem;
background: #fff;
}
aspect-ratio 可以简化,但别忽略它的兼容性断层
现代写法当然可以用 aspect-ratio: 1 / 1 直接搞定,而且支持内边距天然友好——你给元素设 padding,它会自动调整内容区,保持整体比例不变。
但要注意:Safari 15.4 之前不支持,Android WebView 旧版本(尤其 4.4–6.x)基本不可用。如果你的项目还需兼容微信内置浏览器(X5 内核)、钉钉或企业微信老版,aspect-ratio 就不能单独用。
稳妥策略是双写:
.square {
width: 30%;
padding-bottom: 30%; /* fallback */
aspect-ratio: 1 / 1; /* modern */
}
注意:aspect-ratio 会覆盖 padding-bottom 的效果,所以 fallback 必须写在前面。
用 vw/vh 单位时,内边距容易“撑破”视口
有人图省事写 width: 30vw; height: 30vw,看起来也正方形。但问题在于:一旦你给这个元素加 padding 或 border,总尺寸就变成 30vw + 2×padding,可能超出视口,触发横向滚动条。
解决方法只有两个:
- 用
box-sizing: border-box+ 显式减去内边距(如width: calc(30vw - 2rem)),但计算麻烦且响应不灵活 - 改用
padding-bottom方案,因为它的“撑高”本身已含内边距逻辑,后续再加padding是在内容层,不影响容器尺寸
真正难处理的不是怎么画正方形,而是怎么让「内边距」成为正方形的一部分,而不是它的敌人。多数人卡在这一步,是因为默认把 padding 当作装饰,没意识到它本质是尺寸控制变量。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











