萝三画室

解决body位置下移问题

问题背景

实现两个div,其中一个随滚轮滚动,效果如下。
图1-正常情况

上图是正常情况,下图是滚轮滚动时的情况。
图2-滚轮滚动

实现过程

首先添加两个普通的div

1
2
3
4
<body>
<div id="header">我是header</div>
<div id="main">我是main</div>
</body>

为了显示清楚,设置div的背景颜色。

1
2
3
4
5
6
7
8
9
10
11
12
<style type="text/css">
body{
margin: 0;
}
#header{
background: pink;
}
#main{
background: green;
height: 1000px;
}
</style>

这样看上去与图1一致,但无法实现图2的效果。

将header固定在视窗顶部

1
2
3
4
5
6
#header{
background: pink;
/*由于下文fixed定位使元素脱离正常文档流,如果不指定width,则其值自适应子元素宽度*/
width: 100%;
position:fixed;
}

此时发现,main被header盖住了,如图3.
图3
原因是fixed使header元素脱离了正常文档流,相当于本来是第二个元素的main元素变成了第一个元素,占据了body首行位置。

让main元素露出来

为了让main露出来,我马上想到的是通过设置它的margin-top。

1
2
3
4
5
#main{
background: green;
height: 1000px;
margin-top:21px;/*留出header宽度*/
}

然而结果并非我想要的.
图4
不但main没露出来,连header的位置都下移了!查看元素位置发现body元素也下移了21px!
这个问题是由一个原则造成的。我们知道,正常文档流中,子元素的外边界(margin)应与父元素的内边界(padding)对齐。但“如果父元素的第一个子元素存在非0的margin,则父元素与子元素之间以内边界对齐”。这就造成了body和main的padding重合,效果就如图四。
4放弃margin,改成padding
知道了错误原因,我们就可以对症下药了。只要将main的margin设为0,上述“”中的原则便不适用了,main的margin依然与body的padding对齐。再通过增加main的padding-top使其内容区移动到header的位置外,main中的内容就可以全部显示出来了。

1
2
3
4
5
#main{
background: green;
height: 1000px;
padding-top:21px;/*留出header宽度*/
}

Done!
原则很简单,但很多时候都不记得。
最后再重述一下导致本例问题出现的原则:“如果父元素的第一个子元素存在非0的margin,则父元素与子元素之间以内边界对齐”。