Skip to content

精通 CSS - 高级 Web 标准解决方案 8. 布局

🏷️ 《精通 CSS - 高级 Web 标准解决方案》

所有 CSS 布局技术的根本都是 3 个基本概念:定位浮动外边距操纵

8.1 计划布局

布局时先做一些计划可以避免很多问题。

  1. 先把页面规划为大的结构性区域,比如容器、页眉、内容区域和页脚。
  2. 然后,将注意力转移到内容区域本身,开始建立网格结构。
  3. 最后,在各个内容区域中寻找不同的布局结构。

结构设计完之后,可以开始关注不同类型的内容。
查看每个内容块的结构,看看不同的类型中是否有共同的模式。
找出模式并确定命名规约之后,最好马上开始定义将使用的元素。

8.2 设置基本结构

典型的三列博客模板。

html
<body>
    <div class="wrapper">
        <div class="header">
            <!-- Your header content goes here -->
        </div>

        <div class="content">
            <!-- Your content content goes here -->
        </div>

        <div class="footer">
            <!-- Your footer content goes here -->
        </div>
    </div>
</body>

使用外边距让设计居中

设置主体 div 的宽度,并将水平外边距设置为 auto

css
.wrapper {
    width: 920px;
    margin: 0 auto;
}

8.3 基于浮动的布局

基于浮动的布局是最容易使用的,也是最可靠的。只需设置希望定位的元素的宽度,然后将它们向左或向右浮动。

因为浮动的元素不再占据文档流中的任何空间,它们就不再对包围它们的块框产生任何影响。为了解决这个问题,需要对布局中各个点上的浮动元素进行清理。非常常见的做法是浮动几乎所有东西,然后在整个文档的“战略点”(比如页脚)上进行一次或两次清理。还可以使用溢出方法清理某些元素的内容。

8.3.1 两列的浮动布局

html
<div class="content">
    <div class="primary">
        <!-- main content goes here -->
    </div>

    <div class="secondary">
        <!-- navigation and secondary content goes here -->
    </div>
</div>

为每个列设置想要的宽度,然后将次要内容向左浮动,将主要内容向右浮动。

css
/* 将主要内容向右浮动 */
.content .primary {
    width: 650px;
    padding-right: 20px;
    float: right;
    display: inline;
}
/* 将次要内容向左浮动 */
.content .secondary {
    width: 230px;
    float: left;
    display: inline;
}
/* 清除浮动 */
.content {
    overflow: hidden;
}

8.3.2 三列的浮动布局

和两列布局唯一的差异是在内容 div 中添加了两个新的 div:一个用于主内容,一个用于次要内容。

html
<div class="content">
    <div class="primary">
        <div class="primary">
            <!-- primary primary content goes here -->
        </div>
        <div class="secondary">
            <!-- secondary primary content goes here -->
        </div>
    </div>
    <div class="secondary">
        <!-- navigation and secondary content goes here -->
    </div>
</div>
css
.content .primary .primary {
    width: 400px;
    float: left;
    display: inline;
}
.content .prmary .secondary {
    width: 230px;
    float: right;
    display: inline;
}

8.4 固定宽度、流式和弹性布局

上面的两个布局都是固定宽度的布局。该布局比较常见,因为开发人员可以精确的定位元素的位置。
但缺陷也很明显,因为尺寸是固定的,导致无法适配各种分辨率的屏幕。另外更改浏览器的文本字号时可能会导致页面不易阅读。

8.4.1 流式布局

尺寸使用百分比而不是像素来设置。

问题:在窗口较窄时,行会变的非常窄。窗口太大时,也会导致行太宽,也同样不适合阅读。

css
/* 以整个页面宽度为基准计算出百分比 */
.wrapper {
    width: 76.8%;
    margin: 0 auto;
    text-align: left;
    /* 为了确保窗口过大或过小时页面文本也适合阅读,最好以 em 为单位设置最大和最小宽度 */
    max-width: 125em;
    min-width: 62em;
}
.content .primary {
    width: 72.82%;
    float: right;
    display: inline;
}
.content .secondary {
    width: 25%;
    float: left;
    display: inline;
}
/* 以主要内容的宽度为基准计算百分比 */
.content .primary .primary {
    width: 59.7%;
    float: left;
    display: inline;
}
.content .primary .secondary {
    width: 34.33%;
    padding-right: 2.63%;
    float: right;
    display: inline;
}

8.4.2 弹性布局

弹性布局相对于字号(而不是浏览器宽度)来设置元素的宽度。以 em 为单位设置宽度。

问题:不能充分利用可用空间。另外字号增大时整个布局会加大,进而导致水平滚动条出现。需要在容器 div 上设置 max-width

将固定宽度布局转换为弹性布局是相对简单的任务。技巧是要设置基字号,让 1em 大致相当于 10px
大多数浏览器上的默认字号是 16px,10px 大约是 16px 的 62.5%,所以在主题上将字号设置为 62.5% 。

css
body {
    font-size: 62.5%;
    text-align: center;
}
.wrapper {
    width: 92em;
    max-width: 95%;
    margin: 0 auto;
    text-align: left;
}
/* 内部宽度仍然使用百分比 */
.content .primary {
    width: 72.82%;
    float: right;
    display: inline;
}
.content .secondary {
    width: 25%;
    float: left;
    display: inline;
}
.content .primary .primary {
    width: 59.7%;
    float: left;
    display: inline;
}
.content .primary .secondary {
    width: 34.33%;
    padding-right: 2em;
    float: right;
    display: inline;
}

现代浏览器很多都已支持页面缩放了。

8.4.3 流式和弹性图像

使用流式或单行布局,固定宽度的图像会对设计产生强烈的影响。

对于需要跨越大区域的图像,比如站点页眉或品牌区域中的图像,可以考虑率使用背景图像而不是图片元素。

css
#branding {
    height: 171px;
    background: url(/img/branding.png) no-repeat left top;
}
html
<div id="branding"></div>

如果图像需要用作页面上的图像元素,需要将宽度设置为 100% 并且将 overflow 设置为 hidden

css
#branding {
    width: 100%;
    overflow: hidden;
}
html
<div id="branding">
    <img src="/img/branding" width="1600" height="171" />
</div>

对于常规内容图片,你可能希望它们可以水平和垂直伸缩。

css
.news img {
    /* 设置图片的宽度为百分比,这样就可以实现自动伸缩 */
    width: 25%;
    /* 设置最大宽度,以避免图像失真 */
    max-width: 200px;
    float: left;
    display: inline;
    padding: 2%;
}
.news p {
    width: 68%;
    float: right;
    display: inline;
    padding: 2% 2% 2% 0;
}

8.5 faux 列

每个区域由于内部元素的高度各不相同,会导致背景色没有渲染到整列。
对策是在一个占据布局最大高度的元素(比如一个容器 div)上应用重复的背景图像。

css
#wrapper {
    background: #fff url(/img/nav-bg-fixwd.gif) repeat-y left top;
}

对于流式或弹性布局时,则需要多张背景图片分别按照百分比进行定位。

css
.wrapper {
    background: #fff url(/img/secondary-faux-column.gif) repeat-y 25% 0;
}
.inner-wrapper {
    background: #fff url(/img/primary-faux-column.gif) repeat-y 72.82% 0;
}

8.6 高度相等的列

使用表格很容易实现这种效果,但是 CSS 中实现需要一点技巧。

html
<div class="wrapper">
    <div class="box">
        <p>狩魔猎人</p>
        <p>...</p>
        <div class="bottom"></div>
    </div>
    <div class="box">
        <p>秘术师</p>
        <p>...</p>
        <div class="bottom"></div>
    </div>
    <div class="box">
        <p>圣教军</p>
        <p>...</p>
        <div class="bottom"></div>
    </div>
</div>
css
.wrapper {
    width: 100%;
}
.box {
    width: 250px;
    margin-left: 20px;
    float: left;
    display: inline;
    padding: 20px;
    background: #89ac10 url(/img/top.gif) no-repeat left top;
}

这会产生 3 个高度不一致的列。

这种技术的关键是给每个框设置大的底内边距,然后用数值相似的负外边距消除这个高度。

css
.wrapper {
    width: 100%;
    overflow: hidden;
}
.box {
    width: 250px;
    padding-left: 20px;
    padding-right: 20px;
    padding-top: 20px;
    padding-bottom: 520px;
    margin-bottom: -500px;
    margin-left: 20px;
    floatL left;
    display: inline;
    background: #89ac10 url(/img/top.gif) no-repeat left top;
}

为了把列的底边定位在正确的位置,需要让它们与容器元素的底部对齐。
为此,首先把容器的 position 设置为 relative。然后把 bottomposition 设置为 absolute,把它们的 bottom 属性设置为 0。

css
.wrapper {
    width: 100%;
    overflow: hidden;
    position: relative;
}
.bottom {
    position: absolute;
    bottom: 0;
    height: 20px;
    width: 290px;
    background: url(/img/bottom.gif) #89ac10 bottom left no-repeat;
    margin-left: -20px;
}

8.7 CSS 3 列

CSS 3 也可以创建等高文本列,这要通过 column-countcolumn-widthcolumn-gap 属性实现。

html
<p>狩魔猎人</p>
<div class="col">
    <p>...</p>
</div>
css
.col {
    -moz-column-count: 3;
    -moz-column-width: 14em;
    -moz-column-gap: 2em;
    -moz-column-rule: 1px solid #ccc;
    -webkit-column-count: 3;
    -webkit-column-width: 14em;
    -webkit-column-gap: 2em;
    -webkit-column-rule: 1px solid #ccc;
    column-count: 3;
    column-width: 14em;
    column-gap: 2em;
    column-rule: 1px solid #ccc;
}

8.8 CSS 框架与 CSS 系统

CSS 框架 的目标是简化 CSS 的使用,帮助用户方便地创建各种常用的布局,而不需要编辑底层的 CSS。如 YUI Griids、Blueprint 和 960 等。
但其也有缺点,会改变编写标记的方式,破坏变现和意义的分离;要求在设计中必须使用特定的网格结构。

CSS 系统 实际上是一个工具箱,其中包含可重用的样式和标记模式,可以用它开发站点专用的框架。
工具箱可以包含全局 reset、排版样式和表单处理,以及登录表单、日历表格和导航列表等常用 HTML 组件的标记模式。然后再开发作为定制框架使用的系统。

附 1. 引用

  1. 《精通 CSS - 高级 Web 标准解决方案(第 2 版)》 - Andy Budd, Simon Collison, Cameron Moll 著;陈剑瓯 译。

本书后面还有 3 章,分别讲了 bug 的发现与修复方法 和 两个作者写的示例及其用到的一些未来可能会实装的 CSS 特性(由于这本书买的比较早,现在看来常用的浏览器都已经支持这些新的特性了)。
这里就不再继续写了。有兴趣的同学可以买书看一下。

9. bug 和 修复 bug
10. 实例研究:Roma Italia
11. 实例研究:Climb the Mountains