盒模型 | 奇奇怪怪的auto

在《HTML5与CSS3基础教程》(第8版)P215有这样一句话:

如果不显式设置宽度和高度,浏览器就会使用auto,对于大多数默认显示为块级元素的元素,width的auto值是由包含块的宽度减去元素的内边距、边框和外边距计算出来的,简单地说,包含块的宽度指的是父元素给元素留出的宽度

熟悉盒模型的话这句话特别容易理解,这里不多说了。

问题1: heigth:auto失效问题

问题描述:

举一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<style>
.outer {
height: 200px;
width: 200px;
background-color:pink;
text-align: center;
vertical-align: center;
}

.inner {
background-color: blue;
width:auto;
height: 100;
border: 1px solid red;
padding: 5px;
margin: 10px;
}
</style>
<body>
<div class="outer">
<div class="inner"></div>
</div>
</body>

根据上述定义auto的计算方式,不难计算,内部div的width为168px

但是如果我同步将height设置为auto,原本想的是,height可以按照width:auto一样的计算方式得到结果,但是发现,内部div的height为0!

原因解释:

这里需要注意的是:

在块级元素中,width:auto会自适应撑满父元素宽度,这里的撑满是指撑满剩余部分,是需要经过计算的

在内联元素中,width:auto则呈现包裹性,即元素宽度由子元素的宽度决定

而对于height:auto来说,不论是内联元素还是块级元素,height:auto都是呈包裹性的,即元素的高度由子元素高度决定

总结来说,造成上述问题的原因是要理解,height:auto根据块内内容自动调节高度。

问题2:margin:auto垂直方向失效问题

在《HTML5与CSS3基础教程》(第8版)P21继续提到:

如果手动设置width,但将某个外边距设置为auto,那么这个外边距将进行伸缩以弥补不足的部分

如果手动设置width,并将左右边距设为auto,那么两个外边距就会将设为相等的最大值,实现元素居中

问题描述:

看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<style>
.outer {
height: 200px;
width: 200px;
background-color:pink;
}

.inner {
background-color: blue;
width:100px;
height: 100px;
border: 1px solid red;
padding: 5px;
margin: auto;
}
</style>
<body>
<div class="outer">
<div class="inner">

</div>
</div>
</body>

从图中可以发现,将margin设置为auto后,浏览器自动计算了内部div的margin值以弥补空间

问题是,按照道理来说,margin:auto是将上下左右四个方向都设置为了auto,为什么计算的时候只对左右两个方向有效?上下两个方向无效?

原因解释:

这里我们首先需要理解下面两点:

  1. 理解auto的概念:auto是自动填充剩余空间的意思
  2. 理解块级元素的概念:块级元素在默认情况下会占据整行空间,即使元素宽度不是百分之百占据浏览器,浏览器也会给它留出整行的空间

因此,对于内部div来说,如果设置左右外边距为auto的话,计算方式如下:

1
外部div的width = 左外边距 + 左边框宽度 + 左内边距 + 内部div的width + 右内边距 + 右边框宽度 + 右外边距

但是块级元素的高度是不会自动扩充的,所以它的外部尺寸是不会自动充满父元素的,也没有剩余空间,因此margin上下设置auto不能实现垂直居中

解决办法:通过定位+margin解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<style>
.outer {
height: 200px;
width: 200px;
background-color:pink;
position: relative;
}

.inner {
background-color: blue;
width:100px;
height: 100px;
border: 1px solid red;
padding: 5px;
margin: auto;
position:absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>
<body>
<div class="outer">
<div class="inner">
</div>
</div>
</body>

这里的关键在于:上下左右四个定位全部设置为0,这样就有了多余空间,auto就能平分剩余的空间去实现水平垂直居中

拓展问题:CSS百分比的参照问题

问题描述:

之前在牛客做过这样一道选择题:

当 margin-top、padding-top 的值是百分比时,分别是如何计算的?

A. 相对父级元素的 height,相对自身的 height

B. 相对最近父级块级元素的 height,相对自身的 height

C. 相对父级元素的 width,相对自身的 width

D. 相对最近父级块级元素的 width,相对最近父级块级元素的 width

知识点:

  • 参照父元素宽度的元素:padding margin width text-indent
  • 参照父元素高度的元素:height
  • 参照父元素属性:font-size line-height
  • 特殊情况:相对定位的时候,top bottom left right参照的是父元素的内容区的高度与宽度,而绝对定位参照的是最近定位元素包含padding的高度与宽度

实践出真知:margin padding 参照问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<style>
.outer {
height: 300px;
width: 200px;
background-color:pink;
position: relative;
}

.inner {
background-color: blue;
width:100px;
height: 100px;
position:absolute;
padding-top: 50%;
margin-left: 50%;
}
</style>
<body>
<div class="outer">
<div class="inner">
</div>
</div>
</body>
原因分析:

假如padding-top是按照height来说,父元素的高度会包含子元素的高度,如果子元素的padding-top继续增加,那么父元素的高度也会增加,因为父元素要包含子元素嘛,这样的话,父元素的高度就成为了一个死循环. 还有一种说法,我们都知道padding-left/right和margin-left/right都是按照宽度来说的,当我们不设置具体的上下左右只设置margin或padding时四个值应该保持为一种类型