如何实现一个元素垂直水平居中
确定问题背景
题目中只说实现一个元素垂直水平居中,但是问题来了
此元素的宽高是已知还是未知?
此元素相对于谁居中?
相对于浏览器窗口相对于其父元素垂直水平居中
以上情况不同,所能给出的方案也不同,下面依次进行介绍
此元素宽高已知
相对于浏览器窗口居中
相对于浏览器居中的情况下又有两种情况,一种是首屏居中,使用absolute即可 另一种是一直固定在窗口居中,使用fixed即可。
首屏居中
若是只要求在首屏垂直居中,使用absolute
<head><style>body,p{margin: 0; padding: 0;}div{width: 500px;height: 500px;background: pink;position: absolute;margin: auto;right: 0;left: 0;top: 0;bottom: 0;}p{width: 300px;height: 300px;background: yellow;position: absolute;top: 100px;right: 100px;}</style></head><body><div><p>首屏居中</p></div></body>
关于div的居中也可以使用left+margin-left top+margin-top来解决,代码如下
div{width: 500px;height: 500px;background: pink;position: absolute;left: 50%;top: 50%;margin-left: -250px;margin-top: -250px;}
固定居中
若要针对于窗口水平居中且固定不动,那么就只能使用固定定位fixed,将div的定位改为fixed即可
相对于父元素居中
在宽高已知的情况下,实现子元素相对于父元素水平垂直居中的方法有很多
一,给子元素用margin
父元素500px 子元素300px 经过计算可以轻易得知 给子元素添加margin 100 px即可实现垂直水平居中
<style>body,p{margin: 0; padding: 0;}.box{width: 500px;height: 500px;background: pink;margin: 20px;}p{width: 300px;height: 300px;background: yellow;margin: 100px;}</style></head><body><div class="box"><p>margin实现</p></div></body>
margin-top兼容问题
但是情况和我们预想的有点出入,我们发现p的上边距100px似乎没有生效,看效果图的效果像是给父元素div加了100px的上边距。左右下边距显示正常。
不是我们代码写错了,而是margin-top存在的兼容问题,详细原因可以查看CSS 外边距合并
解决这个问题的办法可以用以下三种:
给子元素或者父元素添加浮动(看布局情况) 给最近的父元素添加上边框(透明最好)给父元素添加overflow:hidden
选择一种解决margin-top兼容即可。
二,给父元素用padding
根据已知宽高计算出父元素的padding值很简单,但是这里要注意的是,在标准盒模型下父元素加padding是要增加父元素所占的空间,在这种情况下就有两种解决方法
方案1
既然padding将父元素的宽高撑开,那么在原本的宽高中减去padding即可,本案例中父元素原本宽高500px,padding100px,因此将宽高都减去100*2即可 即300
<style>body,p{margin: 0; padding: 0;}.box{width: 300px;height: 300px;background: pink;padding: 100px;}p{width: 300px;height: 300px;background: yellow;}</style><body><div class="box"><p>padding实现</p></div></body>
方案2
既然加padding会使得元素撑开额外的距离,使用怪异盒子模型即可解决。 给父元素div加上box-sizing属性即可
.box{box-sizing: border-box;width: 500px;height: 500px;background: pink;padding: 100px;}
三,vertical-align+text-align解决
方案1
我们知道line-height=height可以使得单行文本垂直居中,text-align可以使得文本水平居中 因为p是块级元素,而vertical-align只能作用在行内块元素上,因此我们先将其转为行内快,再进行垂直居中操作。
line-height具有继承性,因此在div中设置的行高500px会继承到p上面,行高>自升高度,会导致p中的文字向下跑,给p再加上行高300px与自身高度相等,即可实现文字在p中的垂直居中(水平居中也会继承与div的text-align属性 不用再额外添加)
<style>body,p{margin: 0; padding: 0;}.box{width: 500px;height: 500px;background: pink;line-height: 500px;text-align: center;}p{width: 300px;height: 300px;background: yellow;display: inline-block;vertical-align: middle;line-height: 300px;}</style>...<body><div class="box"><p>vertical-align+text-align</p></div></body>
方案2
不在父元素中添加line-height属性也可以达到效果,但是要借助新元素来完成。
我们在p标签后面添加一个span标签 html结构如下
<body><div><p>padding实现</p><span>黑中介</span></div></body>
这种办法的思想是我们找一个span 让span和div的高度一致,然后让p相对于span垂直居中,已到达p相对于div垂直居中的目的。当然水平居中依然使用text-align:center
来实现
span是行内元素,是不能设置宽高的,想要设置宽高第一步就是将span转为行内块元素,高度设为百分之百
p是块元素,我们也转为行内块元素已达到p和span同行排列。另外vertical-align也只能作用与行内块元素
代码如下
<style>body,p{margin: 0; padding: 0;}div{width: 500px;height: 500px;background: pink;text-align: center;}p{width: 300px;height: 300px;background: yellow;display: inline-block; /*使p和span在同一行*/vertical-align: middle; /*只给一个不能居中*/}span{display: inline-block;height: 100%;/* 转行内快 设置高 */background: green;vertical-align: middle;}</style></head><body><div><p>padding实现</p><span>黑中介</span></div></body>
这里要注意的是,当只给p设置vertical-align属性以想达到垂直居中的时候,p和我们预想的不一样,p没有动,动的反而是span标签。这时给span也同时设置vertical-align属性即可解决问题。
此时页面呈现如下
我们将span背景色去掉 内容去掉让其视觉消失,即可实现垂直水平居中效果
四,定位方法实现
1.父子都是相对定位
代码没什么好说的,如下
<style>body,p{margin: 0; padding: 0;}div{width: 500px;height: 500px;margin: 40px;background: pink;position: relative;}p{width: 300px;height: 300px;background: yellow;position: relative;top: 100px;left: 100px; /*margin: 0 auto;实现水平的居中也可以*/}</style></head><body><div><p>父子相对定位</p></div></body>
p元素同时也可以使用百分比写法,再加上外边距的负偏移量即可
但是有margin-top的兼容性问题还是会导致父元素div的margin-left发生偏移而不是p,因此我们上面解决margin兼容问题的三种办法之一,给父元素添加overflow:hidden即可实现预期效果。
2.父相对子绝对
我们把上面的两种父子都相对的写法改一下,子元素p的定位都改成absolute绝对定位,发现也都可以。
并且第二种使用外边距偏移回去的情况下,margin-top的兼容问题并没有出现(在父元素不添加overflow:hidden的情况下) 原因是因为子元素的定位设置为绝对定位,触发BFC机制,导致p元素独立形成一个BFC,所以问题自己就解决了。
在父相子绝的情况下,想要子元素水平垂直快速居中,可以使用margin: auto; left: 0; top: 0; bottom: 0; right: 0;
的办法
<style>body,p{margin: 0; padding: 0;}div{width: 500px;height: 500px;margin: 40px;background: pink;position: relative;}p{width: 300px;height: 300px;background: yellow;position: absolute;margin: auto;left: 0;top: 0;bottom: 0;right: 0;}</style></head><body><div><p>父相对子绝对3</p></div></body>
此元素的宽高未知
一,vertical-align
方案1
对于上面margin和padding相关的需要用已知宽高来调整位置的方法显然是不可用的。那我们试试vertical-align的方法可不可以
<style>body,p{margin: 0; padding: 0;}div{width: 500px;height: 500px;background: pink;line-height: 500px;text-align: center;}p{background: yellow;display: inline-block;vertical-align: middle;}</style></head><body><div><p>子元素宽高未知</p></div></body>
效果如下:
我们可以看到由于子元素宽高未知,导致撑满整个高度,但是也算勉强实现了题目要求,但是仔细会发现在这种情况下也会出现一像素的偏差。所以这种方法仅做了解即可
方案2
前面介绍vertical-align+text-align的时候介绍了第二种“黑中介”的方案,试一下在宽高未知的情况下表现如何
<style>body,p{margin: 0; padding: 0;}div{width: 500px;height: 500px;background: pink;text-align: center;}p{background: yellow;display: inline-block;vertical-align: middle;}span{display: inline-block;height: 100%;vertical-align: middle;}</style></head><body><div><p>子元素宽高未知</p><span></span></div></body>
效果如下,可以看到达到预期效果
二,定位+transform
在宽高未知的情况下使用定位的方法来实现预期效果可以使用transform
属性来解决,最主要的原因是因为transform
属性的偏倚量是相对于自身的。
<style>body,p{margin: 0; padding: 0;}div{width: 500px;height: 500px;background: pink;position: relative;}p{position: absolute;background: yellow;left: 50%;top:50%;transform: translate(-50%,-50%);}</style>...<body><div><p>子元素宽高未知</p></div></body>
三,弹性盒子实现
方案1
<style>body,p{margin: 0; padding: 0;}div{width: 500px;height: 500px;background: pink;display: flex;}p{margin: auto;background: yellow;}</style></head><body><div><p>子元素宽高未知</p></div></body>
方案2
<style>body,p{margin: 0; padding: 0;}div{width: 500px;height: 500px;background: pink;display: flex;justify-content: center;align-items: center;}p{background: yellow;}</style></head><body><div><p>子元素宽高未知</p></div></body>
可以看到 在已知和未知宽高都可以达到效果的是
vertical-align中介法弹性盒模型的两种方案