这篇翻译不完整。请帮忙从英语翻译这篇文章

在CSS布局中,网格系统是一种非常常见的布局方式, 并且在CSS 网格布局之前,他们倾向于用浮动和其他的布局功能。假想你的布局是一组数字标注的列(e.g. 4, 6, or 12), 然后把你的内容填充到这些想象的列中. 这篇文章将要探讨这种早期的方法是怎么实现的,来帮助你在旧项目工作时更好地理解他们。

Prerequisites: HTML 基础(学习 Introduction to HTML),并且了解CSS是怎么工作的(学习 Introduction to CSS and Styling boxes.)
Objective: 了解浏览器CSS网格布局系统的基本概念。

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

一个来自设计领域的人会惊讶于CSS直到最近才有网格系统,不仅如此,我们还用了许多次优方法来完成网格设计。我们现在把这些称为“古老”的方法。

对于许多新项目,大多数情况下CSS网格布局(CSS Grid Layout)被用来和其他一个或多个现代的布局方法结合形成布局的基础。但是你会时不时的遇到采用这种古老方法的“网格系统”。这很值得了解他们是如何工作的,以及为什么他们和CSS网格布局不同。

这个课程将会解释网格系统和网格框架是如何基于float和flexbox的。学习过网格布局之后你可能会惊讶这些看起来有多复杂!这些知识将会变的十分有用如果你需要在创建不支持新技术的老浏览器上创建后备代码,并且你也可以在用这些类别的项目中工作。

值得随时注意的是,在我们探索这些系统时,没有一个网格建立的方式是通过CSS网格布局创建网格的。他们通过给目标一个大小, 然后推动他们让他们像网格一样排列起来。

两列布局

让我们从最简单的实例开始——两列布局。你可以根据步骤创建一个新的 index.html 在你的电脑上,先拷贝这个框架 simple HTML template,然后在适当的位置填充下面的代码。在底部的区域你可以看到一个最终代码是什么样的实时实例。

首先,我们需要在我们的栏中放入一些内容。把现在在body中的内容替换成下面的部分:

<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>,或者是其他别的。

现在我们来看css。首先,应用以下的代码来对HTML进行基本设置:

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

body将会占90%的视野宽度直到达到900px,在这种情况下,它将固定并保持在窗口正中。 默认情况下,他的子项 (the <h1> 和两个 <div>) 将会达到正文宽度的100%。如果我们希望两个<div>一个浮在窗口的一边另一个浮动在另一边的话, 我们需要将他们的宽度设置为其父元素的100%或则更小,以便他们可以并排放置。将下面的代码加在CSS的底部:

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

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

这里我们将他们都设置为父元素宽度的48%——总共是96%,在两栏之间留4% 的空隙,为他们提供一些宽松的空间。现在我们只需要将他们float,像这样:

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

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

将这些都组合起来会得到这样的结果:

你有没有注意到我们在宽度的表示上都用的是百分比——这是一个很好的策略,因为他创建了一个流动布局(liquid layout),他能够适应不同的屏幕大小,并且在小一些的屏幕上也能使列保持一样的比例。试一试自己来调整浏览器窗口的宽度吧~ 这是响应式网页非常有价值的一个工具哦~

Note:你可以通过点击  0_two-column-layout.html 看到这个实例(或者 the source code)。

创建简单的原始网格框架

大多数古老的框架使用float属性来使列相邻排列,让他们看起来像使一个网格。学习用float创建网格可以展示他们工作的的原理,并且介绍了一些更高级的概念来搭建你在课程floats and clearing中学到的内容。

最简单的网格创建是固定宽度——我们通常只需要计算设计中总的宽度,列的数目,每一列和间隔的宽度。但是,如果我们决定设计的网格是可以根据浏览器宽度缩放的,我们则需要计算每一列和间距的所占的宽度的百分比。

下一部分我们将学习如何创建这两种方式的网格。我们会构建一个有12列的表格——我们选择了12这个常见的数字,来看他对不同情景的适应情况,因为12可以被6,4,3,和2完全整除。

一个简单的固定宽度网格

让我们先来创建一个固定列宽度的网格系统吧~

首先,把 simple-grid.html 下载储存下来,他的body中包含以下的标记:

<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>

我们的目标是把它变成一个有两行十二列的演示网格——第一行显示各列的大小,第二行显示网格上不同大小的区域。

在 <style>中,加入下面的代码,使容器的右侧的padding宽度为20像素,总的宽度变为980像素。这样给我们留出960像素可以放置列和他们的间隔——这种情况下,padding会被从总的内容宽度中减去,因为我们在box-sizing中讲所有的元素设置成了border-box (可以查看Changing the box model completely获得更多信息和解释)。

* {
  box-sizing: border-box;
}
    
body {
  width: 980px;
  margin: 0 auto;
}

.wrapper {
  padding-right: 20px;
}

现在清除网格中每行的浮动:

.row {
  clear: both;
}

这条规则表示我们不用在每行上都填充12列元素. 行与行之间不会互相干扰,并保持分隔。.

列与列之间保持20px的间隔. 我们使用每列元素的左外边框来实现这个间隔。然后我们一共有12个间隔 — 12 x 20 = 240.

我们需要从960px的总宽减去这个间隔,然后剩下720px给我们的列. 如果720除以12,我们将知道每列有60 个像素宽。

接下来我们给.col写一个规则,  向左浮动, 给它设置 20像素的margin-left来实现一个间隔, 设置60像素的 width. 下面是CSS:

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

最上面一行现在看起来是一个排列整齐的网格.

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列。每个宽度是将该列数的列宽加上间隔宽度相加的结果,这些宽度总是比列数少一个。

Add the following at the bottom of your 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; }

通过这些类,我们可以在网格上布局不同宽度的列。试试保存并加载这个页面在你的浏览器上来查看效果。

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).

试试修改,添加,删除这些类来看看你能怎么改变这个布局。例如,你可以把第二行写成这样:

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

现在你的网格布局生效了。现在你可以简单的定义这些行,和每行的列数。然后给他们添加你想要的内容。很棒。

Creating a fluid grid

这个网格表现的不错,但是它长度是固定的。 我们实际却想要一个弹性(流体)的网格,它可以在浏览器的可使用空间 viewport 里自动伸缩。为了达成这个目标,我们需要把相应的像素的长度变为百分比长度。

把固定长度转为伸缩的基于百分比的长度的算式在下面:

target / context = result

在我们的列宽里,我们的目标列长度是60像素,我们的内容是960像素。我们可以这么计算百分比:

60 / 960 = 0.0625

所以在css里面,我们可以用6.25%代替60像素。

我们也这么算间隔:

20 / 960 = 0.02083333333

所以我们用2.08333333% 代替.col里margin-left的20像素,和.wrapper 里 padding-right的20像素。

Updating our grid

创建一个之前例子网页的副本。然后开始这个章节, or make a local copy of our simple-grid-finished.html code to use as a starting point.

更新第二个css规则 (with the .wrapper selector) 像下面这样:

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

.wrapper {
  padding-right: 2.08333333%;
}

我们不仅给它一个百分比长度 width, 也添加了最大长度 max-width 属性来确保布局不过于宽。.

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

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

现在做些稍微麻烦的事 — 我们需要更新所有 .col.span 规则 来 把像素变为百分比. 这需要点时间计算; 为节省你的功夫, 我们在下面帮币做了.

Update the bottom block of CSS rules with the following:

/* 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%; }

现在保存你的代码,从浏览器里加载它, 尝试改变viewport长度 — 你应该可以看到网格漂亮的适配了。.

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).

Easier calculations using the calc() function

你可以用 calc() 函数 来做数学方面的计算 — 这个允许你在css里插入简单的算式, 来计算那些值. 这个会很有用,特别当你有个复杂计算的时候, 甚至你还可以在算式里用不同的单位, 比如 "我想要这个element一直比它父元素少50像素". See this example from a MediaRecorder API tutorial.

言归正传, 来讲我们的网格! 我们网格里跨越超过一列的列,它的总长是6.45%乘跨越的列数 加 2.08333333%乘间隔数(间隔数总等于行数减一) . 这个 calc() 函数 允许我们在长度值右边这么计算, 所以对跨越4列的列我们可以这么算:

.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:

.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)); }

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

Note: If you can't get this to work, it might be because your browser does not support the calc() function, although it is fairly well supported across browsers — as far back as IE9.

Semantic versus “unsemantic” grid systems

在标记中添加类以定义布局意味着您的内容和标记与您的可视化表示相关联。. 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.

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:

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

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

我们创造的网格很有效。只要我们想把所有容器都从网格的左手对齐. 如果我们想在第一个容器前来个空列,或者容器之间来个空列,我们需要新建一个偏移类来弄点左外边距给来显示到网格上. 更多的数学计算!

Let's try this out.

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

我们在css上搞一个类,他会给容器一个一列举例的偏移。. Add the following to the bottom of your CSS:

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

或者你更愿意自己算百分比,用下面这个:

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

你先可以在,想要在左边添加一个一列宽度的空白的容器上添加这个类。. For example, if you have this in your HTML:

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

Try replacing it with

<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!

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:

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

Floated grid limitations

当你想用这个网格系统时,你得仔细看看你的总长是否加的正确,并且每行列数不超过它可容纳的列。因为是浮动布局,如果列数太大,在最后边的元素会跑到下一行去,搞坏了布局 。

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

这个系统的最大限制是,它是一维的。我们在处理列,跨越列,但是处理不了行。如果不设置一个确定的高度,用老方法很难控制元素高。这个方法很不灵活 —它只有在你确定你的内容有个明确的高的情况下有用。

Flexbox grids?

如果你读了之前关于flexbox的文章,你大概会想弹性布局是个写网格布局的好办法。现在有很多基于弹性布局的网格布局,并且弹性布局可以解决很多上面讲的问题。

但是,弹性布局不是为网格布局而设的,把它当网格布局来用也有新的挑战。 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:

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);
}

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

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.

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.

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.

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 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.

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

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.

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.

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.

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

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

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

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.

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.

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

<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>


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.

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.

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

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> and our actual content container <div>s. We've done this already as well.

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:

<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:

<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>

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

Note: If you are having trouble getting this example to work, try comparing it to our html-skeleton-finished.html file (see it running live also).

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.

.three.columns { width: 22%; }

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.

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

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.

In this module

文档标签和贡献者

此页面的贡献者: Hermedius, mdnwebdocs-bot, zxxzzzzz, agnoCJY
最后编辑者: Hermedius,