css居中

居中包括水平居中和垂直居中。

水平居中

水平居中没有什么好说的,比较简单,兼容性也没什么问题。

block 元素我们通常用 margin:0 auto 实现水平居中,而 inline(包括inline-block) 元素一般通过设置其父元素的 text-align:center

垂直居中

垂直居中则比较复杂,居中的难度主要在这里。但是我们要抓住本质,就不难理解这些所谓的奇技淫巧。

我们可以用数字来描述垂直居中:父元素的高度是 H,子元素的高度是 h,当父元素的上边界与子元素的上边界的距离为 (H-h)/2 时则实现了垂直居中。

所以无论我们用了什么手段,最终都是要实现这个目标。

按照难度我做了如下的划分(由于文字垂直居中比较弱智,并且可以用块级元素的某些方式实现,这里不再单独讨论):

1.简单方式实现垂直居中

html元素在浏览器中的布局由一系列的规则决定,最基础的盒模型描述了元素的四个布局要素:margin box,border box,padding box,content box,这四个盒基本可以设定元素的位置,布局排版就是控制不同元素的位置和层次。

根据盒子的定义,对于以下情况可以直接用margin/border/padding完成居中:

a.父容器大小由内部元素决定(撑开),并且对于居中时父元素border与子元素border的距离没有什么硬性要求。

缺点:父元素的大小不能被设定。

例子如下:

 1 <style type="text/css">
 2     .father{
 3         padding: 10% 0;
 4         border: 1px solid;
 5     }
 6     .child{
 7         height: 50px;
 8         width: 100px;
 9         background: #ddd;
10         margin: 0 auto;
11     }
12 </style>
13 <div class="father">
14     <div class="child"></div>
15 </div>

 

b.子元素大小固定

这种情况下,经常使用的方法是定位:

对子元素relative定位,top、left各50%,这个时候如果父元素以中心分成四个象限,那么此时子元素在第四象限,左上角顶着父元素的花心。而我们又知道子元素的宽高,只要用负margin各拉回元素宽高的一半,两颗心就对齐了,完成了居中。

这里无论如何也避不开子元素大小不固定这个条件了,垂直居中的各种淫技基本为了搞定它。我们进入下一个标题:

2.复杂方式的垂直居中

a.使用vertical-align

凭直觉我们会想到这个属性,但是理解这个属性有点复杂,建议深入了解。

vertical-align用来设置行内元素在其所处行框中的垂直对齐方式,行框中从上到下主要的对齐线依次是顶线、中线、基线、底线,默认情况下vertical-align的值是基线。这些对齐线的间距又由行高决定,我们看w3c中一段有在行高的描述:

A line box is always tall enough for all of the boxes it contains. However, it may be taller than the tallest box it contains (if, for example, boxes are aligned so that baselines line up). When the height of a box B is less than the height of the line box containing it, the vertical alignment of B within the line box is determined by the 'vertical-align' property. When several inline-level boxes cannot fit horizontally within a single line box, they are distributed among two or more vertically-stacked line boxes. Thus, a paragraph is a vertical stack of line boxes. Line boxes are stacked with no vertical separation (except as specified elsewhere) and they never overlap.

行高大于等于行内最高的行内盒高度,当行内盒子B的高度小于其存在的行框的高度时,B在行内垂直的对齐方式由“vertiacl-align”决定。

ok.到这里,背景知识已经搞定了。我们来看操作:

对于本小节前面提到的场景,我们把子元素B设置成inline-block,这个内联元素会导致生成一个行框X,X只包含这一个内联元素B,此时它的行高与内部元素高度一致——根据规则,这时vertical-align不起作用,我们有什么办法能把这个行框的高度设成B要相对居中的元素的高度呢?

我们可以做一个宽度为0的高度100%的inline-block元素B2放在X中,X就会被撑开,因为X是匿名的,我们做的B2百分比计算高度时参照对象仍是dom上的父节点。这时我们设置B和B2的vertical-align都为middle就能实现居中了。为什么都要设置为middle,可以参考上面那段英文来思考——行框在什么情况下高度会大于内部最高行盒的高度。

b.使用margin:auto 

还是凭直觉,为什么 margin:0 auto 可以实现水平居中,margin:auto 0 不能实现垂直居中,甚至更省事 margin:auto 怎么不能实现居中?

我评判一个系统设计好坏的重要标准是:在类似的场景下应当有一致的,至少是抽象一致的处理方式。当年我第一次接触到这个命题的时候足足花了两个小时来研究,我觉得用这种方式应该可以实现居中。我思考的过程是这样的,

  • 块级元素在普通流中会自动继承宽度,但不会继承高度,margin:0 auto肯定和这个有关。
  • 进而发现了书写模式这个尚未成为标准的属性:-webkit-writing-mode(下节有对其的说明)。
  • w3c-org中的一段定义:(对于 absolutely positioned 的元素) 'top' + 'margin-top' + 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' + 'margin-bottom' + 'bottom' = height of containing block

第三点是从 这位同学的博客上 发现的,我正好读到规范的第九章,这个博客的总结很到位,我过往对垂直居中的研究基本全覆盖了。

根据第三点,我们让子元素的top和bottom都为0,height of containing block - ( 'border-top-width' + 'padding-top' + 'height' + 'padding-bottom' + 'border-bottom-width' ) = 'margin-top' + 'margin-bottom',此时设置 margin:auto 0 则能实现垂直居中,例子如下:

<style type="text/css">
.c{
    position: relative;
    border: 1px solid;
    height: 100px;
    width: 100px;
}
.mid{
    width: 50px;
    height: 20px;
    background: #ddd;
    position: absolute;
    margin: auto 0;
    top:0;
    bottom: 0;
}
</style>
<div class="c">
    <div class="mid"></div>
</div>

 

ps:这个兼容性不好,IE8+支持,chrome和firfox支持良好。

x.一点延伸:-webkit-writing-mode

请看下面的例子:

看第一个例子,我们使用-webkit-writing-mode来切换元素的排版规则,让容器内部的div原本在水平方向上展开能力丧失,替换为垂直方向上的展开能力,这样{margin:auto 0px;}就具有了垂直居中的功能。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章