先记住这个答案
translate 的百分比始终参照元素自身的宽高。translateX(50%) 让元素向右移动自身宽度的一半,translateY(-100%) 让元素向上移动自身高度的整个距离。不管父元素多大,百分比算出来的移动距离只和元素自身尺寸有关。
translateX百分比相对自身宽度translateY百分比相对自身高度- 绝对定位配合半幅
translate可居中 translate百分比基准与边距不同
最经典的用法:不知道宽高也能居中
绝对定位的 top: 50%; left: 50% 把元素的左上角放到容器中心,但元素本身偏了。加上 translate(-50%, -50%) 再把元素往左和往上各移自身宽高的一半,正好让元素中心对准容器中心。
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%; /* 左上角移到容器垂直中点 */
left: 50%; /* 左上角移到容器水平中点 */
transform: translate(-50%, -50%); /* 往回移半个自身宽高 */
}这个写法之所以好用,就是因为 translate 的百分比相对自身。不管 .child 里面内容多少、宽高多少,-50% 始终是自身宽高的一半。用 margin 做不到这一点,因为 margin 的百分比相对的是父元素的宽度。
和其他属性的百分比规则对比
CSS 里不同属性的百分比参照物不一样,这经常让人搞混。
margin 和 padding 的百分比,不管是左右还是上下,都是相对包含块的宽度。margin-top: 10% 算的是包含块宽度的 10%,不是高度的 10%。
width 和 height 的百分比相对包含块的宽度和高度。
translate 的百分比相对自身。translateX 看自身宽度,translateY 看自身高度。这个设计很合理:translate 的目的就是移动元素自身,如果相对父元素,用起来会很不直观。
background-position 的百分比更特殊,它相对的是容器和图片的差值。这个不需要在面试里展开,知道 translate 相对自身就够了。
元素宽高不确定时百分比怎么算
如果元素的宽高是 auto(由内容撑开),浏览器会先计算出内容的实际宽高,再拿这个实际值算百分比。所以 translate(-50%, -50%) 在内容不确定时也能正确居中,这正是它比 margin 方案好用的地方。
但是,如果元素没有显式宽高、也没有内容,它的宽高可能是 0,translateX(50%) 就等于移动 0 像素,看起来像没生效。这种情况直接用具体像素值就好。
容易答错的地方
- 混淆
translate和margin的百分比参照 margin-left: 50%是父元素宽度的一半,translateX(50%)是自身宽度的一半。两者移动的距离完全不同。面试里经常拿这个对比来考。- 以为
translateY百分比也相对父元素宽度 translateY(50%)相对的是元素自身的高度,不是宽度也不是父元素的任何尺寸。这和margin-top百分比相对父元素宽度的规则完全不同。
面试官还会怎么问?
用 Flexbox 居中和 translate 居中哪个好?
Flexbox 更简洁,父元素加 display: flex; justify-content: center; align-items: center 就行,而且不需要子元素脱离文档流。translate 方案适合不能用 Flexbox 的场景,或者需要在动画中移动元素时用。
translate 的百分比在 3D 变换里怎么算?
translateZ 不支持百分比,只能用具体的长度值。规范没有定义 Z 轴方向的百分比参照物,所以浏览器不接受 translateZ(50%) 这种写法。
translate 会影响其他元素的布局吗?
不会。translate 和整个 transform 一样,只影响视觉渲染,不改变文档流。元素在布局中还是占据原来的位置,周围的元素不会因为 translate 而重新排列。这也是 translate 动画性能好的原因,浏览器只需要重新合成,不需要重新布局。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。