有没有遇到过这种情况,想把一个绝对定位的元素摆到正中间,结果翻来覆去还是那套老代码,top、left各50%,再translate拽回来一半。虽然这招管用了几十年,但每次写总感觉少了点丝滑感。最近发现CSS里藏了个新玩法,不用算来算去,三行代码就能让绝对定位的元素稳稳站中间,而且全浏览器都买账。
啥是place-self
place-self其实就是align-self和justify-self这俩兄弟的合体版,在一个声明里同时搞定垂直和水平方向的对齐。原本这哥几个是给网格布局或者弹性盒子里的子元素准备的,用来指定它们在各自格子里的站位。现在这俩属性也能用在绝对定位元素上了,但有个小机关,不能直接拿来就用。
老办法咋写
想当年为了让绝对定位元素居中,代码都是这么写的:
.old-school {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}先把元素的左上角怼到父容器正中间,再用位移把自己往回拉一半的宽高,这样整个元素才真正居中。这法子没毛病,就是每次都要手动算偏移量,要是元素尺寸变了还得跟着改,不够智能。
新招式咋玩
新版方案更贴近直觉,直接把想居中的想法写进代码里:
.modern-way {
position: absolute;
place-self: center;
inset: 0;
}place-self: center告诉浏览器“我要在可用空间里居中”,而inset: 0则是把top、right、bottom、left全部归零。这里有个关键点,inset属性不光是在固定元素的边距,它实际上是在重新定义所谓的“inset-modified containing block”(简称IMCB)。默认情况下绝对定位元素的IMCB和它自己的尺寸一样大,这时候让它在里面居中,等于是自己跟自己玩,根本动不了。一旦通过inset把四条边都拉到容器的边缘,IMCB就被撑开了,这时候place-self: center才有了真正的参照物,元素就能在父容器里准确居中。
容器有内边距咋整
如果父容器本身有padding,绝对定位元素居中的位置可能会显得不太对。想留出空隙有两种路子,一种是给绝对定位元素本身加margin,比如margin: 20px,它会在居中位置的基础上再往外扩一圈。另一种更直接,改inset的值,写成inset: 20px,相当于把IMCB的边界往里收了一圈,元素自然就跟容器边缘拉开了距离。
.with-spacing {
position: absolute;
place-self: center;
inset: 20px; /* 四边都留20像素空隙 */
}角落定位也行
既然能居中,那想贴边自然也不在话下。place-self支持start、end这些关键词,配合inset的调整,可以快速实现各种角落定位。
.stick-to-top-left {
position: absolute;
place-self: start start; /* 第一个start是垂直,第二个是水平 */
inset: 0;
}
.stick-to-bottom-right {
position: absolute;
place-self: end end;
inset: 0;
}要是只想贴某一边,inset也能单独指定。比如想让元素靠右但上下居中,可以这样:
.align-right-middle {
position: absolute;
place-self: center end;
inset: 0;
}另一种实现思路
虽然place-self加inset的三行代码足够简洁,但偶尔碰到老项目或者需要更精细控制的情况,还有一种备选方案,就是用margin: auto配合inset来实现居中,这招也支持所有浏览器。
.alternative-way {
position: absolute;
inset: 0;
margin: auto;
}这里margin: auto会根据inset定义出的空间自动分配外边距,让元素在四个方向上受力均衡,自然就居中了。而且这种方法在需要给元素指定固定宽高的时候特别好用,比如想让一个200×200的方块在父容器里居中,这俩搭配起来非常稳。
.fixed-size-box {
position: absolute;
inset: 0;
width: 200px;
height: 200px;
margin: auto;
}