三. 盒子之间的关系

单独的一个盒子不难理解,实际上网页往往是很复杂的,一个网页可能存在着大量的盒子,并且它们之间以各种关系相互影响着。为了适应各种排版要求,CSS规范的思路是:首先确定一种标准的排版模式,这个就是“标准流”。 但仅通过标准流方式,很多排版是无法实现的,CSS规范中又给出了另外几种对盒子进行布局的方法,包括“浮动”和“定位”等属性,对某些元素进行特殊排版。

1. DOM树

一个HTML从表面看是文本文件,从逻辑上看则具有内在的层次关系。“树”可以表示具有层次关系的结构。 任意一个HTML文档都对应一棵DOM树,body是所有对象的根节点。而该DOM树的节点如何在浏览器中表现,则由CSS确定。即HTML控制网页的结构,CSS控制网页的表现。

doc to dom 图6 HTML文档对应DOM树

2. 标准文档流

“标准文档流”(Normal Document Stream),简称“标准流”,是指在不使用其他与排列和定位相关的特殊CSS规则时,各种元素的排列规则。 如上图共有四层结构,顶层为body,第二层为ul,第三层为li,第四层为文本。这四种元素分为两类:

块级元素(block level)

li占据着一个矩形的区域,并且和相邻的li依次竖直排列,不会排在同一行中。ul也具有同样的性质,占据着一个矩形的区域,并且和相邻的ul依次竖直排列,不会排在同一行中。这类元素称为“块级元素” ,即它们总是以一个块的形式表现出来,并且跟同级的兄弟块依次竖直排列,左右撑满。 常见的块标记:address、block、div、dl、fieldset、form、h1 ~ h6、menu、ol、ul、p、table

行内元素(inline)

对于文字这类元素,各个字母之间横向排列,到最右端自动折行,这就是另一种元素,称为“行内元素”。比如<strong></strong>标记,就是一个典型的行内元素,这个标记本身不占有独立的区域,仅仅是在其他元素的基础上指出了一定的范围。再比如,最常用的<a></a><span></span>标记。

3.浏览器处理元素过程:

第1步:从body开始,依次把两个ul块竖直排列。 第2步:分别进入每一个ul查看它的下级元素,把两个li块竖直排列在ul中。 第3步:进入li内部,是一行文本,按行内元素排列文字。

4.<div>标记与<span>标记

为了更好地理解“块级元素”和“行内元素”,这里重点介绍在CSS排版的页面中经常使用的<div><span>标记。 div简单而言就是一个块级容器标记,可以容纳段落、标题、表格、图片,乃至章节、摘要和备注等各种HTML元素。可以把div当做一个独立的对象,用CSS进行控制。<span><div>一样,在HTML元素中可以作为独立的对象进行处理。 两者的区别在于:div是一个块级元素,span仅仅是一个行内元素,在它的前后都不会换行。span没有结构上的意义,纯粹是应用样式,当其他行内元素都不适合时,就可以用span标记。div标记可以包含span,span不可以包含div。

5. 盒子在标准流中的定位原则

如果要精确地控制盒子的位置,就必须对margin有更深入的了解。padding只存在于一个盒子内部,所以通常它不会涉及与其他盒子之间的关系和相互影响的问题。margin则用于调整不同的盒子之间的位置关系。

行内元素之间的水平margin

horizontal margin 图7 行内元素之间的水平margin 两个块之间的距离为:30px+40px=70px。

块级元素之间的竖直margin

vertical margin 图8 块级元素之间的竖直margin

如果不是行内元素,而是竖直排列的块级元素,margin的取值情况就会有所不同。 两个块级元素之间的距离不是margin-bottom与margin-top的总和,而是两者中的较大者,如图所示。这个现象称为margin的“塌陷”(或称为“合并”)现象,意思是说较小的margin塌陷(合并)到了较大的margin中。

6. 嵌套盒子之间的margin

除了上面提到的行内元素间隔和块级元素间隔这两种关系外,还有一种父子关系,它的margin值对CSS排版也有重要的作用。当一个<div>块包含在另一个<div>块中时,便形成了典型的父子关系。 其中子块的margin将以父块的内容为参考,如图4.22所示。

nest margin 图9 嵌套盒子之间的margin 在没有设置width和height的情况下,高度和宽度都会自动延伸和收缩。 在标准流中,一个块级元素的盒子水平方向的宽度会自动延伸,直至上一级盒子的限制位置。对于高度,div都是以里面的内容的高度来确定的,也就是会自动收缩到能包容下内容的最小高度。

示例代码7:在没有设置width和height的情况下,高度和宽度都会自动延伸和收缩

<!DOCTYPE html>
<html lang="zh_CN">
<head>
    <meta charset="UTF-8">
    <title>盒子的嵌套</title>
    <style>
        #box1{//父盒子 设置宽度
            border:1px solid red;
            width: 300px;
            height: 150px;
            background: pink;
        }
        #box2{//子盒子 不设置宽度
            border:1px solid red;
            height: 100px;
            background: green;
        }
    </style>
</head>
<body>
    <div id="box1">父盒子
        <div id="box2">子盒子宽度 自动延伸为 父盒子宽度</div>
    </div>
</body>
</html>

效果:

width 100% 图10 子盒子宽度延伸为父盒子宽度

如果更改代码:父盒子不设置高度,子盒子设置高度,则父盒子高度会收缩至子盒子的高度,效果如下:

hight 100% 图11 父盒子高度收缩为子盒子高度

7. margin属性可以设置为负值

上面提及margin的时候,它的值都是正数。其实margin的值也可以设置为负数,而且有关的巧妙运用方法也非常多。

negative margin 图12 margin-left=-50px