CSS盒模型
1. 盒模型
1.1 盒模型及宽高属性
HTML中的元素都可以看做一个盒子,每个盒子都由以下四个部分组成:
Content(内容):盒子的内容,显示文本或图像等
Padding(内边距):清除内容周围的区域
Border(边框): 围绕在内边距和内容外的边框
Margin(外边距): 清除边框外的区域
当设置盒子的宽(width)高(height)属性时,实际上设置的是盒子内容部分(即Content的宽高)
以div元素为例,给div元素的四个部分设置了以上属性以后,其构造如下
div {
width: 50px;
height: 50px;
padding: 10px;
border: 5px solid red;
margin: 10px;
}
而整个div元素的实际的大小为80px * 80px,可见盒子的实际宽高 = width/height(50) + padding(10 * 2) + border(5 * 2)。margin属性为元素外的空白区域,仍占用相应的宽度,但不计入元素内
盒子的宽高计算如下:
盒子的宽度 = width + padding-left + padding-right + border-left + border-right
盒子的高度 = height + padding-top + padding-bottom + border-top + border-bottom
1.2 通用属性规则
- 设置内外边距margin、padding及其单边属性时(如margin-left),遵循以下规则:(以margin为例)
div {
/*四个属性分别为上、右、下、左,即顺时针方向*/
margin: 10px 20px 30px 40px;
/*四个方向设置相同宽度*/
margin: 10px;
/*两个宽度分别代表上下、左右*/
margin: 10px 20px;
/*三个宽度分别代表上、左右、下*/
margin: 10px 20px 30px;
}
- 设置 background-* 属性(如background-color)时,实际覆盖到的部分为 content 和 padding
div {
/*设置黑色border*/
border: 3px solid black;
height: 50px;
width: 50px;
/*设置内边距为20px,背景颜色为红色*/
padding: 20px;
background-color: red;
}
实际效果如下,可见 background-color 覆盖到了border内的全部区域,即 content 和 padding
2. 行内、块级元素
2.1 标准文档流
标准文档流即 html 页面不使用特殊规则时(如浮动、定位等),元素排版布局遵循从上到下,从左至右的流式排列规则。以下均以标准文档流的形式进行讨论。
2.2 块级元素、行内元素和行内块元素
块级元素 | 行内元素 | 行内块元素 |
---|---|---|
block | inline | inline-block |
独立成行 | 不独立成行 | 不独立成行 |
可以设置宽高 | 不可以设置宽高 | 可以设置宽高 |
默认宽度为浏览器宽度 | 默认宽高靠内容撑起来 | |
div、p、ul-li、h系列、table等 | span、a、label等 | img、input、textarea等 |
- 块级元素,以div为例
div {
height: 50px;
width: 50px;
border: 5px solid red;
}
<div></div>
<a href="">hello world</a>
div默认宽度根据浏览器当前伸缩的宽度改变,默认的高度靠div标签里的内容撑起。当给div设置了宽高以后,标签拥有了固定的宽度和高度,但其实际在页面中仍然占据一行,即下一个紧挨着的标签会在div的下一行显示。
- 行内元素,以span为例
span {
height: 50px;
width: 50px;
border: 5px solid red;
}
<span>Hello, nice to meet you.</span>
<span>我是第二个span</span>
给span标签设置了宽度和高度,但实际上不起作用,在页面上其宽高仍然由标签里的内容撑起。同时,当两个span标签相继时,其内容可以在同一行显示。
- 行内块元素,以img为例
img {
width: 500px;
height: 200px;
}
<img src="fox.jpg">
<img src="fox.jpg">
img标签可以任意设置宽高,具有块级元素的性质;页面宽度足够时,两个img标签可以在同一行内显示,也具有行内元素的特征。
2.3 display设置元素类型
元素虽有其本身的类型,但可以通过display重新设置
参考MDN文档 - display
标签 {
/* CSS1规范,inline行内,行内元素默认 */
display:inline;
/* CSS1规范,block块级,块级元素默认 */
display:block;
/* CSS2规范,inline-block行内块元素 */
display:inline-block;
/* display:none 将元素进行隐藏,隐藏后位置消失 */
display:none;
/* 区别于 visibility: hidden,将元素进行隐藏,隐藏后原位置保留*/
visibility: hidden;
}
2.4 空隙的产生
元素有行内特性时,元素之间的空白符、回车换行都会被解析成空白符(不为0,但会占据一定的宽度,且间距会随着字体大小变化)
<a href="">链接1</a>
<a href="">链接2</a>
解决这种空隙的办法:
- 两个标签之间不加空格和换行(会导致代码混乱一般不使用)
<a href="">链接1</a><a href="">链接2</a>
- 父元素设置 font-size:0; 使子元素两个标签中间的空格尺寸为0(但是子元素要设置font-size,否则字会消失)
div { font-size: 0; }
a { font-size: 18px; }
<div>
<a href="">链接1</a>
<a href="">链接2</a>
</div>
- 元素设置浮动
.box { float: left; }
<a class="box" href="">链接1</a>
<a href="">链接2</a>
- 元素设置 margin-left: -*px; (兼容性差,元素间隙大小根据上下文字体大小决定,但是每个浏览器换行大小不同)
.box { margin-left: -5px; }
<a href="">链接1</a>
<a class="box" href="">链接2</a>
- 父元素设置: display: table; word-spacing: -1em; 子元素设置: display: inline-block;
.box{
display: table;
word-spacing: -1em;
}
<div class="box">
<div>模块1</div>
<div>模块2</div>
</div>
3. 边距重叠
边距重叠,即外边距 ( margin ) 合并现象,又称塌陷现象。指在默认布局的垂直方向上,默认情况下的外边距是不会叠加的,而是会根据情况进行合并,以单个外边距的最大值的形式呈现最后的效果。
3.1 相邻元素的边距重叠现象
根据边距的不同取值,边距塌陷可分为以下几种情况。
/*代码的公共部分,设置两个div,宽高均为50*/
/* 去掉默认生成的内外边距 */
*{
padding: 0;
margin: 0;
}
div{
width: 50px;
height: 50px;
background-color: pink;
}
<!-- 两个盒子 -->
<div class="box1"></div>
<div class="box2"></div>
- 如果两个外边距相等,则间距取其中一个
/* box1下边距为50,box2上边距为50,合并后间距为50 */
.box1{
border: 5px solid red;
margin-bottom: 50px;
}
.box2{
border: 5px solid green;
margin-top: 50px;
}
- 如果两个外边距为不同正数,则间距取大的那个
/* box1下边距为100,box2上边距为50,合并后间距为100 */
.box1{
border: 5px solid red;
margin-bottom: 100px;
}
.box2{
border: 5px solid green;
margin-top: 50px;
}
- 如果两个外边距为负数,则间距取绝对值大的那个
/* box1下边距为-50,box2上边距为-10,合并后间距为-50 */
.box1{
border: 5px solid red;
margin-bottom: -50px;
}
.box2{
border: 5px solid green;
margin-top: -10px;
}
注:由于两个盒子各有 5px 的border宽度,所以在设置margin为 -50px,实际覆盖到的部分为 box1 中 5px 的 border-bottom 和其中 45px 的 height,所以 box1 上面还剩余了一部分没有被覆盖到
- 如果两个外边距为一正一负,则取两者之和
/* box1下边距为100,box2上边距为-50,合并后间距为50 */
.box1{
border: 5px solid red;
margin-bottom: 100px;
}
.box2{
border: 5px solid green;
margin-top: -50px;
}
注意 margin 的在实际使用场景:
- margin 和 border 都不在 background - * 属性的作用域下;
- margin 边距重叠只会发生在垂直方向,且只会出现在块级元素之间;
- 由于标准文档流布局从上至下、从左到右的特性,如果要使用 margin,尽量多使用margin-top,少使用 margin-bottom
- 一般 margin 用于兄弟之间元素调整距离,padding 用于父子元素调整距离;
- 在浮动流 ( float ) 和绝对定位 ( position:absolute ) 场景下,不会产生外边距的重叠现象。
3.2 父子元素的边距重叠现象
没有内容将父元素和后代元素分开时,也会发生边距重叠
/* 公共代码部分 */
.box{ /* 用来观测 parent 和 son 的位置 */
width: 205px;
border: 5px solid gold;
}
.parent{
width: 200px;
height: 200px;
background-color: red;
}
.son{
width: 100px;
height: 100px;
background-color: blue;
/* 左右居中 */
margin: 0 auto;
/* 上边距为50px */
margin-top: 50px;
}
<div class="box">
<div class="parent">
<div class="son"></div>
</div>
</div>
父元素的边距为 0,子元素的上边距为50px,发生边距重叠,上边距为50px
解决办法:
- 给父元素加边框border(但实际情况可能不想要这个border)
.parent { border: 2px solid black; }
- 给父元素加 padding(但要注意父元素实际大小的变化)
.parent { padding: 2px; }
- 给父级或子级添加 display: inline-block;
因为只有块级元素会产生边距重叠,那么考虑将块级元素变成非块级元素,即行内块级元素(注意:给子元素设置为行内块元素时,是否使用了margin)
.parent { display: inline-block; }
.son { display: inline-block; }
- 给父元素添加属性 overflow: hidden; (子元素的高度加上外边距 < 父元素的高度。如果超出,子元素的部分内容会被隐藏掉)
.parent { overflow: hidden; }
- 给父级或子级设置浮动float
.parent { float: left; }
由于设置了浮动,parent盒子及里面的内容脱离了标准文档流,导致了外层box的边框发生了塌陷
.son { float: left; }
- 给父级或者子级设置定位position: absolute
.parent { position: absolute; }
效果跟浮动差不多,内容脱标,box边框塌陷
.son { position: absolute; }
4. box-sizing | 两种盒模型
css3 新增了 box-sizing 属性,提供了两种计算元素总高度和总宽度的方法。
-
box-sizing : content-box ;
标准盒模型,为box-sizing的默认(缺省)值
计算方式:
width = 内容的宽度
height = 内容的高度
(宽度和高度的计算值都不包含内容的边框(border)和内边距(padding)) -
box-sizing : border-box ;
怪异盒模型
计算方式:
width = border + padding + 内容的宽度
height = border + padding + 内容的高度
.content-box , .border-box {
width: 100px;
height: 100px;
padding: 10px;
border: 10px solid black;
margin: 10px;
background-color: pink;
}
.content-box { box-sizing: content-box }
.border-box { box-sizing: border-box; }
<div class="content-box">content-box</div>
<div class="border-box">border-box</div>
:) 错误欢迎指正