网格布局

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

网格(Grid)是一种成熟的设计工具,许多现代的网站的布局是根据普通的网格来实现的。在这篇文章中,我们将会了解基于网格的设计,以及如何用 CSS 来创建网格—用现在的工具,以及在各大浏览器上刚刚落地的新技术。

前提条件: HTML 基础 (前往 HTML入门学习),并了解CSS是如何运作的 (需要学习 CSS入门 和 CSS盒子模型.)
目标: 网格(Grid)布局基础概念,学会如何在网页上应用 网格布局。

什么是网格布局?

一个网格元素集中设计了水平线和垂直线,它帮助我们在布局设计,一个页面跳转到另一个页面,其中元素宽度不变,提供了网站的一致性。

网格具有列、行、在每一行列的空白 — 通常被称为沟槽

[临时图; 将很快替换被更好的图片 by a better diagram soon.]

注意:该CSS不具有内置的网格系统,是我们用各种现有方法创建的网格设计。在本文最后一部分中,它将会被改变,但是您现在需要了解与探索创建网格的方法。

在项目中使用“网格机制”

从一开始网格系统的基础是为了确保网站或应用程序体验一致,这意味着你不需要考虑某个元素和其他元素的宽度,你只需考虑“Grid跨多少列”。

您在设计过程中“网格系统”可以简单地帮你决策形成一个简单的正则网格,你可以在如Photoshop等应用程序创建一个网格然后引用,描述参考 A better Photoshop grid for responsive web design by Elliot Jay Stocks.

你的网格系统可能是由第三方通过CSS来执行项目网格框架。

创建简单的网格框架

首先我们先看看如何为你的项目创建一个简单的网格框架。

目前大多数创建网格布局使用浮动(floats)。 如果您读过  我们上一篇有关floats布局文章。您已看过如何使用这一技术创建多个列的布局——这是任何系统使用网格的本质方法。

要创建的最简单的网格框架类型是固定宽度的网格框架 - 我们只需要计算出我们想要设计的总宽度,我们想要多少列,以及水槽和列的宽度。如果我们决定在具有根据浏览器宽度增长和缩小的列的网格上布置我们的设计,我们需要计算它们之间的列和间距的百分比宽度。

在下一节中,我们将看看如何创建两个。我们将创建一个12列网格-一个非常常见的选择被认为是非常适应不同情况下考虑到12除以 6、4、3、2。

简单的固定宽度的网格

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

开始简单本地栅格样本simple-grid.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>

我们的目标是将这个示范网格两行一百变成十二列网格 — 第一行显示单个列的尺寸,第二行不同区域的网格尺寸。

首先,<style> 添加以下代码,给页面上所有元素包裹在宽度980像素盒子中 sized as border boxes ,右侧填充20px. 总共列960px / 沟槽宽度。

* { box-sizing: border-box; }
    
.wrapper {
  width: 980px;
  margin: 0 auto;
  padding-right: 20px;
}

现在从另一行中清除一行,使用网格包围每一行的容器。在您上一个规则下面添加以下规则:

.row {
  clear: both;
}

此清除意味着我们不需要构建完整十二列元素填充每一行。行将保持分离,并且不干扰彼此。

列之间的间距宽度20像素。我们在每个列的左侧创建这些水槽作为边缘 - 包括第一列,以平衡容器右侧的填充的20个像素。所以我们有12个水槽 -  12×20 = 240。

我们需要从960像素的总宽度中减去它,为列提供720像素。如果现在将它除以12,我们知道每列宽度应该是60像素。我们的下一步为calss.col创建一个规则浮动它,给它一个20像素的 margin-left 以形成一个gutter,并且一个 width 60px。将以下规则添加到CSS的底部:

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

现在将顶行的单列网格整齐排列

注意:我们给每列一个浅红色,这样你就可以清楚看到每一个空间占用多少。

需要跨越多个列的布局我们需要特殊容器来调整它们的布局. width 所需的列数值 (加上中间的水槽). 我们需要创建一个额外的calss,容器跨越2到12列。该列数的每个宽度的列宽加上装订线的宽度相加得到结果,总比列数少1。


在你的CSS底部添加如下:

/* 两列宽 (120px) + 1沟槽宽 (20px) */
.col.span2 { width: 140px; }
/* 三列宽 (180px) + 两个槽宽 (40px) */
.col.span3 { width: 220px; }
/* 凡此种种,不列举... */
.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; }

通过创建class类,我们现在可以在我的网格上设置不同宽度的列,尝试在浏览器中保存和加载页面查看效果。

注意:上面的例子对你如果有困难,试着比较它与我们完成的版本或者在GitHub ( 查看它是怎么运行的)。


尝试修改class元素的类,添加和移除一些容器;以了解如何布局。例如,您可以使第二行看起来像这样:

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

Great!你现在已经有一个网格系统,可以简单定义每一行的行和列的数量,然后填满每个容器所需的内容。

创建流体网格

网格工作良好,但它是固定宽度。我真的想要一个灵活(流体)网格,为了实现这一点,我们可以使用参考像素的宽度,并把它们变成百分比。将增长和在浏览器窗口中的可用空间缩小。

建立一个灵活固定宽度百分比-公式如下.

target / context = result

对于列宽,我们的目标是用960px容器和宽度60px包裹上下文。使用以下计算百分比。

60 / 960 = 0.0625

然后移动小数点2位,给一个百分比为6.25%。所以在我们的CSS,我们可以用6.25%代替60像素列的宽度。

槽的宽度我们需要同样的:

20 / 960 = 0.02083333333

所以需要更换20px margin-left col规则和20pxpadding-right 跟着用容器 2.08333333%包裹。

更新网格

开始制作一个新的示列,把本节作为起始点,或者拷贝我们的代码到本地simple-grid-finished.html 

更新CSS规则 (用选择器包装) 如下:

.wrapper {
  width: 90%;
  max-width: 980px;
  margin: 0 auto;
  padding-right: 2.08333333%;
}

我们不仅要给它一个百分比 width, 我们还增加了一个{cssxref("max-width")}} 属性为了阻止布局变得太宽。

其次,更新第四行CSS规则(与Col选择器)像这样: 

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

现在是一个更困难的部分 — 使用百分比更新像素宽度col、span。这需要用计算器,为了节省你的时间,我们已经为你做好以下。

更新底部CSS规则 如下:

/* 两列宽 (12.5%) 加上一个沟槽宽度 (2.08333333%) */
.col.span2 { width: 14.58333333%; }
/* 三列宽度(18.75%)加上两个沟槽宽度 (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%; }

Great!现在尝试着改变窗口列宽度在浏览器中加载它,调整适合后保存你的代码。

注意::上述例子如果你有困难,尝试我们在GitHub的完整版本 (看它是如何运行的)。

使用 calc() 函数简化计算

你可以使用 calc() 功能做数学在你的CSS — 这允许你插入到你的CSS值的数学方程。去计算一个值应该是什么,当有复杂的数学要做,这是特别有用。甚至可以计算出一个不同单位的,例如:“我想要这个元素的高度始终是父级高度的100%,减去50px”  从 MediaRecorder API 示列看教程

好了, 我们回到网格!任何网格跨越超过一列总宽度为6.25%乘以列数加2.08333333% 乘以槽数(其中总数量减1)这个calc() 函数允许我们在宽度做计算,所以,对于任何跨越4列的项目,我们可以这样做,例如:

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

试着用下面的代码替换你之前底部规则,然后在浏览器中重新加载,看看你是否得到了相同的结果:

.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 (如何运行的)。

注意: 它无法工作,可能是因为你的浏览器不支持。早在IE9 ,calc() 这个函数,支持跨浏览器。功能相当不错。

Semantic 与 “un-semantic” 网格机制

添加Class类,定义布局意味着您的内容和标记与其视觉呈现相关联。你有时会听到这样的使用CSS class类被描述为“非语义”—— 描述内容的外观 —— 是描述class类的语义,这是我们的span2、span3、class类,等等其他。

这些并不是唯一途径和方法。 你可以决定你的网格大小,然后添加信息现有的语义规则 class类.。列如如果你有一个 <div> 一个class类,你想跨8栏,你可以从span8复制整个宽度:

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

注意: 如果你使用一个预处理器如 Sass, 你可以创建一个简单的值混合插入。

偏移网格容器

我们创建的网格工作得很好,只要我们想要启动所有的容器与网格的左手边齐平。如果我们想在第一个容器之前留下一个空隙,或者在容器之间留下一个空隙,我们需要创建一个偏移类来添加一个左边距到我们的网站,以推动它在网格上。更多数学!

让我们试试这个。

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

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

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

或者如果你喜欢自己计算百分比,使用这一个:

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

您现在可以将这个class类添加到任何容器,留下一个左边列宽的间隙。例如,在你的HTML:

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

尝试更换它

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

注意: 您需要减少跨列的数量,以弥补偏移空间!

尝试加载、刷新看到的差异,或查看我们的 fluid-grid-offset.html 示列 (它是如何运行nning 的).。完成的示例应该如下:

注意:偏移列作为一个额外练习, 你能实现一个 offset-by-two class?

浮动网格限制

当您使用这样的系统时,需要注意正确相加总宽度,并且不包括行中的元素,由于浮动的方式工作,列跨越的列比行可以包含的列多。如果总宽度变宽超过100%,多余的项目将下降到下一行。

如果同样事情会发生,元素的内容推动他们变宽,也将使总宽度超过100%。

用container容器<div> with a class of row helps to prevent our design falling into chaos should our lines not add up neatly to 100% but you do need to do a fair amount of managing of the grid when using this method. Commonly you would use 媒体查询  to create a different layout at narrower breakpoints to ensure that you don’t have the issue of the grid pushing too wide.

这个系统的另一个限制是它本质上是一维的。我们处理的列,和生成的元素在列,而不是行。用旧布局来控制元素高度,而不明确设置一个高度,这是非常死板的方法也是非常困难的 — 它只工作,你能保证你的内容高度。

Flexbox 的网格?

如果你读过我们以前的文章flexbox 你可能会认为 flexbox 是创建网格系统的理想解决方案。目前有很多基于flexbox搭建的网格系统,available和flexbox可以解决我们在创建网格时发现的许多问题。

然而,flexbox从来没有被设计为网格系统,并当作一个使用时提出了一系列新的挑战。一个简单的例子,我们可以采用我们上面使用的相同的示例标记,并使用以下CSS来设置wrapper,row和col类的样式:wrapper, row, col classes:

.wrapper {
  width: 90%;
  max-width: 980px;
  margin: 0 auto;
  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 代码示列( 了解它怎么运行 )。

我们将这里的每一行变成一个Flex集装箱。一个行需要flexbox-based网格,为了让我们的元素总计小于100%。我们设置容器display: flex.

在我们设置Col flex属性的第一个值 (flex-grow) 到1,所以我们的项目可以增长,第二个值 (flex-shrink) 的项目1可以缩小,第三个值 (flex-basis) 自动将元素宽度width 设置为基础值flex-basis使用。


我们在顶部得到十二个整齐方块的网格,随着我们改变窗口宽度而它们同样地增长和收缩。在下一行,但是我们只有四个项目,这些也从60px基础增长和收缩。结果是只有四个可以增长比上面行中的项目多,在第二行他们都占据相同的宽度。

为了解决这个问题我们还需要一个class类包跨宽度的span,以替换flex-basis基础值所使用。

关于上面网格项目也不尊重使用,因为他们什么也不知道。

Flexbox是一维设计,它处理一个单独维度,一行或一列。我们不能为行和列创建一个严格的网格,这意味着如果使用flexbox网格我们还需要计算出浮动的百分比布局。

在你的项目,你可能会选择使用一个flexbox网格。由于网格额外排列和空间分布的能力flexbox提供浮动。但你应该注意仍在使用的工具跳过额外排列和空间,所以你可能会使用“flexbox‘Grid’来得到你想要的最终结果。

第三方网格机制

既然我们理解了网格背后的计算数学,我们就可以很好地观察一些常用的第三方网格系统。如果你搜索“CSS网格框架”。你会发现一个巨大的名单。流行的框架,如BootstrapFoundation流行框架。无论是开发或使用CSS预处理器,都包括一个独立的网格系统。

让我们看看其中的一个独立系统,因为它演示了处理框架通用的网格技术。网格,我们将使用的是Skeleton的CSS框架。

访问Skeleton website框架选择“下载”压缩文件。解压,并复制skeleton.css和normalize.css文件到新的目录。

保存一份 html-skeleton.html 文件在同一目录下的skeleton和规范的CSS。

通过 skeleton 和 normalize CSS 在HTML页面添加以下在head中:

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

Skeleton,你可以用为出发点。包括超过一个网格系统,CSS排版和其他页面元素。但我真正感兴趣的是网格。现在我们将这些放在默认值。

注意:”normalize是由Nicolas Gallagher编写的,一个非常有用小型CSS库。它自动执行修复一些有用的基本布局,并使默认元素样式在不同浏览器之间更一致。我们将使用前面类似的HTML列子将以下内容添加到HTML主体中:

将以下列子添加到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 centred 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="col one column">1</div>
    <div class="col one column">2</div>        
    <div class="col 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="col one column">13</div>
  <div class="col six columns">14</div>
  <div class="col three columns">15</div>
  <div class="col 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 makes using a framework for a grid system a compelling choice!

Skeleton is a simpler grid system than some of the frameworks you may come across. The grids in large frameworks such as Bootstrap and Foundation offer more functionality and additional breakpoints for various screen widths. However they all work in a similar way — by adding specific classes to your markup you can control how the element is laid out using the predefined grid.

Native CSS Grids with Grid Layout

We said at the beginning of this article that CSS has not previously had a real system for creating grid layouts, but this is set to change. While we can’t use a native CSS grid system yet, in the coming year we should see browser support appear for the CSS Grid Layout Module.

Currently you can only use the technique we’ll be showing you in browsers that are implementing CSS Grid Layout “behind a flag” — meaning it is currently implemented, but in an experimental state that you need to switch on to use.

In Firefox, for example, you need to navigate to a URL of about:config, search for the layout.css.grid.enabled preference, and double click it to enable CSS Grids. You cna find out how to use it in other browsers by visiting Grid by Example.

We looked at the Skeleton Grid framework above — like other third party Grids and even hand-built grids, it requires that you add <div>s to form rows, and then specify the number of columns the items in these rows will span.  

With CSS Grid Layout you can specify your grid entirely in CSS, without needing to add these helper classes to the markup at all. Let’s take our simple example and see how we would create that same layout using CSS Grid Layout.

Building a native grid

First, get started by making a local copy of the css-grid.html file. It contains the following markup:

<div class="wrapper">
  <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 class="col">13</div>
  <div class="col span6">14</div>
  <div class="col span3">15</div>
  <div class="col span2">16</div>       
</div>

This time we have a parent <div> with a class of wrapper, and then all of the child elements just appear directly inside the wrapper — no row elements. We have added a class to the items that should span more than one column.

Now add the following into the <style> element:

.wrapper {
  width: 90%;
  max-width: 960px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-gap: 20px;
}

.col {
  background: rgb(255,150,150);
}

Here we set the .wrapper rule so it is 90% of the body width, centered, and has a max-width of 960px.

Now for the CSS grid properites. We can declare a grid using the grid value of the display property, set up a gutter with the grid-gap property and then create a grid of 12 equal width columns using grid-template-columns, the new repeat() function, and a new unit defined for grid layout — the fr unit.

The fr unit is a fraction unit — it describes a fraction of the available space in the grid container. If all columns are 1fr, they will each take up an equal amount of space. This removes the need to figure out percentages to create a flexible grid.

Having created a grid, the grid auto-placement rules will immediately lay out our boxes on this grid and we get a twelve column flexible grid layout.

To style the containers that span multiple column tracks on the grid we can use the grid-column property. To span 6 columns for example:

.span6 {
  grid-column: auto / span 6;
}

To span 3:

.span3 {
  grid-column: auto / span 3;
}

The value before the forward slash is the start line — in this case we are not explicitly setting that and allowing the browser to place the item on the next available line. We can then set it to span 6, 3 or however many lines we want.

Add the following at the bottom of your CSS:

.span2 { grid-column: auto / span 2;}
.span3 { grid-column: auto / span 3;}
.span4 { grid-column: auto / span 4;}
.span5 { grid-column: auto / span 5;}
.span6 { grid-column: auto / span 6;}
.span7 { grid-column: auto / span 7;}
.span8 { grid-column: auto / span 8;}
.span9 { grid-column: auto / span 9;}
.span10 { grid-column: auto / span 10;}
.span11 { grid-column: auto / span 11;}
.span12 { grid-column: auto / span 12;}

Try saving and refreshing, and you'll see that the containers span multiple columns as appropriate. Cool!

CSS grids are two-dimensional, so as the layout grows and shrinks the elements remain lined up horizontally and vertically.

You can test this by replacing your last 4 col <div>s with the following:

<div class="col">13some<br>content</div>
<div class="col span6">14this<br>is<br>more<br>content</div>
<div class="col span3">15this<br>is<br>less</div>
<div class="col span2">16</div>

Here we've deliberately added in some line break (<br>) tags to force some of the columns to become taller than others. If you try saving and refreshing, you'll see that the columns adjust their height to be as tall as the tallest container, so everything stays neat and tidy.

The final layout looks like so:

Note: If you are having trouble getting this example to work, you can check your code against our finished version (also see it running live).

Other nice CSS grid features

With CSS grids, we don’t need to push things along by way of margins to offset them. Trying making these changes in your CSS:

.content {
  grid-column: 2 / 8;
}
<div class="col span2 content">16</div>

Container 16 will now span columns 2 to 8, on the next available row where it can fit.

We can span rows just as easily as columns:

.content {
  grid-column: 2 / 8;
  grid-row: 3 / 5;
}

Container 16 will now span rows 3 to 5, as well as columns 2 to 8.

We also don’t need to use a margin to fake gutters or calculate their widths explicitly — CSS grid has this functionality built right in with the grid-gap property.

We’re just touching the surface of what is possible with CSS Grid Layout, but the key thing to understand in the context of this article is that you don’t need to create a grid system with grid - it is one. You can write CSS that places an item directly onto a predefined grid. This is the first time it has been possible with CSS, and this will get a lot more use once browser support solidifies.

Summary

Having read this article you should now have an understanding of how grid layouts, and grid frameworks work in CSS. You have also had a peek into the future off CSS grids, and should now understand that the grid frameworks we use today are essentially a stopgap solution until we have a widely supported native way of achieving this in CSS.

文档标签和贡献者

 此页面的贡献者: goodluckforever, ziyunfei, Slayer1986, Ende93
 最后编辑者: goodluckforever,