Learn web development

Introduction to CSS layout

本文将介绍我们以前模块中已经介绍过的一些CSS布局特性 ... 例如不同的display值,并介绍我们将在本单元中介绍的一些概念。

前提条件: 对HTML有一些基本的了解 (学习“HTML介绍”), 并且理解CSS的工作原理 (学习“CSS介绍”).
目标: 对CSS页面布局技术有一个总体的了解. 每种技术都能够在后面的教程中获取到更加详细的信息.

CSS页面布局技术允许我们拾取网页中的元素,并且控制它们相对正常布局流、周边元素、父容器或者主视口/窗口的位置. 在这个模块中将覆盖更多页面布局技术的细节:

  • 块布局 (浮动, 多栏)
  • 行内
  • 定位
  • 表格
  • 弹性盒子
  • 网格

 

每种技术都有它们的用途,各有优缺点.

正常布局流

正常布局流是指在不对页面进行任何布局控制时,浏览器默认的HTML布局方式. 让我们快速地看一个HTML的例子:

<p>I love my cat.</p>
<ul>
  <li>Buy cat food</li>
  <li>Exercise</li>
  <li>Cheer up friend</li>
</ul>
<p>The end!</p>

默认情况下,浏览器的显示如下:

注意,HTML元素完全按照源码中出现的先后次序显示——第一个段落、无序列表、第二个段落.

布局技术会覆盖默认的布局行为:

  • position 属性 — 正常布局流中,默认为 static , 改为其它值会影响布局效果, 例如将元素固定到浏览器窗口的左上角.
  • Floats — 应用 float 值,如 left 能够让块级元素水平排成一行, 而不是垂直排放.
  •  display 属性 — 标准值 block, inline or inline-block 会改变元素在正常布局流中的行为(见 Types of CSS boxes ), 而一些不常见或特殊的值允许我们使用完全不同的方式进行布局,比如Flexbox.

浮动

浮动技术允许元素浮动到另外一个元素的左侧或右侧,而不是第一个叠一个. float 的主要用途是水平排列元素或让文字环绕图片. 下面我们快速浏览一下 float 属性并通过一个例子来说明.

 float 属性有四个可能的值:

  • left — 将元素浮动到左侧.
  • right — 将元素浮动到右侧.
  • none — 默认值, 不浮动.
  • inherit — 继承父元素的浮动属性.

简单HTML示例

下面展示了如何用浮动来创建一个简单的两列布局. 首先看一下HTML:

<h1>2 column layout example</h1>
<div>
  <h2>First column</h2>
  <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p>
</div>
<div>
  <h2>Second column</h2>
  <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut.</p>
</div>

代码中有一个一级标题和两个简单的 <div> 元素. 每个 <div> 元素又各自包含一个二级标题和一个段落. 默认情况下, HTML内容自上而下显示:

整列浮动

下面让我们将两个 <div> 元素排成一行. 下面的代码可以实现这个效果. 注意这两个 <div> 一个的 float 值为 left, 另外一个 float 为 right. 这意味着它们其中一个往左靠,另外一个往右靠. 给这两个元素分别设置 width 值,使得它们能够在同一行放下来,并且设置一个水平的间距(总宽度不要大于100!).

div:nth-of-type(1) {
  width: 48%;
  float: left;
}
div:nth-of-type(2) {
  width: 48%;
  float: right;
}

修改过的代码如下:

注意: 学习更多关于 CSS 浮动的知识,参见我们关于浮动的文章.

定位技术

定位技术(position)允许我们将一个元素从它在页面的原始位置准确地移动到另外一个位置.

有四种主要的定位类型需要我们了解:

  • 静态定位(static)是每个元素默认的属性——它表示“将元素放在文档布局流的默认位置——没有什么特殊的地方”.
  • 相对定位(relative)允许我们相对元素在正常的文档流中的位置移动它——包括将两个元素叠放在页面上. 相对定位在对布局进行微调的时候非常有用. 
  • 绝对定位(absolute)将元素完全从页面的正常布局流中移出, 类似将它单独放在一个图层中. 我们可以将元素相对页面的 <html> 元素边缘固定(或者它最近的被定位的上层元素). 绝对定位在创建复杂布局效果时非常有用,例如通过标签显示和隐藏的内容面板或者通过按钮控制滑动到屏幕中的信息面板.
  • 固定定位(fixed)与绝对定位非常类似, 除了它是将一个元素相对浏览器视口固定,而不是相对另外一个元素. 在创建类似页面滚动总是处于页面上方的导航菜单时非常有用. 

简单定位示例

我们将展示一些示例代码来熟悉这些布局技术. 这些示例代码都作用在相同的HTML上: 

<h1>Positioning</h1>
<p>I am a basic block level element.</p>
<p class="positioned">I am a basic block level element.</p>
<p>I am a basic block level element.</p>

This HTML will be styled by default using the following CSS:

body {
  width: 500px;
  margin: 0 auto;
}
p {
  background: aqua;
  border: 3px solid blue;
  padding: 10px;
  margin: 10px;
}
span {
  background: red;
  border: 1px solid black;
}

渲染效果如下:

相对定位

相对定位通常用来对布局进行微调,比如将一个图标往下调一点,以便放置文字. 我们可以通过下面的规则添加相对定位来实现效果: 

.positioned {
  position: relative;
  background: yellow;
  top: 30px;
  left: 30px;
}

Here we give our middle paragraph a position value of relative — this doesn't do anything on its own, so we also add top and left properties. These serve to move the affected element down and to the right — this might seem like the opposite of what you were expecting, but you need to think of it as the element being pushed on it's left and top sides, which result in it moving right and down.

Adding this code will give the following result:

Absolute Positioning

Absolute positioning is used to move your elements anywhere around the web page, to create complex layouts. Interestingly, it is often used work in concert with relative positioning and floats.

Going back to our original non-positioned example, we could add the following CSS rule to implement absolute positioning:

.positioned {
  position: absolute;
  background: yellow;
  top: 30px;
  left: 30px;
}

Here we give our middle paragraph a position value of absolute, and the same top and left properties as before. The result however, Adding this code will give the following result:

This is very different! The positioned element has now been completely separated from the rest of the page layout, and sits over the top of it. The other two paragraphs now sit together as if their positioned sibling doesn't exist. The top and left properties have a different effect on absolutely positioned elements than they do on relatively positioned elements. In this case they don't specify how much the element moves relative to its original position; instead they specify  the distance the element should sit from the top and left sides of the page's boundaries (the <html> element, to be exact).

We'll leave fixed positioning for now — it basically works in the same way, except that it remains fixed to the browser viewport's edges, not its positioned parent's edges.

Note: to find more out about positioning, see our Positioning and Practical positioning examples articles.

CSS tables

HTML tables are fine for displaying tabular data, but many years ago — before even basic CSS was supported reliably across browsers — web developers used to also use tables for entire web page layouts — putting their headers, footers, different columns, etc. in various table rows and columns. This worked at the time, but it has many problems — table layouts are inflexible, very heavy on markup, difficult to debug, and semantically wrong (e.g. screen reader users have problems navigating table layouts).

CSS tables exist to allow you to layout elements like they were a table, without any of the issues described above — this may sound strange, and you should use table elements for tabular data, but sometimes this can be useful. For example, you might want to lay out a form with the labels and text inputs lined up; this can be tricky, but CSS tables make it easy.

Let's look at an example. First, some simple markup that creates an HTML form. Each input element has a label, and we've also included a caption inside a paragraph. Each label/input pair is wrapped in a <div>, for layout purposes.

<form>
  <p>First of all, tell us your name and age.</p>
  <div>
    <label for="fname">First name:</label>
    <input type="text" id="fname">
  </div>
  <div>
    <label for="lname">Last name:</label>
    <input type="text" id="lname">
  </div>
  <div>
    <label for="age">Age:</label>
    <input type="text" id="age">
  </div>
</form>

Now, the CSS for our example. Most of the CSS is fairly ordinary, except for the uses of the display property. The <form>, <div>s, and <label>s and <input>s have been told to display like a table, table rows, and table cells respectively — basically they'll act like HTML table markup, causing the labels and inputs to nicely line up by default. All we then have to do is add a bit of sizing, margin, etc. to make everything look a bit nicer and we're done.

You'll notice that the caption paragraph has been given display: table-caption; — which makes it act like a table <caption> — and caption-side: bottom; to tell the caption to sit on the bottom of the table for styling purposes, even though the markup is before the inputs in the source. This allows for a nice bit of flexbiility.

html {
  font-family: sans-serif;
}
form {
  display: table;
  margin: 0 auto;
}
form div {
  display: table-row;
}
form label, form input {
  display: table-cell;
  margin-bottom: 10px;
}
form label {
  width: 200px;
  padding-right: 5%;
  text-align: right;
}
form input {
  width: 300px;
}
form p {
  display: table-caption;
  caption-side: bottom;
  width: 300px;
  color: #999;
  font-style: italic;
}

This gives us the following result:

You can also see this example live at css-tables-example.html (see the source code too.)

Note: We won't cover CSS tables in any more detail in this module.

Flexible boxes

CSS is a powerful language that can do many things, but it has traditionally fallen down in terms of layout. Traditional old-fashioned layout methods like float and positioning work, but sometimes they feel more complex, fiddly, inflexible and hacky than they need to be. For example, what if you wanted to:

  • Vertically center a box of content (not just text; line-height won't work).
  • Make several columns containing different amounts of content have the same height, without using a fixed height, or faking it with background images.
  • Make several boxes in a line take up the same amount of the available space, regardless of how many of them there are, and if they have padding, margin, etc. applied.

The examples above are pretty much impossible to achieve with regular CSS — Flexible boxes (or flexbox) was invented to allow such things to be more easily achieved.

Let's look at an example; first, some simple HTML:

<section>
  <div>This is a box</div>
  <div>This is a box</div>
  <div>This is a box</div>
</section>
<button class="create">Create box</button>
<button class="reset">Reset demo</button>

Here we've got a <section> element with three <div>s inside, plus a couple of buttons to create a new box, and reset the demo. By default, the child elements would not be laid out or sized at all, and using old traditional methods we'd have to carefully size each one, allowing for width, padding, border and margin, and if we added another child element we'd have to completely change all the values.

Let's instead do this with Flexbox:

html {
  font-family: sans-serif;
}
section {
  width: 93%;
  height: 240px;
  margin: 20px auto;
  background: purple;
  display: flex;
}
div {
  color: white;
  background: orange;
  flex: 1;
  margin-right: 10px;
  text-shadow: 1px 1px 1px black;
}
div:last-child {
  margin-right: 0;
}
section, div {
  border: 5px solid rgba(0,0,0,0.85);
  padding: 10px;
}

Two lines of this CSS are really interesting:

  • display: flex; tells the <section> element's children to be laid out as flexible boxes — by default, they will all stretch to fill the available height of the parent, whatever that is, and be laid out in a row — with enough width to wrap their content.
  • flex: 1; tells each <div> element to take up an equal amount of the space available in the row, no matter how many there are.

To illustrate further how amazing this is, we'll also add a little JavaScript so that you can add further child <div>s  by pressing the Create box button. You can also reset the demo if you add too many <div>s, by pressing the Reset demo button.

Here's the example live — have a play, to witness how powerful Flexbox is as a layout tool.

You can also find this demo at flexbox-example.html (see also the source code).

Note: To find more out about Flexbox, see our Flexbox article.

Grid layout

The most experimental feature to mention here is CSS Grids, which aren't supported very widely across browsers yet. Web pages are often laid out using grid systems, in the same manner as print media, and the idea here is to make this process easier and more natural, by defining a grid, and then defining which parts of the content sit within each area of the grid.

CSS Grids in their present state aren't really supported anywhere yet (except in experimental versions of Firefox and Chrome). IE and Edge support an older, obsolete version of the technology. This is something we can look forward to in the future!

Note: To find more out about the current grid frameworks and other technologies in use today, and the upcoming native CSS Grids specification, see our Grids article.

Summary

This article has provided a brief summary of all the layout technologies you should know about. Read on for more information on each individual technology!

https://developer.mozilla.org/zh-CN/docs/Web/CSS/Layout_mode

文档标签和贡献者