先记住这个答案
在 flex 布局里,子项的 auto margin 会吸收所在方向上的所有剩余空间。交叉轴上也一样:margin-top: auto 会把行内上方的剩余空间全部吃掉,子项被推到底部。两端都设 auto 则上下平分空间,子项垂直居中。这个效果优先级比 align-items 和 align-self 都高。
- auto margin 吸收交叉轴剩余空间
- 优先级高于
align-self margin-top: auto推到底部- 两端都 auto 则垂直居中
用 auto margin 实现单个子项的特殊对齐
假设 flex 容器设了 align-items: flex-start,所有子项靠顶对齐。但某个子项需要贴在底部。常规做法是加 align-self: flex-end,但用 margin-top: auto 也行,而且优先级更高。
margin-top: auto 把子项推到底部CSS.container {
display: flex;
align-items: flex-start;
height: 200px;
}
.item {
/* 默认靠顶对齐 */
}
.item-bottom {
margin-top: auto; /* 上方空间全部被吃掉,子项贴底 */
}浏览器的结算顺序是:先计算 flex line 的高度和子项的尺寸,然后处理 auto margin,最后才看 align-self。auto margin 把空间吃完了,align-self 就没有空间可操作了。
两侧 auto 实现垂直居中
如果子项同时设了 margin-top: auto 和 margin-bottom: auto(或者直接 margin: auto 0),两侧平分交叉轴上的剩余空间,子项就垂直居中了。
这种居中方式不需要改容器的 align-items,而且只影响这一个子项。在需要让某个子项单独垂直居中而其他子项保持靠顶时特别有用。
和 align-self: center 的视觉效果一样,但 auto margin 的优先级更高,如果两者冲突,auto margin 赢。
和主轴上 auto margin 的区别
主轴上 margin-left: auto 是把子项推到右边,常用来做导航栏里「右侧按钮」的布局。交叉轴上 margin-top: auto 是把子项推到底部。原理一样,但方向不同。
主轴上 auto margin 还有一个特殊效果:它会让 justify-content 失效,因为 auto margin 先把剩余空间分完了。交叉轴上类似,auto margin 让 align-self 失效。
容易答错的地方
- 以为 auto margin 只在主轴上有效
- 交叉轴上一样有效。
margin-top: auto和margin-bottom: auto都会吸收交叉轴上的剩余空间。 - 忽略了行高不够时 auto margin 变成 0
- 如果子项高度等于 flex line 高度,交叉轴上没有剩余空间,auto margin 计算结果就是 0,推不动子项。这通常发生在容器没有设固定高度、行高由子项内容决定的时候。
面试官还会怎么问?
auto margin 和 align-self 同时写了谁优先?
auto margin 优先。规范规定 auto margin 在对齐属性之前结算。如果 margin-top: auto 吃掉了所有空间,align-self 就没有效果了。
怎么用 auto margin 实现 flex 子项的完美居中?
给子项设 margin: auto。在主轴上 auto 吸收左右剩余空间实现水平居中,在交叉轴上 auto 吸收上下剩余空间实现垂直居中。前提是容器要有明确的宽高,否则没有剩余空间可分。
Grid 布局里 auto margin 也能这样用吗?
可以。Grid 子项的 auto margin 同样会吸收单元格内的剩余空间,效果和 flex 类似。不过 Grid 有 place-self 更直观一些。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。