深入理解CSS盒子模型
盒模型
盒模型是CSS的基石之一,它指定元素如何显示以及(在某种程度上)如何交互。页面上每一个元素都被看做一个矩形框,框由元素的内容,内边距 (padding),边框 (border)和外边距 (margin)组成,如下图所示。
内边距出现在内容区域周围,若给元素上添加背景,背景将会应用于由内容和内边距组成的区域。添加边框,会在内边距的区域外加一条线,这些线有多种样式,后面会有所介绍。在边框外边是外边距,外边距是透明的,一般使用它控制元素之间的间隔。
CSS2.1还包含outline属性,绘制在元素框之上,不影响元素的大小或定位。大多数现代浏览器(包括IE8)都支持outline,但IE7和更低版本不支持。
内边距、边框、外边距都是可选的,默认值为零。但许多元素将由用户代理样式表设置外边距和内边距,所以将元素的margin和padding设置为零,对写整个样式有帮助,这项工作一般由全局reset进行。
1. IE和盒模型
IE的早期版本,包括IE6,在混杂模式中使用自己的非标准盒模型。浏览器的width属性不是内容的宽度,而是内容,内边距和边框的总和。添加的内边距越多,给内容预留的空间就越少。
在CSS3中,可通过box-sizing属性定义使用哪种盒模型,但除了一些非常特殊的场合很少使用该属性。
目前最好的解决方案是回避这个问题。也就是,不给元素添加指定宽度的内边距,而是尝试将内边距或外边距添加到父元素或子元素。
2. box-sizing
box-sizing属于CSS3内容,属性值包括:content-box, border-box, inherit。该属性用于更改预设的CSS盒模型宽度和高度的计算方式,可使用该属性模拟不正确支持CSS盒模型规范的浏览器行为。
- content-box
- 根据CSS标准的起始值和预设值(标准盒模型,现在浏览器默认支持该属性)。width和height只包括内容本身的宽度和高度。元素框的大小=width/height+padding+border+margin
- border-box
- 该属性值下,width和height属性包括内容(content),内边距(padding)和边框(border)。
- inherit。指定 box-sizing 属性的值,应该从父元素继承
浏览器支持:IE8及以上,Chrome 10.0以上,FireFox 29.0 以上,Safari 5.1以上,Opera 9.5以上。
示例:
div {
box-sizing:border-box;
-moz-box-sizing:border-box; /* Firefox */
-webkit-box-sizing:border-box; /* Opera */
width:50%;
float:left;
}
3. margin
margin属性用于设置外边距,下面我们将讲述margin一些比较有意思的知识点
3.1 margin与容器尺寸
在标准盒模型中,border-box部分,即包括border,padding,content的方框代表可视尺寸(clientWidth)。外边距加上可视尺寸则是“占据尺寸”(张鑫旭大神自命名)。
在一些前提下,通过设置margin属性可以改变可视尺寸和“占据尺寸“的大小。
1. margin改变可视尺寸
适用范围:
-
适用于没有设定width/height的普通block水平元素(
float,absolute/fixed,inline水平,table cell元素。..) -
只适用于水平方向尺寸
可利用该特性实现一侧定宽自适应布局和两端对齐布局效果。
2. margin改变”占据尺寸“
适用范围:
-
block/inline-block水平元素均适用
-
与有无设定width/height值无关
-
适用于水平方向和垂直方向
可利用该效果实现滚动容器上下留白及等高布局效果。
3.2 margin与百分比单位
-
普通元素的百分比margin都是相对于容器(父级元素)的宽度计算。
-
绝对定位元素的百分比margin都是相对于第一个定义祖先元素(relative/absolute/fixed)的计算宽度
- 在IE中,绝对定位元素的百分比margin是相对于第一个定义祖先元素的宽度计算
- 在Chrome/FireFox/Opera中,绝对定位元素的百分比margin是相对于第一个定义祖先元素的border-box的宽度计算的。Opera浏览器由于作者是windows系统,安装的windows版本,感觉表现得很奇怪。没有显示出数值,不方便得出结论,希望有读者能够测试了在评论区反映一下,共同探讨之,谢谢!
3.3 margin重叠
margin重叠,即外边距叠加,是一个比较简单的概念。但是,在实践中对网页进行布局时,它会造成很多混淆。简单地说,当两个或更多垂直外边距相遇时,它们将形成一个外边距。这个外边距的高度等于两个发生重叠的外边距的高度中的较大值。
1.3. 1 margin重叠特性
- 只有普通文档流中的块框的垂直外边距才会发生外边距叠加(不包括float框和absolute框以及行内框)
- 不考虑writing-mode,只发生在垂直方向(margin-top/margin-bottom)
1.3.2 margin重叠的3种情境
margin重叠3种情境:
- 相邻的兄弟元素
- 父级和第一个/最后一个子元素
- margin-top重叠其他条件
- 父元素非块状格式化上下文元素
- 父元素没有border-top/padding-top设置
- 父元素和第一个子元素之间没有inline元素分隔
- margin-bottom重叠其他条件
- 父元素非块状格式化上下文元素
- 父元素没有border-bottom/padding-bottom值
- 父元素和最后一个子元素之间没有inline元素分隔
- 父元素没有height,min-height限制
- 干掉margin-top重叠
- 在父元素加属性,overflow:hidden;
- 父元素设置border-top/padding-top值
- 父元素与第一个子元素之间插入inline元素,如空格
- 干掉margin-bottom重叠
- 在父元素加属性,overflow:hidden;
- 父元素设置border-bottom/padding-bottom值
- 设置height相关声明(min-height以及height。max-height不起作用)
- margin-top重叠其他条件
- 空的block元素(自己的上下外边距叠加)
- 重叠其他条件
- 元素不能有border/padding值
- 里面没有inline元素
- 没有height,或者min-height
- 重叠其他条件
1.3.3 margin重叠计算规则
- 正正取大值
- 正负值相加
- 负负最负值
1.3.4 margin重叠的意义
- 连续段落或列表之类,如果没有margin重叠,首尾项间距会和其他兄弟标签1:2关系,排版不自然
- web种任何地方嵌套或直接放入任何裸div,都不会影响原来的布局
- 遗落的空任意多个p元素,不会影响原来的阅读排版
1.4 margin auto
作用机制:自动填充元素占据空间的剩余空间,可利用其实现水平居中:
div{
width:300px;
margin:0 auto;
}
注意:margin实现居中,必须计算后的距离不能是负值。
margin 如何实现垂直布局?
- 改变流(但水品不再居中)
.father{height:200px; width:100%; writing-mode:vertical-lr;}
.son {height:100px; width:500px; margin:auto;}
2.绝对元素的margin:auto居中(IE8+)
.father{ height:200px; position:relative;}
.son{ position:absolute; top:0; right: 0; bottom:0; left:0;
width:500px; height:100px; margin:auto;}
1.6 CSS margin失效情形
1.inline水平元素的垂直margin无效
前提:
- 非替换元素(如img)
- 正常书写模式
2.margin重叠
3.display:table-cell与margin
margin可应用于所有元素,除了diplay为table相关类型(不包括table-caption,table以及inline-table)的所有。甚至可应用于::first-letter
4.绝对定位元素非定位方向的margin值“无效”
绝对定位元素的margin值一直有效,但由于设置了绝对定位,脱离了文档流,所以看不出效果。
5.鞭长莫及导致margin无效,一些情况下,如浮动时,margin无效可能是不够大。
6.内联特性导致margin无效,例如对于图片,使用margin的负值定位,不会出现在容器之外。
1.7 了解margin-start/margin-end属性
Chrome/FireFox目前支持该属性,IE不支持
margin-start
- 正常流向margin-start与margin-left等效,两者重叠不累加。
- 如果水平流是从右往左,margin-start等同于margin-right;
- 在垂直流下(writing-mode:vertical-*),margin-start等同于margin-top;
margin-end
- 正常流向margin-end与margin-right等效,两者重叠不累加。
- 如果水平流是从右往左,margin-end等同于margin-left;
- 在垂直流下(writing-mode:vertical-*),margin-end等同于margin-bottom;
4. border
4.1 border-width 不支持百分比
盒子模型种,padding,margin都支持百分比,但是border,即边框宽度不支持百分比;来自张鑫旭大神的理解:border-width不支持百分比是由于其语义限制,因为可以看到平板和手机两个不同显示大小的边框大小并不根据元素长宽变化而变化。
4.2 了解各种border-style类型
-
solid (实线)
-
dashed (虚线)
在Chrome/FireFox中,虚线边框的宽高为3:1,IE为2:1。
-
dotted(点线)
在Chrome/FireFox中,点的形状为方形,IE为圆形。
-
double(双实线)
双线宽度相等,中间空白间隔$\pm$1
-
inset(内凹)
4.3 border-color与color
border-color默认继承自color,即未指定color时border-color与color一样。类似的还有box-shadow,text-shadow,outline。
5. padding
5.1 padding与容器尺寸
当width auto或者box-sizing为border-box,但是padding大小超过宽高时,padding会影响元素尺寸。
对于block元素:
- padding值暴走,一定会影响尺寸
- width非auto,padding影响尺寸
- witdh为auto或box-sizing为border-box时,同时padding值未暴走,不影响元素尺寸。
对于内联元素:
水平padding影响尺寸,垂直padding不影响尺寸。但会影响背景色。
5.2 padding负值与百分比值
padding不支持任何负值,padding的百分比相对于宽度计算。
inline元素的百分比值
- 同样相对于宽度计算
- padding会断行
- 默认的高度宽度细节差异
空inline元素+padding高端也不等。是由于inline元素的垂直padding会让"幽灵空白节点"显现,也就是规范中的“strut”出现。这时通过设置font-size:0规避
span{padding:50%;font-size:0;}
5.3 标签元素内置padding
button表单按钮设置padding:0,Chrome是ok的,但是在FireFox中左右依然会有padding,通过设置属性-moz-focus-inner规避;IE浏览器中,IE7文字越多左右padding逐渐变大,通过overflow属性设置规避。
button::-moz-focus-inner {
padding:0;
}
button{padding:0;overflow:visible;}
对于button,padding与高度计算不兼容,所以一般通过label标签实现button,而button通过绝对定位到页面之外或者z-index隐藏在页面下方。
<button id="btn"></button>
<label for="btn">按钮</label>
label{
display:inline-block;
line-height:20px;
padding:10px;
}