文章地址:https://alistapart.com/article/holygrail
从开始讲起
三列。一个固定宽度的侧栏为导航栏,另一个,例如谷歌广告或Flickr照片(也是固定宽度的),还有一个宽度可以伸缩的中间栏的存在。它在博客的这个黄金时代被广泛应用,以及使用他的相当大的困难,使它赢得了“圣杯”的称号。
关于圣杯的文章很多,存在一些好的模板。然而,所有现有的解决方案都涉及牺牲:适当的源顺序,全宽度页脚,和精益标记往往在追求这一难以捉摸的布局。
最近的一个项目使我的个人圣杯任务结束了。我将描述的技术将允许您在不损害代码或灵活性的情况下部署圣杯布局。它将:
-
有一个自适应宽度的中间栏两个固定宽度的侧边栏
-
允许中心列首先出现在源代码中
-
允许任何列最高
-
只需要一个额外的div标记,以及
-
需要非常简单的CSS,带有最小的 hacks patches
站在巨人的肩膀上
这里提出的技术灵感来自Alex Robinson强大的一个真正的布局。亚历克斯甚至在他的文章中提到了圣杯问题,但是他的解决方案需要两个容器,并且在每列中没有相对应的div,这使得内边距的调整变得困难。
另一个线索来自Eric Meyer的改编,它使用定位来组合多个单元类型。他的例子还产生了一个三列布局固定的侧栏和液体中心。不幸的是,它依赖于近似百分比,并且填充了不同屏幕分辨率变化的视口的一部分。
话不多说--上代码
所需的HTML是直观和优雅的。
为了清楚地展示这种技术,我们有意使用非语义化的ID"centert"、“left”和“right”。我们建议您在使用该技术的任何应用程序中使用语义化ID。-Ed)
<div id="header"></div><div id="container">
<div id="center" class="column"></div>
<div id="left" class="column"></div>
<div id="right" class="column"></div></div><div id="footer"></div>
就是这样。一个额外的div包含列是你所需要的,这甚至满足了我强迫症的习惯。
样式表几乎一样简单。假设你想要有一个固定宽度为200px的左列和一个固定宽度为150px的右列。为了简化注释,我将分别将左、右和中心列缩写为LC、RC和CC。这里必不可少的CSS:
body {
min-width: 550px; /* 2x LC width + RC width */
}
#container {
padding-left: 200px; /* LC width */
padding-right: 150px; /* RC width */
}
#container .column {
position: relative;
float: left;
}
#center {
width: 100%;
background-color: pink;
}
#left {
width: 200px; /* LC width */
right: 200px; /* LC width */
margin-left: -100%;
background-color: black;
}
#right {
width: 150px; /* RC width */
margin-right: -150px; /* RC width */
background-color: black;
}
#footer {
clear: both;
}
/*** IE6 Fix ***/
* html #left {
left: 150px; /* RC width */
}
简单地用你想要的尺寸替换价值,圣杯就是你的。该技术适用于所有的现代浏览器:Safari,Opera,Firefox,和(与在底部的单一规则hack)IE6,IE5.5支持至少需要一个盒子模型HACK,它留给读者作为练习。
他是怎么工作的
这个策略很简单。容器DIV将有一个自适应的中心栏和固定宽度的侧边栏。诀窍是让左边的列与左边内边距对齐,右边的列与右边的内边距对齐,留下中心列来填充容器的自适应宽度。
让我们一步一步地建立起来。
1.建立框架
header,container,footer
<div id="header"></div>
<div id="container"></div>
<div id="footer"></div>
给container设置padding,这是给左右侧边栏预留空间
#container {
padding-left: 200px; /* LC width */
padding-right: 150px; /* RC width */
}
这个时候,我们的布局看起来是这样的(当然,如果布局中没有内容的话是不会显示的,你可以认为设置高度或者在div中加上一些字)
image.png2.添加列
我们现在已经有了大体的框架了,让我们来添加列吧!
<div id="header"></div>
<div id="container">
<div id="center" class="column"></div>
<div id="left" class="column"></div>
<div id="right" class="column"></div>
</div>
<div id="footer"></div>
接下来,我们添加适当的宽度并浮动它们以使它们保持一致。我们还需要给footer清除浮动,使其保持在浮动栏的下方。(记住啊,自己看效果的时候可以加颜色和高度啊!)
#container .column {
float: left;
}
#center {
width: 100%;
}
#left {
width: 200px; /* LC width */
}
#right {
width: 150px; /* RC width */
}
#footer {
clear: both;
}
这个时候我们看到的布局大概是下面这个样子的
image.png
注意,中心栏上的100%的宽度指的是容器DIV的宽度,不包括padding,所以不是把一整个页面占满的。
所有的列都按顺序排列,但是因为中心列占用了可用空间的100%,所以左右列都上不去,只能在下面待着。
3.把左列推到合适的位置
现在左列要做的唯一一件事情就是让左列与容器上的padding对齐。中心栏正好在需要的地方开始,所以我们将集中注意力在左边的列上。
需要两个步骤来实现左栏的位置。首先,我们将以一个100%的负边距拉它穿过中心栏。记住,100%是指容器的中心宽度,也正好是中心柱的宽度。
(因为他们都是浮动的~块级的他们就不会这样了,左列的上不去)
现在左边的列与中心栏重叠,共享了中心栏的左边。右柱向左浮动,与中心柱的右边缘紧紧挨在一起,留给我们如下:
为了在剩下的路径中推左边的列,我们将使用相对定位,偏移量正好是左栏的宽度。
#container .columns {
float: left;
position: relative;
}
#left {
width: 200px; /* LC width */
margin-left: -100%;
right: 200px; /* LC width */
}
right属性将它从右边缘推出200 px;也就是说,向左推。现在左边栏与容器的左padding完美地对齐。
image.png
6. 把右栏推到合适的位置
剩下的唯一任务就是把右栏拉到合适的位置。要做到这一点,我们只需要把它从容器中取出,放入容器的填充物中。我们将再次使用负值。
#right {
width: 150px; /* RC width */
margin-right: -150px; /* RC width */
}
现在所有东西都好啦~
image.png
7. 保守设计(调整)
如果调整浏览器窗口的大小,使得中心栏比左栏小,那么在符合标准的浏览器中,布局就会中断。在body上设置min-width可以保持列的位置。IE6不会发生这种情况,所以它不支持min-width也不是什么问题。
body {
min-width: 550px; /* 2x LC width + RC width */
}
当然,如果某种布局技术并不包含IE需要的某些方法,那么它就不是完整的(这句话高级黑啊),IE6中,负边距将左栏拖到左边的左边(浏览器窗口的全宽)。我们需要把它推回到右边栏的全部宽度-使用star-html hack来屏蔽其他浏览器-我们已经准备好了。
* html #left {
left: 150px; /* RC width */
}
我们需要使用右边列宽度的原因涉及代数。我不会让你知道细节,你可以自己解决问题,或者只是把它看作是IE的另一个魅力。
写在后面
讲了这么多,用flexbox简简单单就能实现弹性布局。
html
<body class="HolyGrail">
<header>...</header>
<div class="HolyGrail-body">
<main class="HolyGrail-content">...</main>
<nav class="HolyGrail-nav">...</nav>
<aside class="HolyGrail-ads">...</aside>
</div>
<footer>...</footer>
</body>
css
.HolyGrail {
display: flex;
min-height: 100vh;
flex-direction: column;
}
header,
footer {
flex: 1;
}
.HolyGrail-body {
display: flex;
flex: 1;
}
.HolyGrail-content {
flex: 1;
}
.HolyGrail-nav, .HolyGrail-ads {
/* 两个边栏的宽度设为12em */
flex: 0 0 12em;
}
.HolyGrail-nav {
/* 导航放到最左边 */
order: -1;
}
网友评论