整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Web前端:CSS 轻松搞定标签(元素)居中问题

者:蔷薇Nina

原文:https://www.cnblogs.com/wcwnina/p/11297630.html

在CSS里,标签位置居中一直是困扰Web前端的难题。在本文中,我对这类问题进行了探究和给出了几点建议,供读者参考。

1 行内标签

1.1 水平居中

在父级标签中使用 text-align: center

效果:

1.2 垂直居中

如果是单行,则为该标签设置行高line-height)且与其父级标签 height 相等即可。

效果:

如果是多行,稍微有点麻烦,需要在该标签设置 display: table-cell vertical-align: middle,在其父级标签设置 display: table

效果:

2 块标签

2.1 水平居中

方法一:在父级标签中使用 flex 弹性盒子。

效果:

方法二:在该标签中使用 margin 属性。

效果:

2.2 垂直居中

在父级标签中使用 flex 弹性盒子。

效果:

总结:对于行内标签居中,优先考虑文本对齐(text-align)和显示单元格(table-cell);对于块标签居中,优先考虑显示弹性盒子(flex)。

者|颜海镜

编辑|覃云

出处丨前端之巅

本文已获作者授权,转载来源:

https://segmentfault.com/a/1190000016389031

划重点,这是一道面试必考题,很多面试官都喜欢问这个问题,我就被问过好几次了。



要实现上图的效果看似很简单,实则暗藏玄机,本文总结了一下 CSS 实现水平垂直居中的方式大概有下面这些,本文将逐一介绍一下,我将本文整理成了一个 github 仓库在:https://github.com/yanhaijing/vertical-center

欢迎大家 star。

仅居中元素定宽高适用:

  • absolute + 负 margin
  • absolute + margin auto
  • absolute + calc

居中元素不定宽高:

  • absolute + transform
  • lineheight
  • writing-mode
  • table
  • css-table
  • flex
  • grid

1.absolute + 负 margin

为了实现上面的效果先来做些准备工作,假设 HTML 代码如下,总共两个元素,父元素和子元素:

<div class="wp">
 <div class="box size">123123</div>
</div>

wp 是父元素的类名,box 是子元素的类名,因为有定宽和不定宽的区别,size 用来表示指定宽度,下面是所有效果都要用到的公共代码,主要是设置颜色和宽高。

注意:后面不在重复这段公共代码,只会给出相应提示。

/* 公共代码 */
.wp {
 border: 1px solid red;
 width: 300px;
 height: 300px;
}
.box {
 background: green; 
}
.box.size{
 width: 100px;
 height: 100px;
}
/* 公共代码 */

绝对定位的百分比是相对于父元素的宽高,通过这个特性可以让子元素的居中显示,但绝对定位是基于子元素的左上角,期望的效果是子元素的中心居中显示。

为了修正这个问题,可以借助外边距的负值,负的外边距可以让元素向相反方向定位,通过指定子元素的外边距为子元素宽度一半的负值,就可以让子元素居中了,css 代码如下。

/* 此处引用上面的公共代码 */
/* 此处引用上面的公共代码 */
/* 定位代码 */
.wp {
 position: relative;
}
.box {
 position: absolute;;
 top: 50%;
 left: 50%;
 margin-left: -50px;
 margin-top: -50px;
}

这是我比较常用的方式,这种方式比较好理解,兼容性也很好,缺点是需要知道子元素的宽高。

点击查看完整 DEMO:

http://yanhaijing.com/vertical-center/absolute1.html

2.absolute + margin auto

这种方式也要求居中元素的宽高必须固定,HTML 代码如下:

<div class="wp">
 <div class="box size">123123</div>
</div>

这种方式通过设置各个方向的距离都是 0,此时再讲 margin 设为 auto,就可以在各个方向上居中了。

/* 此处引用上面的公共代码 */
/* 此处引用上面的公共代码 */
/* 定位代码 */
.wp {
 position: relative;
}
.box {
 position: absolute;;
 top: 0;
 left: 0;
 right: 0;
 bottom: 0;
 margin: auto;
}

这种方法兼容性也很好,缺点是需要知道子元素的宽高。

点击查看完整 DEMO:

http://yanhaijing.com/vertical-center/absolute2.html

3.absolute + calc

这种方式也要求居中元素的宽高必须固定,所以我们为 box 增加 size 类,HTML 代码如下:

<div class="wp">
 <div class="box size">123123</div>
</div>

感谢 css3 带来了计算属性,既然 top 的百分比是基于元素的左上角,那么在减去宽度的一半就好了,代码如下

/* 此处引用上面的公共代码 */
/* 此处引用上面的公共代码 */
/* 定位代码 */
.wp {
 position: relative;
}
.box {
 position: absolute;;
 top: calc(50% - 50px);
 left: calc(50% - 50px);
}

这种方法兼容性依赖 calc 的兼容性,缺点是需要知道子元素的宽高。

点击查看完整 DEMO:

http://yanhaijing.com/vertical-center/absolute3.html

4.absolute + transform

还是绝对定位,但这个方法不需要子元素固定宽高,所以不再需要 size 类了,HTML 代码如下:

<div class="wp">
 <div class="box">123123</div>
</div>

修复绝对定位的问题,还可以使用 css3 新增的 transform,transform 的 translate 属性也可以设置百分比,其是相对于自身的宽和高,所以可以讲 translate 设置为 -50%,就可以做到居中了,代码如下:

/* 此处引用上面的公共代码 */
/* 此处引用上面的公共代码 */
/* 定位代码 */
.wp {
 position: relative;
}
.box {
 position: absolute;
 top: 50%;
 left: 50%;
 transform: translate(-50%, -50%);
}

这种方法兼容性依赖 translate2d 的兼容性。

点击查看完整 DEMO:

http://yanhaijing.com/vertical-center/absolute4.html

5.lineheight

利用行内元素居中属性也可以做到水平垂直居中,HTML 代码如下:

<div class="wp">
 <div class="box">123123</div>
</div>

把 box 设置为行内元素,通过 text-align 就可以做到水平居中,但很多同学可能不知道通过通过 vertical-align 也可以在垂直方向做到居中,代码如下:

/* 此处引用上面的公共代码 */
/* 此处引用上面的公共代码 */
/* 定位代码 */
.wp {
 line-height: 300px;
 text-align: center;
 font-size: 0px;
}
.box {
 font-size: 16px;
 display: inline-block;
 vertical-align: middle;
 line-height: initial;
 text-align: left; /* 修正文字 */
}

这种方法需要在子元素中将文字显示重置为想要的效果。

点击查看完整 DEMO:

http://yanhaijing.com/vertical-center/lineheight.html

6.writing-mode

很多同学一定和我一样不知道 writing-mode 属性,感谢 @张鑫旭老师的反馈,简单来说 writing-mode 可以改变文字的显示方向,比如可以通过 writing-mode 让文字的显示变为垂直方向。

<div class="div1">水平方向</div>
<div class="div2">垂直方向</div>
.div2 {
 writing-mode: vertical-lr;
}

显示效果如下:

水平方向
垂
直
方
向

更神奇的是所有水平方向上的 css 属性,都会变为垂直方向上的属性,比如 text-align,通过 writing-mode 和 text-align 就可以做到水平和垂直方向的居中了,只不过要稍微麻烦一点:

<div class="wp">
 <div class="wp-inner">
 <div class="box">123123</div>
 </div>
</div>
/* 此处引用上面的公共代码 */
/* 此处引用上面的公共代码 */
/* 定位代码 */
.wp {
 writing-mode: vertical-lr;
 text-align: center;
}
.wp-inner {
 writing-mode: horizontal-tb;
 display: inline-block;
 text-align: center;
 width: 100%;
}
.box {
 display: inline-block;
 margin: auto;
 text-align: left;
}

这种方法实现起来和理解起来都稍微有些复杂。

点击查看完整 DEMO:

http://yanhaijing.com/vertical-center/writing-mode.html

7.table

曾经 table 被用来做页面布局,现在没人这么做了,但 table 也能够实现水平垂直居中,但是会增加很多冗余代码:

<table>
 <tbody>
 <tr>
 <td class="wp">
 <div class="box">123123</div>
 </td>
 </tr>
 </tbody>
</table>

tabel 单元格中的内容天然就是垂直居中的,只要添加一个水平居中属性就好了。

.wp {
 text-align: center;
}
.box {
 display: inline-block;
}

这种方法就是代码太冗余,而且也不是 table 的正确用法。

点击查看完整 DEMO:

http://yanhaijing.com/vertical-center/table.html

8.css-table

css 新增的 table 属性,可以让我们把普通元素,变为 table 元素的现实效果,通过这个特性也可以实现水平垂直居中。

<div class="wp">
 <div class="box">123123</div>
</div>

下面通过 css 属性,可以让 div 显示的和 table 一样:

.wp {
 display: table-cell;
 text-align: center;
 vertical-align: middle;
}
.box {
 display: inline-block;
}

这种方法和 table 一样的原理,但却没有那么多冗余代码,兼容性也还不错。

点击查看完整 DEMO:

http://yanhaijing.com/vertical-center/css-table.html

9.flex

flex 作为现代的布局方案,颠覆了过去的经验,只需几行代码就可以优雅的做到水平垂直居中。

<div class="wp">
 <div class="box">123123</div>
</div>
.wp {
 display: flex;
 justify-content: center;
 align-items: center;
}

目前在移动端已经完全可以使用 flex 了,PC 端需要看自己业务的兼容性情况。

点击查看完整 DEMO:

http://yanhaijing.com/vertical-center/flex.html

10.grid

感谢 @一丝姐 反馈的这个方案,css 新出的网格布局,由于兼容性不太好,一直没太关注,通过 grid 也可以实现水平垂直居中。

<div class="wp">
 <div class="box">123123</div>
</div>
.wp {
 display: grid;
}
.box {
 align-self: center;
 justify-self: center;
}

代码量也很少,但兼容性不如 flex,不推荐使用。

点击查看完整 DEMO:

http://yanhaijing.com/vertical-center/grid.html

总结

下面对比下各个方式的优缺点,肯定又双叒叕该有同学说回字的写法了,简单总结下:

  • PC 端有兼容性要求,宽高固定,推荐 absolute + 负 margin
  • PC 端有兼容要求,宽高不固定,推荐 css-table
  • PC 端无兼容性要求,推荐 flex
  • 移动端推荐使用 flex

小贴士:关于 flex 的兼容性决方案,请看这里:

https://yanhaijing.com/css/2016/08/21/flex-practice-on-mobile/


最近发现很多同学都对 css 不够重视,这其实是不正确的,比如下面的这么简单的问题都有那么多同学不会,我也是很无语:

<div class="red blue">123</div>
<div class="blue red">123</div>
.red {
 color: red
}
.blue {
 color: blue
}

问两个 div 的颜色分别是什么,竟然只有 40% 的同学能够答对,这 40% 中还有很多同学不知道为什么,希望这些同学好好补习下 CSS 基础。

素分类

在讲解CSS布局之前,我们需要提前知道一些知识,在CSS中,html中的标签元素大体被分为三种不同的类型:

块状元素、内联元素(又叫行内元素)和内联块状元素。

常用的内联元素有:

<a>、<span>、<br/>、<sub>、<sup>、<label>、<b>、<i>、<u>、<del>

常用的块状元素有:

<div>、<p>、<h1>...<h6>、<ol>、<ul>、<li>、<dl>、<dt>、<dl>、<table>、<marquee>、<form>、<pre>

常用的内联块状元素(又叫行内块元素)有:

<img>、<input>

内联元素(行内)

在html中,<span>、<a>、<label>、<input>、 <img>、 <strong> 和<em>就是典型的内联元素(行内元素)(inline)元素。

当然块状元素也可以通过代码display:inline将元素设置为内联元素。如下代码就是将块状元素div转换为内联元素,从页使用div元素具有内联元素特点。

div{display:inline}

内联元素(行内)特点:

1、和其他元素都在一行上;

2、元素的高度、宽度、行高及顶部和底部边距不可设置;(padding可以设置)

3、元素的宽度就是它包含的文字或图片的宽度,不可改变。

块级元素

什么是块级元素?在html中<div>、<p>、<h1>、<form>、<ul> 和 <li>就是块级元素。

设置display:block就是将元素显示为块级元素。如下代码就是将内联元素a转换为块状元素,从而使a元素具有块状元素特点。

a{display:block;}

块级元素特点:

1、每个块级元素都从新的一行开始,并且其后的元素也另起一行。(真霸道,一个块级元素独占一行)

2、元素的高度、宽度、行高以及顶和底边距都可设置。

3、元素宽度在不设置的情况下,是它本身父容器的100%(和父元素的宽度一致),除非设定一个宽度。

内联块状元素(行内块)

内联块状元素(inline-block)就是同时具备内联元素、块状元素的特点,

代码display:inline-block就是将元素设置为内联块状元素。(css2.1新增),<img>、<input>标签就是这种内联块状标签。

inline-block元素特点:

1、和其他元素都在一行上;

2、元素的高度、宽度、行高以及顶和底边距都可设置。

提示:下一小节是用视频动画来讲解css中的盒模型。

块元素尽量采用div嵌套, 行内元素尽量采用span嵌套

显示模式的转换

块级、行内 、行内块元素三者是可以相互转换的。

display 显示 的意思

block 块

inline 行内


块级 → 行内元素 display: inline;

<style>
div{
    width:100px;
    height:100px;
    background-color:#036;
    display:inline;
}
</style>

行内元素 → 块级元素 display: block;

<style>
a{
    width:100px;
    height:100px;
    background-color:#960;
    display:block
}
</style>

行内和块级 → 行内块 display:inline-block;

span{
    width:100px;
    height:100px;
    background-color:#960;
    didplay:inline-block;
}

水平居中设置-行内元素

如果被设置元素为文本、图片等行内元素时,水平居中是通过给父元素设置text-align:center来实现的。如下代码:

html代码:

<body>
<div class="txtCenter">我是文本,哈哈,我想要在父容器中水平居中显示。</div>
<div class="imgCenter"><img src="http://img.mukewang.com/52da54ed0001ecfa04120172.jpg" /></div>
</body>

css代码:

<style>
div.txtCenter{
text-align:center;
}
div.imgCenter{
text-align:center;
}
</style>

水平居中设置-定宽块状元素

当被设置元素为块状元素时用text-align:center就不起作用了,这时也分两种情况:定宽块状元素和不定宽块状元素。

满足定宽和块状两个条件的元素是可以通过设置"左右margin"值为"auto"来实现居中的。我们来看个例子就是设置div这个块状元素水平居中:

第一种方法

html代码:

<body>
<div>我是定宽块状元素,哈哈,我要水平居中显示。</div>
</body>

css代码:

<style>
div{
border:1px solid red;/*为了显示居中效果明显为 div 设置了边框*/
width:500px;/*定宽*/
margin:20px auto;/* margin-left 与 margin-right 设置为 auto */
}
</style>

也可以写成:

margin-left:auto;
margin-right:auto;

注意:元素的"上下margin"是可以随意设置的。这种水平居中的方法两个2个条件缺一不可

第二种方法

html代码:

<body>
<div>我是定宽块状元素,哈哈,我要水平居中显示。</div>
</body>

css代码:

<style>
div{
border:1px solid red;/*为了显示居中效果明显为 div 设置了边框*/
width:500px;/*定宽*/
position:absoute;
left:50px;
margin-left:-25px;
}
</style>

水平居中设置-不定宽块状元素

在实际工作中我们会遇到需要为"不定宽度的块状元素"设置居中,比如网页上的分页导航,因为分页的数量是不确定的,所以我们不能通过设置宽度来限制它的弹性。

不定宽度的块状元素有三种方法居中(这三种方法目前使用的都比多):

加入table标签

设置display;inline方法

设置position:relative和left:50%;

(1)第一种方法:

第一步:为需要设置的居中的元素外面加入一个table标签(包括<tbody>、<tr>、<td>)。

第二步:为这个table设置"左右margin auto"(这个和定宽块状元素的方法一样)。举例如下:

html代码:

<div>
<table>
<tbody>
<tr><td>
<ul>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
</ul>
</td></tr>
</tbody>
</table>
</div>

css代码:

<style>
table{
margin:0 auto;
}
ul{list-style:none;margin:0;padding:0;}
li{float:left;display:inline;margin-right:8px;}
</style>

(2)第二种方法:

改变块级元素的dispaly为inline类型,然后使用text-align:center来实现居中效果。如下例子:

html代码:

<body>
<div class="container">
<ul>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
</ul>
</div>
</body>

css代码:

<style>
.container{
text-align:center;
}
.container ul{
list-style:none;
margin:0;
padding:0;
display:inline;
}
.container li{
margin-right:8px;
display:inline;
}
</style>

这种方法相比第一种方法的优势是不用增加无语义标签,简化了标签的嵌套深度,

但也存在着一些问题:它将块状元素的display类型改为inline,变成了行内元素,所以少了一些功能,比如设定长度值。

(2)第三种方法:

通过给父元素设置float,然后给父元素设置position:relative和left:50%,子元素设置position:relative和left:-50%来实现水平居中

代码如下:

<body>
<div class="container">
<ul>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
</ul>
</div>
</body>

css代码:

<style>
.container{
float:left;
position:relative;
left:50%
}
.container ul{
list-style:none;
margin:0;
padding:0;
position:relative;
left:-50%;
}
.container li{float:left;display:inline;margin-right:8px;}
</style>

这种方法可以保留块状元素仍以display:block的形式显示,优点不添加无语议表标签,不增加嵌套深度,

但它的缺点是设置了position:relative,带来了一定的副作用。

这三种方法使用得都非常广泛,各有优缺点,具体选用哪种方法,可以视具体情况而定。

隐性改变display类型

有一个有趣的现象就是当为元素(不论之前是什么类型元素,display:none除外)设置以下2个句之一:

position:absolute

float:left或float:right

元素会自动变为以display:inline-block的方式显示,当然就可以设置元素的width和height了且默认宽度不占满父元素。

如下面的代码,小伙伴们都知道a标签是行内元素,所以设置它的width是没有效果的,但是设置为position:absolute以后,就可以了。

<div class="container">
<a href="#" title="">进入课程请单击这里</a>
</div>

css代码

<style>
.container a{
position:absolute;
width:200px;
background:#ccc;
}
</style>

如何让一段文字水平居中且垂直居中

<div>水平垂直居中</div>
div{
width:200px;height:200px; /*设置div的大小*/
border:1px solid green; /*边框*/
text-align: center; /*文字水平居中对齐*/
line-height: 200px; /*设置文字行距等于div的高度*/
overflow:hidden;
}

text-align 和margin auto 区别

text-align 可以让块级元素里面的文字内容居中对齐.

文字内容 == (图片 input 行内元素 行内块元素)

但是对于里面的块级元素无效

让一个块级元素居中对齐 : margin:0 auto;

【实例】

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>赵丽颖的图片</title>
<style type="text/css">
body{
text-align:center; /* 所有的元素居中 */
}
div{ /*块元素的居中方法*/
width:600px;
margin:30px auto;
}
.img1{ /*行内块元素的居中方法 */
display:block;
width:600px;
margin:30px auto;
}
.img2{ /*行内块元素的居中方法 */
position:relative;
left:50%;
margin-left:-300px;
}
.form1 input{
width:200px; /*块容器包裹下的行内块元素居中方法*/
margin:10px auto;
}
.img3{ /*块容器包裹下的行内块元素居中方法*/
text-align:center;
}
</style>
</head>
<body>
<div><img src="../../photo/赵丽颖.jpeg" /></div>
<img class="img1" src="../../photo/赵丽颖.jpeg" />
<img class="img2" src="../../photo/赵丽颖.jpeg" />
<div class="form1">
<form action="" method="get" accept-charset="utf-8">
<label>电子邮箱: <input type="text" name="email" value="" placeholder="请输入电子邮箱"/></label><br/>
<label>密码: <input type="password" name="password"/></label><br/>
<label for="address">地址</label>
<input type="text" name="address" id="address" placeholder="请输入地址" />
</form>
</div>

<div class="img3">
<img src="../../photo/赵丽颖.jpeg" />
</div>

</body>
</html>

CSS布局水平居中实战

方法一:margin + width

<!Doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title>css布局水平居中margin + width</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.box {
width: 100px;
margin: 0 auto;
background: red;
}
</style>
</head>
<body>
<div class="box">Demo</div>
</body>
</html>

说明:这个水平居中方法, 我们最熟悉了, 也是最常用的, width可以固定px也可以使用百分比

方法二:table + margin

<!Doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title>css布局水平居中table + margin</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.box {
display: table;
margin: 0 auto;
background: red;
}
</style>
</head>
<body>
<div class="box">Demo</div>
</body>
</html>

说明:display: table在表现上类似block元素,但是宽度为内容宽。无需设置父元素样式 (支持 IE 8 及其以上版本) 兼容 IE 8 一下版本需要调整为<table>

方法三:inline-block + text-align

<!Doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title>css布局水平居中inline-block + text-align</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.content {
text-align: center;
}
.box {
display: inline-block;
background: red;
}
</style>
</head>
<body>
<div class="content">
<div class="box">Demo</div>
</div>
</body>
</html>

说明:兼容性佳(甚至可以兼容 IE 6 和 IE 7)

方法四:absolute + margin-left

<!Doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title>css布局水平居中absolute + margin-left</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.content {
position: relative;
}
.box {
position: absolute;
left: 50%;
width: 100px;
margin-left: -50px;
background: red;
}
</style>
</head>
<body>
<div class="content">
<div class="box">Demo</div>
</div>
</body>
</html>

说明:宽度固定相比于使用transform, 有兼容性更好

方法五:absolute + transform

<!Doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title>css布局水平居中absolute + transform</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.content {
position: relative;
}
.box {
position: absolute;
left: 50%;
transform: translateX(-50%);
background: red;
}
</style>
</head>
<body>
<div class="content">
<div class="box">Demo</div>
</div>
</body>
</html>

说明:绝对定位脱离文档流, 不会对后续元素的布局造成影响。transform为 CSS3 属性, 有兼容性问题

方法六:flex + justify-content