圣杯布局、双飞翼布局

1. 问题场景

三列布局中,如果想要将主要内容main优先加载优化,则DOM如下所示

1
2
3
4
5
<div class="g-container">
  <div class="g-main">我是主列</div>
  <div class="g-left">我是左列</div>
<div class="g-right">我是右列</div>
</div>

但又想将主要内容在中间位置显示,便有如下css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.g-container {
float: left;
width: 100%;

& > div {
width: 190px;
min-height: 30px;
}
}

.g-container .g-main {
float: left;
width: 100%;
background: #cc6630;
}

.g-left {
float: left;
margin-left: -100%;
background: #f00;
}

.g-right {
float: left;
margin-left: -190px;
background: #00f;
}

下面逐行分析一下:
第1行:grid-s5m0e5 是一个布局框的名称,我们为其定义了宽度100%(在IE6一不定义100%时,有点小问题,亲们自己可以一试)

第2行:col-main 【主列】:浮动左侧,宽度100%(宽度全让它给占了,左右两侧的层该怎么办?)

第3行:col-sub 【子列】:浮动左侧,宽度190,左边界为-100%(此处是关键:浮动情况下,负边界值会导致DIV上移,而使用-100%可以确实它移动到最左侧。)

第4行:col-extra 【附加列】:左浮动,宽度190,左边界为-190px(道理同上,注意的是,负左边界一定要大于或等于该DIV的宽度,才能靠到上一行去)

让我们看看效果

1565423970941

但这样布局后发现主列中的文字不见了,经过DOM分析发现,原来是被col-sub挡住了,那么如何给main正确的定位呢。

1.圣杯布局(margin+position)

左右两列通过margin-leftleft和right准确定位,中间列用width:100%撑开
圣杯布局的关键点父元素需要设置padding
margin-left取值为百分比时,是以其父元素的宽度为基准的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.g-container {
position: relative;
padding: 0 190px;

& > div {
float: left;
min-height: 30px;
}
}

.g-main {
position: relative;
width: 100%;
background: #cc6630;
}

.g-left {
position: relative;
width: 190px;
margin-left: -100%;
left: -190px;
background: #ffcc00;
}

.g-right {
position: relative;
width: 190px;
margin-left: -190px;
right: -190px;
background: pink;
}

2. 圣杯布局(flex)

利用flex的order属性调整位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.g-container {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;

& > div {
min-height: 30px;
}
}

.g-main {
order: 2;
flex: auto 1 0;
background: #cc6630;
}

.g-left {
order: 1;
flex: 200px 0 0;
background: #ffcc00;
}

.g-right {
order: 3;
flex: 200px 0 0;
background: pink;
}

image-20201030180215043

这种写法更加简洁,但是兼容性不太好

3.双飞翼布局(margin)

利用margin-left属性将左右两列放置到准确的位置,通过控制 main列 的margin空出左右两列

下面是淘宝的做法:

1、DOM结构的改变:在.col-main下再次添加一个 .main-wrap

2、利用CSS调整.main-wrap的位置。【这里很简单,就是把左右被挡住的部分,设置为main-wrap的左 右边界即可】

1
2
3
4
5
6
7
8
9
<div class="g-container">
<div class="g-main">
<div class="main-wrap">
我是主列,出来吧!
</div>
</div>
<div class="g-left">我是左列</div>
<div class="g-right">我是右列</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.g-container {
float: left;
width: 100%;

& > div {
float: left;
width: 190px;
min-height: 30px;
}
}

.g-container .g-main {
width: 100%;
background: #cc6630;

.main-wrap {
margin-left: 200px; /*与g-left产生10像素距离*/
margin-right: 200px; /*与g-right产生10像素距离*/
background: #0f0;
}
}

.g-left {
margin-left: -100%;
background: #f00;
}

.g-right {
margin-left: -190px;
background: #00f;
}

最终效果

1565424018386

优点

  • 实现了内容与布局的分离,即Eric提到的Any-Order Columns.
  • main部分是自适应宽度的,很容易在定宽布局和流体布局中切换。
  • 任何一栏都可以是最高栏,不会出问题。
  • 需要的hack非常少(就一个针对ie6的清除浮动hack:_zoom: 1;)
  • 在浏览器上的兼容性非常好,IE5.5以上都支持。

不足

  • main需要添加一个额外的包裹层。
作者

Liang

发布于

2020-10-30

更新于

2021-12-23

许可协议


评论