css的盒模型一直是一个重点和难点,最近由后端的学习转到前端,觉得有必要深入研究一下css的盒模型。
1.万物皆盒子
我们必须要有一个理念,在html的世界里,万物皆盒子,那就是任何一个html元素都是一个盒模型。比如一个div,一个标题,一个段落。他们本质上都是一个盒模型。
2.盒模型的结构
如下所示。
注意它的宽度和高度指的是它元素的宽度和高度。元素到边框之间的区域叫做padding(内边距),边框在往外扩展的区域就叫做外边界。外边界就是整个盒模型能到达的最遥远的地方,也是保证其他的盒子不会侵袭这个盒子的边界线。
有几个点需要注意:
a.首先分析盒模型,要找准你分析的对象,比如一个div对象。上图中所有盒模型的所有术语(width,heghit,padding)都是针对该盒模型而言的。这时候你就不要去管它旁边的,或者它内部的其他元素。只需要分析这个对象就好了。
b.width和height指的是元素的宽度和高度,确切的说,应该是这个盒模型的元素可以使用的宽度和高度,事实上,它里面的元素可能并没有所规定的高度和宽度那么大,也有可能超出这个范围。但是在IE浏览器中,这个高度和宽度是内容区+内边距+边框的距离。我们可以通过box-sizing:border-box;来设置一个盒子是采用IE的模式来计算宽高。
c.background-color或者背景图像所填充的区域是包含元素+内边距的内容。利用这点我们可以来做一些实验。
d.边框和外边距之间的内容默认是透明的。
以上便是一个盒模型的所有元素。下面我们先来看一个例子,对盒模型有个直观的了解。
<body> <div id="box1"> <h1>a box</h1> </div> </body>
其css代码如下
* { margin: 0; padding: 0; } #box1 { background-color: #C6F08C; padding: 5px; color: white; margin: 5px; width: 300px; height: 300px; }
因为有些浏览器默认会提供margin和padding,为了方便我们试验观察,这里我们先强制设为0,如上面的第一个css所示。运行上述的代码以后,我们看到页面展示的内容是这样的。
从这里你看不出什么东西,这时候可以利用google的f12,观察html元素。选中div id=“box1”这个元素,这时候将展示出他的盒模型,如下图所示。
你可以尝试勾选上图中box1的css元素,观察右侧html页面的实际变化,比如,当我们将padding:5px这个元素不选中以后,盒模型变成如下所示。
如果你自己操作,仔细观察,就会很明显的发现,划掉padding以后,这个box1的背景颜色的长度和宽度变小了,因为background包含的是element+padding,现在没有了padding,总的面积就减少了。另外一个变化是内容“a box"变得紧贴着边沿。同样是因为padding变为0了。元素和边框之间没有其他东西了。
读者可以在尝试划掉margin,就会发现整个盒模型紧贴着浏览器的边沿,如下所示。
我们继续做实验,把padding依然设为5,而把margin设为-10.看看这时候页面的样式。
我们发现浏览器的边沿侵占进了box1这个盒子的边沿(上边沿和下边沿),造成我们只看得到a box这行字的部分,事实上,box1的边框内部(包含padding和元素)是没有任何改变的,只是因为margin变为-10,则它的领地位置变得是从边框往里缩进了10个像素,也就是说放在它前后左右的其他盒子(如果没有盒子的话,就是浏览器的边沿)都可以侵占到它bordern内10个像素。
我们可以得出如下结论:
a.padding是针对box的元素而言的,它指代的是内部元素与边框之间的区域。
b.margin则是针对于其他的box而言的,它表示边框能到的最远位置,也是其他的盒子能接触该盒子的极限位置。
3.盒子中的盒子
经过上面篇幅的介绍,我们大概知道了盒模型的主要元素。现在我们在google浏览器中将目标定位在box1中的h1元素。按照任何对象都是一个盒子的理论,这也是一个盒子。我们来看一下它的布局。
我们看到,h1这个盒子,它的长X宽是300X42。margin和padding都是0.因为box1的长宽为300X300.所以整个h1到外边界的部分最大也就是300X300.我们可以做个试验,设置h1的padding和margin。
可以看到这时候的h1的element+padding+margin才是300.证明了我们的猜想:子盒子的外边界能到的最大地方就是父盒子的元素所规定的长宽。
4.盒子与盒子
再新建一个盒子,box2,其css如下所示。
#box2 { background-color: blue; width: 300px; height: 300px; padding: 5px; }
观察到上面的css,我们没有设置box2的margin,来看看效果。
因为box2没有设置margin,所以它的左侧是紧挨着浏览器边缘的。但是由于box1设置了margin,所以box1和box2接壤的地方是有5px的空间隔离的。
我们设置一下box2的margin,设为5px,再看看效果。
我们发现,两个box的margin折叠了,也就是说box1的下外边距+box2的上外边距并不是5+5=10,而是只有5.事实上,假如我们将其中一方的margin设置得比另一方大,则会取大的那一方为准。如下所示。
不仅在兄弟盒子之间会发生折叠,父子盒子之间也会。比如说box4是box3的子元素,两者都设置了margin,并且box3没有设置padding和border,那么box3和box4的top margin将会重合,box3与兄弟盒子之间的top margin为box3与box4之间较大者。
#box3 { background-color: yellow; width: 300px; height : 300px; height: 300px; margin:5px; /* padding:5px; */ } #box4 { background-color: green; width: 200px; height: 200px; margin:50px; }
上述的css的效果如下。可以看到除了top margin,box4其他的方面都可以按照我们对盒子的原本理解来解释。不管的左、右,下外边距都是相对于box3的element来说的。(box3的element为300X300,box3的外边距设置为50,所以实际的box4的元素为200X200.)。但是如你所见,box4上外边距跟box3重合了,他共同跟外部盒子的上外边距为两者中的大者(50px),而box3的左右下外边距依然是5px.
而一旦设置了box3的上内边距,则上述的折叠现象将不复存在。如下图所示。
外边距的折叠只发生在普通的块之间的垂直位置上,行内框、浮动框或绝对定位之间的外边距不会折叠的,比如说当一个盒子被标注成float的时候。如下所示。
可以发现两个盒子之间的margin为5+5=10了。
外边距合并初看上去可能有点奇怪,但是实际上,它是有意义的。以由几个段落组成的典型文本页面为例。第一个段落上面的空间等于段落的上外边距。如果没有外边距合并,后续所有段落之间的外边距都将是相邻上外边距和下外边距的和。这意味着段落之间的空间是页面顶部的两倍。如果发生外边距合并,段落之间的上外边距和下外边距就合并在一起,这样各处的距离就一致了。
PS:当margin-left和margin-right都设为auto的时候,框将在父容器中自动居中。
总得来说,关于css的盒模型,要多去实践,才能发现其中的规律。