传统的布局方法

网格系统是 CSS 布局中非常常见的功能,在 CSS 网格布局出现之前,它们往往使用浮动或其他布局功能来实现。你将布局想象为一定数量的列(例如 4、6 或 12),然后将内容列放入这些假想的列中。在本文中,我们将探讨这些旧方法的工作原理,以便你了解在处理旧项目时如何使用它们。

¥Grid systems are a very common feature used in CSS layouts, and before CSS Grid Layout they tended to be implemented using floats or other layout features. You imagine your layout as a set number of columns (e.g. 4, 6, or 12), and then fit your content columns inside these imaginary columns. In this article we'll explore how these older methods work, in order that you understand how they were used if you work on an older project.

先决条件: HTML 基础知识(研究 HTML 简介),以及 CSS 工作原理的概念(研究 CSS 简介样式盒)。
目标: 了解在 CSS 网格布局在浏览器中可用之前使用的网格布局系统背后的基本概念。

CSS 网格布局之前的布局和网格系统

¥Layout and grid systems before CSS Grid Layout

对于任何有设计背景的人来说,CSS 直到最近才具有内置网格系统,这可能会让人感到惊讶,相反,我们似乎正在使用各种次优方法来创建类似网格的设计。我们现在将这些称为 "legacy" 方法。

¥It may seem surprising to anyone coming from a design background that CSS didn't have an inbuilt grid system until very recently, and instead we seemed to be using a variety of sub-optimal methods to create grid-like designs. We now refer to these as "legacy" methods.

对于新项目,大多数情况下 CSS 网格布局将与一种或多种其他现代布局方法结合使用,形成任何布局的基础。然而,你有时会遇到使用这些遗留方法的 "网格系统"。值得了解它们的工作原理以及它们与 CSS 网格布局的不同之处。

¥For new projects, in most cases CSS Grid Layout will be used in combination with one or more other modern layout methods to form the basis for any layout. You will however encounter "grid systems" using these legacy methods from time to time. It is worth understanding how they work, and why they are different to CSS Grid Layout.

本课将解释基于浮动和弹性盒的网格系统和网格框架如何工作。研究过网格布局后,你可能会惊讶地发现这一切看起来多么复杂!如果你需要为不支持较新方法的浏览器创建后备代码,这些知识除了允许你处理使用这些类型系统的现有项目外,还将对你有所帮助。

¥This lesson will explain how grid systems and grid frameworks based on floats and flexbox work. Having studied Grid Layout you will probably be surprised how complicated this all seems! This knowledge will be helpful to you if you need to create fallback code for browsers that do not support newer methods, in addition to allowing you to work on existing projects which use these types of systems.

值得记住的是,当我们探索这些系统时,它们实际上都没有像 CSS 网格布局创建网格那样创建网格。他们的工作方式是给项目一个尺寸,然后推动它们以看起来像网格的方式排列。

¥It is worth bearing in mind, as we explore these systems, that none of them actually create a grid in the way that CSS Grid Layout creates a grid. They work by giving items a size, and pushing them around to line them up in a way that looks like a grid.

两列布局

¥A two column layout

让我们从最简单的示例开始 - 两列布局。你可以在计算机上创建一个新的 index.html 文件,用 简单的 HTML 模板 填充该文件,然后在适当的位置插入以下代码。在本节的底部,你可以看到最终代码应该是什么样子的实时示例。

¥Let's start with the simplest possible example — a two column layout. You can follow along by creating a new index.html file on your computer, filling it with a simple HTML template, and inserting the below code into it at the appropriate places. At the bottom of the section you can see a live example of what the final code should look like.

首先,我们需要将一些内容放入专栏中。将当前体内的内容替换为以下内容:

¥First of all, we need some content to put into our columns. Replace whatever is inside the body currently with the following:

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. Duis felis orci,
    pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at
    ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer
    ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur
    vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus.
    Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus
    sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus.
    Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis,
    eget fermentum sapien.
  </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, facilisis sed
    est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus
    tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies
    lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis
    vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque
    penatibus et magnis dis parturient montes, nascetur ridiculus mus.
  </p>
</div>

每一列都需要一个外部元素来包含其内容,并让我们一次操作所有内容。在此示例中,我们选择了 <div>,但你可以选择语义上更合适的内容,例如 <article><section><aside> 等。

¥Each one of the columns needs an outer element to contain its content and let us manipulate all of it at once. In this example case we've chosen <div>s, but you could choose something more semantically appropriate like <article>s, <section>s, and <aside>, or whatever.

现在介绍 CSS。首先,将以下内容应用到 HTML 以提供一些基本设置:

¥Now for the CSS. First, of all, apply the following to your HTML to provide some basic setup:

css
body {
  width: 90%;
  max-width: 900px;
  margin: 0 auto;
}

主体宽度将占视口宽度的 90%,直到宽度达到 900px,在这种情况下,它将保持固定在该宽度,并在视口中居中。默认情况下,其子项(h1 和两个 <div>)将跨越主体宽度的 100%。如果我们希望两个 <div> 并排浮动,我们需要将它们的宽度设置为其父元素宽度的 100% 或更小,以便它们可以并排放置。将以下内容添加到 CSS 底部:

¥The body will be 90% of the viewport wide until it gets to 900px wide, in which case it will stay fixed at this width and center itself in the viewport. By default, its children (the h1 and the two <div>s) will span 100% of the width of the body. If we want the two <div>s to be floated alongside one another, we need to set their widths to total 100% of the width of their parent element or smaller so they can fit alongside one another. Add the following to the bottom of your CSS:

css
div:nth-of-type(1) {
  width: 48%;
}

div:nth-of-type(2) {
  width: 48%;
}

在这里,我们将两者都设置为父级宽度的 48%,总共为 96%,留出 4% 的空间作为两列之间的装订线,为内容提供一些喘息的空间。现在我们只需要浮动列,如下所示:

¥Here we've set both to be 48% of their parent's width — this totals 96%, leaving us 4% free to act as a gutter between the two columns, giving the content some space to breathe. Now we just need to float the columns, like so:

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

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

把这些放在一起应该给我们一个像这样的结果:

¥Putting this all together should give us a result like so:

你会注意到,我们对所有宽度都使用百分比 - 这是一个非常好的策略,因为它创建了一种液体布局,可以根据不同的屏幕尺寸进行调整,并在较小的屏幕尺寸下保持列宽的相同比例。尝试调整浏览器窗口的宽度来亲自查看。这是响应式网页设计的一个有价值的工具。

¥You'll notice here that we are using percentages for all the widths — this is quite a good strategy, as it creates a liquid layout, one that adjusts to different screen sizes and keeps the same proportions for the column widths at smaller screen sizes. Try adjusting the width of your browser window to see for yourself. This is a valuable tool for responsive web design.

注意:你可以看到此示例在 0_two-column-layout.html 上运行(另请参阅 源代码)。

¥Note: You can see this example running at 0_two-column-layout.html (see also the source code).

创建简单的遗留网格框架

¥Creating simple legacy grid frameworks

大多数遗留框架使用 float 属性的行为将一列浮动到另一列旁边,以创建看起来像网格的东西。通过使用浮动创建网格的过程,你将了解其工作原理,并介绍一些更高级的概念,以构建你在 浮动和清理 课程中学到的知识。

¥The majority of legacy frameworks use the behavior of the float property to float one column up next to another in order to create something that looks like a grid. Working through the process of creating a grid with floats shows you how this works and also introduces some more advanced concepts to build on the things you learned in the lesson on floats and clearing.

最容易创建的网格框架类型是固定宽度的网格框架 - 我们只需要计算出我们想要的设计总宽度是多少,我们想要多少列,以及装订线和列应该有多宽。如果我们决定将我们的设计布局在一个网格上,其中的列根据浏览器宽度而增长和缩小,我们将需要计算列和它们之间的间距的百分比宽度。

¥The easiest type of grid framework to create is a fixed width one — we just need to work out how much total width we want our design to be, how many columns we want, and how wide the gutters and columns should be. If we instead decided to lay out our design on a grid with columns that grow and shrink according to browser width, we would need to calculate percentage widths for the columns and gutters between them.

在接下来的部分中,我们将了解如何创建两者。我们将创建一个 12 列网格 - 这是一个非常常见的选择,考虑到 12 可以很好地被 6、4、3 和 2 整除,因此它非常适合不同的情况。

¥In the next sections we will look at how to create both. We will create a 12 column grid — a very common choice that is seen to be very adaptable to different situations given that 12 is nicely divisible by 6, 4, 3, and 2.

一个简单的固定宽度网格

¥A simple fixed width grid

让我们首先创建一个使用固定宽度列的网格系统。

¥Lets first create a grid system that uses fixed width columns.

首先制作示例 simple-grid.html 文件的本地副本,该文件的正文中包含以下标记。

¥Start out by making a local copy of our sample simple-grid.html file, which contains the following markup in its body.

html
<div class="wrapper">
  <div class="row">
    <div class="col">1</div>
    <div class="col">2</div>
    <div class="col">3</div>
    <div class="col">4</div>
    <div class="col">5</div>
    <div class="col">6</div>
    <div class="col">7</div>
    <div class="col">8</div>
    <div class="col">9</div>
    <div class="col">10</div>
    <div class="col">11</div>
    <div class="col">12</div>
  </div>
  <div class="row">
    <div class="col span1">13</div>
    <div class="col span6">14</div>
    <div class="col span3">15</div>
    <div class="col span2">16</div>
  </div>
</div>

目的是将其变成十二列网格上两行的演示网格 - 第一行展示各个列的大小,第二行展示网格上一些不同大小的区域。

¥The aim is to turn this into a demonstration grid of two rows on a twelve column grid — the top row demonstrating the size of the individual columns, the second row some different sized areas on the grid.

CSS grid with 16 grid items spread across twelve columns and two rows. The top row has 12 equal-width grid items in 12 columns. The second row has different-sized grid items. Item 13 spans 1 column, item 14 spans six columns, 15 spans three, and 16 spans two.

<style> 元素中,添加以下代码,使封装器容器的宽度为 980 像素,右侧填充 20 像素。这使得我们的总列/装订线宽度为 960 像素 - 在这种情况下,从总内容宽度中减去填充,因为我们已在网站上的所有元素上将 box-sizing 设置为 border-box(有关更多说明,请参阅 另一种 CSS 盒模型)。

¥In the <style> element, add the following code, which gives the wrapper container a width of 980 pixels, with padding on the right-hand side of 20 pixels. This leaves us with 960 pixels for our total column/gutter widths — in this case, the padding is subtracted from the total content width because we have set box-sizing to border-box on all elements on the site (see The alternative CSS box model for more explanation).

css
* {
  box-sizing: border-box;
}

body {
  width: 980px;
  margin: 0 auto;
}

.wrapper {
  padding-right: 20px;
}

现在,使用包围网格每一行的行容器来清除另一行。在前一条规则下方添加以下规则:

¥Now use the row container that is wrapped around each row of the grid to clear one row from another. Add the following rule below your previous one:

css
.row {
  clear: both;
}

应用此清除意味着我们不需要用元素完全填充每一行以构成完整的十二列。行将保持分开,并且不会相互干扰。

¥Applying this clearing means that we don't need to completely fill each row with elements making the full twelve columns. The rows will remain separated, and not interfere with each other.

列之间的装订线宽度为 20 像素。我们将这些装订线创建为每列(包括第一列)左侧的边距,以平衡容器右侧的 20 像素内边距。所以我们总共有 12 个装订线 — 12 x 20 = 240。

¥The gutters between the columns are 20 pixels wide. We create these gutters as a margin on the left side of each column — including the first column, to balance out the 20 pixels of padding on the right-hand side of the container. So we have 12 gutters in total — 12 x 20 = 240.

我们需要从 960 像素的总宽度中减去它,为我们的列提供 720 像素。如果我们现在将其除以 12,我们就知道每列的宽度应为 60 像素。

¥We need to subtract that from our total width of 960 pixels, giving us 720 pixels for our columns. If we now divide that by 12, we know that each column should be 60 pixels wide.

我们的下一步是为 .col 类创建一条规则,使其向左浮动,为其提供 20 像素的 margin-left 来形成装订线,以及 60 像素的 width。将以下规则添加到 CSS 底部:

¥Our next step is to create a rule for the class .col, floating it left, giving it a margin-left of 20 pixels to form the gutter, and a width of 60 pixels. Add the following rule to the bottom of your CSS:

css
.col {
  float: left;
  margin-left: 20px;
  width: 60px;
  background: rgb(255 150 150);
}

最上面一行的单列现在将整齐地布局为网格。

¥The top row of single columns will now lay out neatly as a grid.

注意:我们还为每列赋予了浅红色,以便你可以准确地看到每列占用了多少空间。

¥Note: We've also given each column a light red color so you can see exactly how much space each one takes up.

我们想要跨越多列的布局容器需要指定特殊的类,以将其 width 值调整为所需的列数(加上中间的间距)。我们需要创建一个额外的类来允许容器跨越 2 到 12 列。每个宽度都是该列数的列宽加上装订线宽度的结果,装订线宽度始终比列数少一。

¥Layout containers that we want to span more than one column need to be given special classes to adjust their width values to the required number of columns (plus gutters in between). We need to create an additional class to allow containers to span 2 to 12 columns. Each width is the result of adding up the column width of that number of columns plus the gutter widths, which will always number one less than the number of columns.

在 CSS 底部添加以下内容:

¥Add the following at the bottom of your CSS:

css
/* Two column widths (120px) plus one gutter width (20px) */
.col.span2 {
  width: 140px;
}
/* Three column widths (180px) plus two gutter widths (40px) */
.col.span3 {
  width: 220px;
}
/* And so on… */
.col.span4 {
  width: 300px;
}
.col.span5 {
  width: 380px;
}
.col.span6 {
  width: 460px;
}
.col.span7 {
  width: 540px;
}
.col.span8 {
  width: 620px;
}
.col.span9 {
  width: 700px;
}
.col.span10 {
  width: 780px;
}
.col.span11 {
  width: 860px;
}
.col.span12 {
  width: 940px;
}

创建这些类后,我们现在可以在网格上布置不同宽度的列。尝试在浏览器中保存并加载页面以查看效果。

¥With these classes created we can now lay out different width columns on the grid. Try saving and loading the page in your browser to see the effects.

注意:如果你在使用上面的示例时遇到问题,请尝试将其与 GitHub 上的 成品版(也包括 看到它实时运行)进行比较。

¥Note: If you are having trouble getting the above example to work, try comparing it against our finished version on GitHub (see it running live also).

尝试修改元素上的类,甚至添加和删除一些容器,看看如何改变布局。例如,你可以使第二行看起来像这样:

¥Try modifying the classes on your elements or even adding and removing some containers, to see how you can vary the layout. For example, you could make the second row look like this:

html
<div class="row">
  <div class="col span8">13</div>
  <div class="col span4">14</div>
</div>

现在你已经有了一个正在运行的网格系统,你可以定义行和每行中的列数,然后用所需的内容填充每个容器。很棒的!

¥Now you've got a grid system working, you can define the rows and the number of columns in each row, then fill each container with your required content. Great!

创建流体网格

¥Creating a fluid grid

我们的网格工作得很好,但它有固定的宽度。我们确实想要一个灵活的(流动的)网格,它会随着浏览器中的可用空间而增长和缩小 viewport。为了实现这一点,我们可以将参考像素宽度转换为百分比。

¥Our grid works nicely, but it has a fixed width. We really want a flexible (fluid) grid that will grow and shrink with the available space in the browser viewport. To achieve this we can turn the reference pixel widths into percentages.

将固定宽度转换为基于百分比的灵活宽度的公式如下。

¥The equation that turns a fixed width into a flexible percentage-based one is as follows.

target / context = result

对于我们的列宽,我们的目标宽度是 60 像素,我们的上下文是 960 像素封装器。我们可以使用以下公式来计算百分比。

¥For our column width, our target width is 60 pixels and our context is the 960 pixel wrapper. We can use the following to calculate a percentage.

60 / 960 = 0.0625

然后我们将小数点移动 2 位,得到 6.25% 的百分比。因此,在我们的 CSS 中,我们可以将 60 像素的列宽替换为 6.25%。

¥We then move the decimal point 2 places giving us a percentage of 6.25%. So, in our CSS we can replace the 60 pixel column width with 6.25%.

我们需要对装订线宽度做同样的事情:

¥We need to do the same with our gutter width:

20 / 960 = 0.02083333333

因此,我们需要将 .col 规则上的 20 像素 margin-left.wrapper 上的 20 像素 padding-right 替换为 2.08333333%。

¥So we need to replace the 20 pixel margin-left on our .col rule and the 20 pixel padding-right on .wrapper with 2.08333333%.

更新我们的网格

¥Updating our grid

要开始本部分,请为之前的示例页面创建一个新副本,或者为我们的 simple-grid-finished.html 代码创建一个本地副本以用作起点。

¥To get started in this section, make a new copy of your previous example page, or make a local copy of our simple-grid-finished.html code to use as a starting point.

更新第二个 CSS 规则(使用 .wrapper 选择器),如下所示:

¥Update the second CSS rule (with the .wrapper selector) as follows:

css
body {
  width: 90%;
  max-width: 980px;
  margin: 0 auto;
}

.wrapper {
  padding-right: 2.08333333%;
}

我们不仅为其指定了百分比 width,还添加了 max-width 属性,以防止布局变得太宽。

¥Not only have we given it a percentage width, we have also added a max-width property in order to stop the layout becoming too wide.

接下来,更新第四个 CSS 规则(使用 .col 选择器),如下所示:

¥Next, update the fourth CSS rule (with the .col selector) like so:

css
.col {
  float: left;
  margin-left: 2.08333333%;
  width: 6.25%;
  background: rgb(255 150 150);
}

现在是稍微费力的部分 - 我们需要更新所有 .col.span 规则以使用百分比而不是像素宽度。使用计算器这需要一些时间;为了节省你的精力,我们在下面为你完成了这项工作。

¥Now comes the slightly more laborious part — we need to update all our .col.span rules to use percentages rather than pixel widths. This takes a bit of time with a calculator; to save you some effort, we've done it for you below.

使用以下内容更新 CSS 规则的底部块:

¥Update the bottom block of CSS rules with the following:

css
/* Two column widths (12.5%) plus one gutter width (2.08333333%) */
.col.span2 {
  width: 14.58333333%;
}
/* Three column widths (18.75%) plus two gutter widths (4.1666666) */
.col.span3 {
  width: 22.91666666%;
}
/* And so on… */
.col.span4 {
  width: 31.24999999%;
}
.col.span5 {
  width: 39.58333332%;
}
.col.span6 {
  width: 47.91666665%;
}
.col.span7 {
  width: 56.24999998%;
}
.col.span8 {
  width: 64.58333331%;
}
.col.span9 {
  width: 72.91666664%;
}
.col.span10 {
  width: 81.24999997%;
}
.col.span11 {
  width: 89.5833333%;
}
.col.span12 {
  width: 97.91666663%;
}

现在保存你的代码,将其加载到浏览器中,然后尝试更改视口宽度 - 你应该看到列宽度很好地调整以适应。

¥Now save your code, load it in a browser, and try changing the viewport width — you should see the column widths adjust nicely to suit.

注意:如果你在使用上面的示例时遇到困难,请尝试将其与我们的 GitHub 上的完成版本(也包括 看到它实时运行)进行比较。

¥Note: If you are having trouble getting the above example to work, try comparing it against our finished version on GitHub (see it running live also).

使用 calc() 函数更轻松地进行计算

¥Easier calculations using the calc() function

你可以使用 calc() 函数在 CSS 内部进行数学计算 - 这允许你将简单的数学方程插入到 CSS 值中,以计算值应该是什么。当需要完成复杂的数学运算时,它特别有用,你甚至可以使用不同的单位进行计算,例如 "我希望这个元素的高度始终是其父元素高度的 100%,减去 50px"。参见 此示例来自 MediaStream Recording API 教程

¥You could use the calc() function to do the math right inside your CSS — this allows you to insert simple mathematical equations into your CSS values, to calculate what a value should be. It is especially useful when there is complex math to be done, and you can even compute a calculation that uses different units, for example "I want this element's height to always be 100% of its parent's height, minus 50px". See this example from a MediaStream Recording API tutorial.

无论如何,回到我们的网格!跨越网格中多于一列的任何列的总宽度为 6.25% 乘以跨越的列数加上 2.08333333% 乘以装订线数量(始终为列数减 1)。calc() 函数允许我们在宽度值内进行此计算,因此对于跨越 4 列的任何项目,我们可以执行此操作,例如:

¥Anyway, back to our grids! Any column that spans more than one column of our grid has a total width of 6.25% multiplied by the number of columns spanned plus 2.08333333% multiplied by the number of gutters (which will always be the number of columns minus 1). The calc() function allows us to do this calculation right inside the width value, so for any item spanning 4 columns we can do this, for example:

css
.col.span4 {
  width: calc((6.25% * 4) + (2.08333333% * 3));
}

尝试用以下内容替换底部的规则块,然后在浏览器中重新加载它,看看是否得到相同的结果:

¥Try replacing your bottom block of rules with the following, then reload it in the browser to see if you get the same result:

css
.col.span2 {
  width: calc((6.25% * 2) + 2.08333333%);
}
.col.span3 {
  width: calc((6.25% * 3) + (2.08333333% * 2));
}
.col.span4 {
  width: calc((6.25% * 4) + (2.08333333% * 3));
}
.col.span5 {
  width: calc((6.25% * 5) + (2.08333333% * 4));
}
.col.span6 {
  width: calc((6.25% * 6) + (2.08333333% * 5));
}
.col.span7 {
  width: calc((6.25% * 7) + (2.08333333% * 6));
}
.col.span8 {
  width: calc((6.25% * 8) + (2.08333333% * 7));
}
.col.span9 {
  width: calc((6.25% * 9) + (2.08333333% * 8));
}
.col.span10 {
  width: calc((6.25% * 10) + (2.08333333% * 9));
}
.col.span11 {
  width: calc((6.25% * 11) + (2.08333333% * 10));
}
.col.span12 {
  width: calc((6.25% * 12) + (2.08333333% * 11));
}

注意:你可以在 fluid-grid-calc.html(也可以在 现场观看)看到我们的完成版本。

¥Note: You can see our finished version in fluid-grid-calc.html (also see it live).

语义与 "unsemantic" 网格系统

¥Semantic versus "unsemantic" grid systems

向标记添加类来定义布局意味着你的内容和标记将与你的视觉呈现相关联。有时你会听到 CSS 类的这种使用被描述为 "unsemantic" — 描述内容的外观 — 而不是描述内容的类的语义使用。我们的 span2span3 等班就是这种情况。

¥Adding classes to your markup to define layout means that your content and markup becomes tied to your visual presentation. You will sometimes hear this use of CSS classes described as being "unsemantic" — describing how the content looks — rather than a semantic use of classes that describes the content. This is the case with our span2, span3, etc., classes.

这些并不是唯一的方法。你可以改为决定网格,然后将大小信息添加到现有语义类的规则中。例如,如果你有一个带有 content 类的 <div>,并且你想要跨越 8 列,则可以从 span8 类复制整个宽度,从而给出如下规则:

¥These are not the only approach. You could instead decide on your grid and then add the sizing information to the rules for existing semantic classes. For example, if you had a <div> with a class of content on it that you wanted to span 8 columns, you could copy across the width from the span8 class, giving you a rule like so:

css
.content {
  width: calc((6.25% * 8) + (2.08333333% * 7));
}

注意:如果你要使用 Sass 等预处理器,你可以创建一个简单的 mixin 来为你插入该值。

¥Note: If you were to use a preprocessor such as Sass, you could create a simple mixin to insert that value for you.

在我们的网格中启用偏移容器

¥Enabling offset containers in our grid

只要我们希望所有容器与网格左侧齐平,我们创建的网格就可以很好地工作。如果我们想在第一个容器之前(或容器之间)留出一个空的列空间,我们需要创建一个偏移类来为我们的网站添加左边距,以在视觉上将其推过网格。更多数学!

¥The grid we have created works well as long as we want to start all of the containers flush with the left-hand side of the grid. If we wanted to leave an empty column space before the first container — or between containers — we would need to create an offset class to add a left margin to our site to push it across the grid visually. More math!

让我们试试这个。

¥Let's try this out.

从你以前的代码开始,或使用我们的 fluid-grid.html 文件作为起点。

¥Start with your previous code, or use our fluid-grid.html file as a starting point.

让我们在 CSS 中创建一个类,它将容器元素偏移一列宽度。将以下内容添加到 CSS 底部:

¥Let's create a class in our CSS that will offset a container element by one column width. Add the following to the bottom of your CSS:

css
.offset-by-one {
  margin-left: calc(6.25% + (2.08333333% * 2));
}

或者,如果你更喜欢自己计算百分比,请使用以下百分比:

¥Or if you prefer to calculate the percentages yourself, use this one:

css
.offset-by-one {
  margin-left: 10.41666666%;
}

现在,你可以将此类添加到你想要在其左侧留下一列宽的空白空间的任何容器中。例如,如果你的 HTML 中有这样的内容:

¥You can now add this class to any container you want to leave a one column wide empty space on the left-hand side of it. For example, if you have this in your HTML:

html
<div class="col span6">14</div>

尝试将其替换为

¥Try replacing it with

html
<div class="col span5 offset-by-one">14</div>

注意:请注意,你需要减少跨越的列数,以便为偏移腾出空间!

¥Note: Notice that you need to reduce the number of columns spanned, to make room for the offset!

尝试加载并刷新以查看差异,或者查看我们的 fluid-grid-offset.html 示例(也可查看 实时运行)。完成的示例应如下所示:

¥Try loading and refreshing to see the difference, or check out our fluid-grid-offset.html example (see it running live also). The finished example should look like this:

The grid has 2 rows. The first row has 12 equal-width grid items and the second row has 4 items of different widths. Item 13 spans 1 column, item 14 spans five columns, 15 spans three, and 16 spans two. Item 14 has the 'offset-by-one' class applied, which means it starts in the 3rd column, rather than the second, leaving a one-column wide empty space in the second-row second-column.

注意:作为额外练习,你可以实现 offset-by-two 课程吗?

¥Note: As an extra exercise, can you implement an offset-by-two class?

浮动网格限制

¥Floated grid limitations

使用这样的系统时,你确实需要注意总宽度正确相加,并且行中所包含的元素的列数不得超过该行可以包含的列数。由于浮动的工作方式,如果网格列的数量对于网格来说太宽,则末尾的元素将下降到下一行,从而破坏网格。

¥When using a system like this you do need to take care that your total widths add up correctly, and that you don't include elements in a row that span more columns than the row can contain. Due to the way floats work, if the number of grid columns becomes too wide for the grid, the elements on the end will drop down to the next line, breaking the grid.

还要记住,如果元素的内容比它们占据的行宽,它就会溢出并看起来一团糟。

¥Also bear in mind that if the content of the elements gets wider than the rows they occupy, it will overflow and look a mess.

该系统的最大限制是它本质上是一维的。我们正在处理列,以及跨越列的元素,而不是行。使用这些旧的布局方法,在不显式设置高度的情况下控制元素的高度是非常困难的,这也是一种非常不灵活的方法 - 只有当你能保证你的内容具有一定的高度时,它才有效。

¥The biggest limitation of this system is that it is essentially one dimensional. We are dealing with columns, and spanning elements across columns, but not rows. It is very difficult with these older layout methods to control the height of elements without explicitly setting a height, and this is a very inflexible approach too — it only works if you can guarantee that your content will be a certain height.

弹性盒子网格?

¥Flexbox grids?

如果你阅读了我们之前关于 flexbox 的文章,你可能会认为 Flexbox 是创建网格系统的理想解决方案。有许多基于 Flexbox 的网格系统可用,Flexbox 可以解决我们在上面创建网格时已经发现的许多问题。

¥If you read our previous article about flexbox, you might think that flexbox is the ideal solution for creating a grid system. There are many flexbox-based grid systems available and flexbox can solve many of the issues that we've already discovered when creating our grid above.

然而,Flexbox 从未被设计为网格系统,并且在用作网格系统时会带来一系列新的挑战。作为一个简单的示例,我们可以采用上面使用的相同示例标记,并使用以下 CSS 来设置 wrapperrowcol 类的样式:

¥However, flexbox was never designed as a grid system and poses a new set of challenges when used as one. As a simple example of this, we can take the same example markup we used above and use the following CSS to style the wrapper, row, and col classes:

css
body {
  width: 90%;
  max-width: 980px;
  margin: 0 auto;
}

.wrapper {
  padding-right: 2.08333333%;
}

.row {
  display: flex;
}

.col {
  margin-left: 2.08333333%;
  margin-bottom: 1em;
  width: 6.25%;
  flex: 1 1 auto;
  background: rgb(255 150 150);
}

你可以尝试在自己的示例中进行这些替换,或者查看我们的 flexbox-grid.html 示例代码(也可参见 实时运行)。

¥You can try making these replacements in your own example, or look at our flexbox-grid.html example code (see it running live also).

在这里,我们将每一行变成一个弹性容器。对于基于 Flexbox 的网格,我们仍然需要行,以便让元素之和小于 100%。我们将该容器设置为 display: flex

¥Here we are turning each row into a flex container. With a flexbox-based grid we still need rows in order to allow us to have elements that add up to less than 100%. We set that container to display: flex.

.col 上,我们将 flex 属性的第一个值 (flex-grow) 设置为 1,以便我们的项目可以增长,将第二个值 (flex-shrink) 设置为 1,以便项目可以缩小,将第三个值 (flex-basis) 设置为 auto。由于我们的元素设置了 width,因此 auto 将使用该宽度作为 flex-basis 值。

¥On .col we set the flex property's first value (flex-grow) to 1 so our items can grow, the second value (flex-shrink) to 1 so the items can shrink, and the third value (flex-basis) to auto. As our element has a width set, auto will use that width as the flex-basis value.

在顶行,我们在网格上看到十二个整齐的盒子,当我们改变视口宽度时,它们会均匀地增长和缩小。然而,在下一行中,我们只有四个项目,它们也会在 60 像素的基础上增长和缩小。只要有四个,它们就可以比上面一行中的项目长得多,结果是它们在第二行上都占据相同的宽度。

¥On the top line we get twelve neat boxes on the grid and they grow and shrink equally as we change the viewport width. On the next line, however, we only have four items and these also grow and shrink from that 60px basis. With only four of them they can grow a lot more than the items in the row above, the result being that they all occupy the same width on the second row.

The grid has two rows. Each row is a flex container. The first row has twelve equal-width flex items. The second row has four equal-width flex items.

为了解决这个问题,我们仍然需要包含 span 类来提供一个宽度,该宽度将替换 flex-basis 用于该元素的值。

¥To fix this we still need to include our span classes to provide a width that will replace the value used by flex-basis for that element.

他们也不尊重上述项目使用的网格,因为他们对此一无所知。

¥They also don't respect the grid used by the items above because they don't know anything about it.

Flexbox 在设计上是一维的。它处理单个维度,即行或列的维度。我们无法为列和行创建严格的网格,这意味着如果我们要使用 Flexbox 作为网格,我们仍然需要计算浮动布局的百分比。

¥Flexbox is one-dimensional by design. It deals with a single dimension, that of a row or a column. We can't create a strict grid for columns and rows, meaning that if we are to use flexbox for our grid, we still need to calculate percentages as for the floated layout.

在你的项目中,你可能仍然选择使用 Flexbox 'grid',因为 Flexbox 在浮动上提供了额外的对齐和空间分布功能。但是,你应该意识到,你仍在使用工具来完成其设计目的以外的用途。因此,你可能会觉得它让你跳过额外的障碍才能获得你想要的最终结果。

¥In your project you might still choose to use a flexbox 'grid' due to the additional alignment and space distribution capabilities flexbox provides over floats. You should, however, be aware that you are still using a tool for something other than what it was designed for. So you may feel like it is making you jump through additional hoops to get the end result you want.

第三方网格系统

¥Third party grid systems

现在我们了解了网格计算背后的数学原理,我们可以很好地了解一些常用的第三方网格系统。如果你在网络上搜索 "CSS 网格框架",你会发现大量可供选择的选项。诸如 引导程序基础 之类的流行框架包含网格系统。还有一些独立的网格系统,要么使用 CSS 开发,要么使用预处理器开发。

¥Now that we understand the math behind our grid calculations, we are in a good place to look at some of the third party grid systems in common use. If you search for "CSS Grid framework" on the Web, you will find a huge list of options to choose from. Popular frameworks such as Bootstrap and Foundation include a grid system. There are also standalone grid systems, either developed using CSS or using preprocessors.

让我们看一下其中一个独立系统,它演示了使用网格框架的常用技术。我们将使用的网格是 Skeleton(一个简单的 CSS 框架)的一部分。

¥Let's take a look at one of these standalone systems as it demonstrates common techniques for working with a grid framework. The grid we will be using is part of Skeleton, a simple CSS framework.

要开始使用,请访问 骨架网站,然后选择 "下载" 下载 ZIP 文件。解压该文件并将 skeletal.css 和 normalize.css 文件复制到新目录中。

¥To get started visit the Skeleton website, and choose "Download" to download the ZIP file. Unzip this and copy the skeleton.css and normalize.css files into a new directory.

复制我们的 html-skeleton.html 文件并将其保存在与骨架相同的目录中并规范化 CSS。

¥Make a copy of our html-skeleton.html file and save it in the same directory as the skeleton and normalize CSS.

通过在其头部添加以下内容,在 HTML 页面中包含框架并标准化 CSS:

¥Include the skeleton and normalize CSS in the HTML page, by adding the following to its head:

html
<link href="normalize.css" rel="stylesheet" />
<link href="skeleton.css" rel="stylesheet" />

Skeleton 不仅仅包含网格系统,它还包含用于排版的 CSS 以及你可以用作起点的其他页面元素。不过,我们暂时将它们保留为默认值 - 这是我们真正感兴趣的网格。

¥Skeleton includes more than a grid system — it also contains CSS for typography and other page elements that you can use as a starting point. We'll leave these at the defaults for now, however — it's the grid we are really interested in here.

注意:标准化 是一个非常有用的小型 CSS 库,由 Nicolas Gallagher 编写,它会自动执行一些有用的基本布局修复,并使默认元素样式在浏览器之间更加一致。

¥Note: Normalize is a really useful little CSS library written by Nicolas Gallagher, which automatically does some useful basic layout fixes and makes default element styling more consistent across browsers.

我们将使用与之前示例类似的 HTML。将以下内容添加到你的 HTML 正文中:

¥We will use similar HTML to our earlier example. Add the following into your HTML body:

html
<div class="container">
  <div class="row">
    <div class="col">1</div>
    <div class="col">2</div>
    <div class="col">3</div>
    <div class="col">4</div>
    <div class="col">5</div>
    <div class="col">6</div>
    <div class="col">7</div>
    <div class="col">8</div>
    <div class="col">9</div>
    <div class="col">10</div>
    <div class="col">11</div>
    <div class="col">12</div>
  </div>
  <div class="row">
    <div class="col">13</div>
    <div class="col">14</div>
    <div class="col">15</div>
    <div class="col">16</div>
  </div>
</div>

要开始使用 Skeleton,我们需要为封装器 <div> 提供一个 container 类 - 这已经包含在我们的 HTML 中。这会将内容居中,最大宽度为 960 像素。你可以看到这些框现在的宽度永远不会超过 960 像素。

¥To start using Skeleton we need to give the wrapper <div> a class of container — this is already included in our HTML. This centers the content with a maximum width of 960 pixels. You can see how the boxes now never become wider than 960 pixels.

你可以查看 sculpture.css 文件来查看我们应用此类时使用的 CSS。<div> 使用 auto 左右边距居中,左右应用 20 像素的填充。Skeleton 还像我们之前所做的那样将 box-sizing 属性设置为 border-box,因此该元素的内边距和边框将包含在总宽度中。

¥You can take a look in the skeleton.css file to see the CSS that is used when we apply this class. The <div> is centered using auto left and right margins, and a padding of 20 pixels is applied left and right. Skeleton also sets the box-sizing property to border-box like we did earlier, so the padding and borders of this element will be included in the total width.

css
.container {
  position: relative;
  width: 100%;
  max-width: 960px;
  margin: 0 auto;
  padding: 0 20px;
  box-sizing: border-box;
}

如果元素位于行内,则它们只能是网格的一部分,因此与我们前面的示例一样,我们需要一个附加的 <div> 或其他具有 row 类的元素,嵌套在内容 <div> 元素和容器 <div> 之间。我们也已经这样做了。

¥Elements can only be part of the grid if they are inside a row, so as with our earlier example we need an additional <div> or other element with a class of row nested between the content <div> elements and the container <div>. We've done this already as well.

现在让我们布置容器。骨架基于 12 列网格。最上面的行框都需要 one column 类才能跨越一列。

¥Now let's lay out the container boxes. Skeleton is based on a 12 column grid. The top line boxes all need classes of one column to make them span one column.

现在添加这些,如以下代码片段所示:

¥Add these now, as shown in the following snippet:

html
<div class="container">
  <div class="row">
    <div class="one column">1</div>
    <div class="one column">2</div>
    <div class="one column">3</div>
    /* and so on */
  </div>
</div>

接下来,给第二行类上的容器解释它们应该跨越的列数,如下所示:

¥Next, give the containers on the second row classes explaining the number of columns they should span, like so:

html
<div class="row">
  <div class="one column">13</div>
  <div class="six columns">14</div>
  <div class="three columns">15</div>
  <div class="two columns">16</div>
</div>

尝试保存 HTML 文件并将其加载到浏览器中以查看效果。

¥Try saving your HTML file and loading it in your browser to see the effect.

注意:如果你在运行此示例时遇到问题,请尝试加宽用于查看它的窗口(如果窗口太窄,则不会按照此处所述显示网格)。如果这不起作用,请尝试将其与我们的 html-skeleton-finished.html 文件进行比较(也请参阅 实时运行)。

¥Note: If you are having trouble getting this example to work, try widening the window you're using to view it (the grid won't be displayed as described here if the window is too narrow). If that doesn't work, try comparing it to our html-skeleton-finished.html file (see it running live also).

如果你查看 sculpture.css 文件,你可以看到它是如何工作的。例如,Skeleton 定义了以下内容来添加 "三列" 类的样式元素。

¥If you look in the skeleton.css file you can see how this works. For example, Skeleton has the following defined to style elements with "three columns" classes added to them.

css
.three.columns {
  width: 22%;
}

Skeleton(或任何其他网格框架)所做的就是设置预定义的类,你可以通过将它们添加到标记中来使用它们。这与你自己计算这些百分比的工作完全相同。

¥All Skeleton (or any other grid framework) is doing is setting up predefined classes that you can use by adding them to your markup. It's exactly the same as if you did the work of calculating these percentages yourself.

正如你所看到的,使用 Skeleton 时我们只需要编写很少的 CSS。当我们向标记添加类时,它会为我们处理所有浮动。正是这种将布局责任交给其他东西的能力,使得使用网格系统框架成为一个令人信服的选择!然而如今,随着 CSS 网格布局的出现,许多开发者正在放弃这些框架,转而使用 CSS 提供的内置原生网格。

¥As you can see, we need to write very little CSS when using Skeleton. It deals with all of the floating for us when we add classes to our markup. It is this ability to hand responsibility for layout over to something else that made using a framework for a grid system a compelling choice! However these days, with CSS Grid Layout, many developers are moving away from these frameworks to use the inbuilt native grid that CSS provides.

概括

¥Summary

你现在了解了如何创建各种网格系统,这对于使用旧站点以及理解 CSS 网格布局的原生网格与这些旧系统之间的差异非常有用。

¥You now understand how various grid systems are created, which will be useful in working with older sites and in understanding the difference between the native grid of CSS Grid Layout and these older systems.