margin系列之圣杯拾遗
博客专区 > 山哥 的博客 > 博客详情
margin系列之圣杯拾遗
山哥 发表于1年前
margin系列之圣杯拾遗
  • 发表于 1年前
  • 阅读 47
  • 收藏 0
  • 点赞 0
  • 评论 0

【腾讯云】如何购买服务器最划算?>>>   

margin系列之布局篇 一文结尾时,我们谈到了圣杯布局,说这个布局的实现本身存在了一些问题:“在IE6/7下报废,不过不用慌,因为它可被修复”。

圣杯布局的一些谈资

下面节选一段来自网路上对圣杯的描述(略有调整):

圣杯是宗教传说中的圣物,耶稣曾经用这个杯子吩咐门徒喝下里面象征他的血的红葡萄酒,借此创立了受难纪念仪式。因为这个特殊的原因,后来有些人认为这个杯子具有某种神奇的能力。很多传说相信,如果能找到这个圣杯而喝下其盛过的水就将返老还童、死而复生并且获得永生,这个传说广泛延续到很多文学、影视、游戏等作品中。

而所谓的圣杯布局也并不是一个具象的形容,更多的是指借希望于它能够实现某种特殊的布局。

这种特殊布局的需求是:侧边栏宽度固定,主内容栏宽度自适应,并且需要将主内容栏放在侧边栏前面,以便优先渲染(不论是两栏或者三栏,需求都是一样的)。

遗留的问题

在 margin系列之布局篇 里,我们用圣杯布局做了 图0 的效果。

图0:classsic layout

图0:classsic layout

下面是我们在上篇文章中写的圣杯布局核心代码(当然,这个 #demo 容器你也可以利用 body来取代):

HTML

1
2
3
4
5
6
7
8
<div id="demo">
    <header id="hd">头部</header>
    <div id="bd">
        <div id="main">主内容栏自适应宽度</div>
        <aside id="aside">侧边栏固定宽度</aside>
    </div>
    <footer id="ft">底部</footer>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#demo {
    width: 80%;
}
#bd {
    *zoom: 1;
    overflow: hidden;
    padding-left: 210px;
}
#main {
    float: left;
    width: 100%;
}
#aside {
    _display: inline;
    float: left;
    position: relative;
    left: -210px;
    width: 200px;
    margin-left: -100%;
}

大家可以使用各种浏览器来测试一下这个示例 圣杯:左栏固定主内容自适应

一般情况下,你会发现除了IE6外,其它的浏览器看起来都算正常,然而问题的范围可能并不仅限于这些,大部分问题没被看出只不过是因为没到达边界。

问题列表:

  • IE6 布局错乱,侧边栏位置不对;
  • IE7 resize窗口时,侧边栏会跳动;
  • IE7及其它浏览器,当窗口缩小到主内容栏的宽度小于侧边栏的宽度时,布局错乱;

上面这几个问题,大家其实都可以自己去测测看,应该是当前的实现中都存在的。

对于第3点,我们看看上述的代码实现,还是能非常轻松的理解的。因为侧边栏定义了 margin-left: -100%,在这个场景中,100% 其实就等同于主内容栏的宽度。如果主内容栏的宽度小于侧边栏,那么侧边栏偏移了一个比自己小的宽度,自然是放不下自己的。

对于第1点,这个就有点意思了,基本上这又算是IE6的一个Bug,描述一下这个Bug的现象:

在IE6中,假定是处于默认的书写模式下,当一个浮动的元素定义了margin的值是一个百分比,那么此时,浮动元素的margin百分比参照最近的清除了浮动的包含块的父元素的宽度进行计算,或者参照body。(然而标准描述只是参考包含块的宽度进行计算,详情请参阅我之前的文章 margin系列之百分比

我会用一段伪代码来详述这个事,代码如下:

1
body > c > b > a

假设上述代码中的 a 就是我们说的浮动元素,正常情况下 a 设置了一个百分比的margin,百分比是要参考 b 的宽度进行计算的。

然后 IE6 并没有实现这个规则,它的特征是:

  • 浮动元素 a 定义了百分比的margin,假设它的祖先元素 b 和 c 都没有清除浮动,那么就会参照 body 的宽度进行百分比换算;
  • 假设 b 清除了浮动,那么就会参照 c 的宽度进行百分比换算;

对于这个Bug,我写了一个示例,大家可以对照着描述来看这个例子:浮动margin百分比在ie6上的Bug

好了,知道了在 IE6 中有这个Bug之后,关于问题列表中的第1点,我们就也能够理解了,因为 position: relative; left: -210px; 这个定义对于 IE6 来讲,其实是多余的。

对于第2点,应该是在resize过程中,不断的重绘造成的,它需要不断的去计算这个百分比的使用值。

杀死它们

所以如果想使得圣杯布局变得更靠谱一些,我们要么就是见招拆招,修复这个问题(比如说为 IE6 重置掉 position: relative; left: -210px; 定义),要么就避免遇上这些问题,我更喜欢第二种的方式。

我们如何做才能避免遇上这些问题?

其实我们可以细看一下,问题列表中的几点,其实都是因浮动元素的margin百分比引发的。既然浮动元素的margin百分比,在各浏览器下需要差异化处理,那么干脆弃用百分比,改用固定值(复杂度其实并没有上升,因为用百分比的时候,还得给left定义一个固定的偏移量)。

那么,新的问题来了。如果改用margin固定值,我们要如何知道这个固定值是多少?比如在这个布局中我们的容器宽度是视窗的 80%,我们无法得到侧边栏需要偏移的固定值是多少,除非我们使用运算表达式 calc(),但是它的兼容性并不是我们想要的。

这是因为主内容栏和侧边栏都是左浮动,并且侧边栏浮动在主内容栏后面,所以我们需要让侧边栏偏移 #main + #aside 的宽度,才能让侧边栏出现在正确的位置。

所以,其实我们可以转变一下思路,让主内容栏和侧边栏朝不同的方向浮动,这样的话,侧边栏只需要偏移自身的宽度就能出现在正确的位置上,不在需要使用margin百分比值。

新路

我们按照前面说的将代码调整一下,HTML不变:

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#demo {
    width: 80%;
}
#bd {
    *zoom: 1;
    overflow: hidden;
    padding-left: 210px;
}
#main {
    float: right;
    width: 100%;
}
#aside {
    _display: inline;
    float: left;
    width: 200px;
    margin: 0 10px 0 -210px;
}

我们来看看这个 进化的圣杯:左栏固定主内容自适应 效果,你会欣喜的发现,问题列表中的3个问题都被我们跳过了,这是一个更健康的实现。

当然,它也是可以任意调整列呈现顺序的,我们只需要这样就行:

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#demo {
    width: 80%;
}
#bd {
    *zoom: 1;
    overflow: hidden;
    padding-right: 210px;
}
#main {
    float: left;
    width: 100%;
}
#aside {
    _display: inline;
    float: right;
    width: 200px;
    margin: 0 -210px 0 10px;
}

于是我们就得到了一个 进化的圣杯:右栏固定主内容自适应 的布局。

总体来讲,圣杯布局只是有能力达成我们的需求,但就其本身来讲并不是太先进的布局,灵活性相对局限。

另外,你可能关注到了代码中出现的 margin 定义,它并不是一个单纯的负值,而是多了一个 10px,这其实是为了解决 IE6/7 右浮动子元素的向右负偏移量最大只能是自身宽度的问题(感兴趣的童鞋可以看看这个测试:右浮动margin-right负值在ie67上的bug),所以额外处理的间隙,但这其实并不影响其他浏览器。

最后

本文,更多的在于补全之前的那篇文章,算个简单的完结。本意其实并不在于说让大家去折腾那些古老而无趣的浏览器,而是希望看到的是对待任何事情,我们首先要觉得它可以解决,然后再抽丝剥茧的去实现它。未知并不可怕,可怕是恐惧未知。

共有 人打赏支持
山哥
粉丝 237
博文 306
码字总数 136465
×
山哥
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: