11.12 CSS 隐式网格布局

由网格容器自动生成的网格布局元素

网格模板(grid-template)属性及其普通写法(longhands)定义了一个固定数量的轨道,构成显式网格。 当网格项目定位在这些界限之外,网格容器通过增加隐式网格线生成隐式网格轨道。 这些隐含的和显式的网格线一起构成隐式网格(implicit grid)。 隐式网格轨道的尺寸由网格自动行(grid-auto-rows)网格自动列(grid-auto-columns)属性来确定。

网格自动流(grid-auto-flow)属性用来控制无明确位置的网格项的自动定位(auto-placement), 一旦显式网格被填满(或者如果没有显式的网格),auto-placement也将导致隐式网格轨道的生成。

自动生成行和列的尺寸:grid-auto-rows 和 grid-auto-columns 属性

名称: grid-auto-columns, grid-auto-rows
可用取值: <track-size>
初始值: auto
用于: grid containers
继承的:
百分比: 查看轨道尺寸
媒体: visual
计算值: 查看轨道尺寸
是否支持动画:

如果一个网格项被放到一个未明确定义尺寸的行或列中,隐式网格轨道将被创建来容纳它。 这在两种情况下会发生:通过显式定位到一个超出范围的行或列中,或是由自动定位算法创建额外的行或列。 网格自动列和网格自动行属性用来指定这样的隐式创建的轨道的大小。

隐式网格轨道的使用

<style type="text/css">
  #grid {
    display: grid;
    grid-template-columns: 20px;
    grid-template-rows: 20px }
  #A { grid-column: 1;          grid-row: 1; }
  #B { grid-column: 5;          grid-row: 1 / span 2; }
  #C { grid-column: 1 / span 2; grid-row: 2; }
</style>

<div id="grid">
  <div id="A">A</div>
  <div id="B">B</div>
  <div id="C">C</div>
</div>

上面这个例子演示了隐式网格轨道的使用。本例中共创建了2行5列,其中显式声明的只有第1行/第1列,除此之外有1个隐含行和4个隐含列。 网格项B位于网格线5,这将自动创建4个隐式网格列,但是由于列3和4中没有任何网格项,所以其宽度塌缩为0。你可以通过在线实例自己测试下。

自动布局:网格自动流(grid-auto-flow)属性

名称: grid-auto-flow
可用取值: [ row | column ] || dense
初始值: row
用于: grid containers
继承的:
百分比: n/a
媒体: visual
计算值: 指定值
是否支持动画:

未明确指定位置的网格项将通过自动定位算法来自动放置到网格容器的未占用空间中。 网格自动流就是用来控制自动布局算法如何工作的,指定如何把自动布局的网格项放进网格中。 这在网格项布局算法中会详细讲解其工作原理。

row
自动布局算法把网格项按顺序填充到每一行,必要时添加新行。这是grid-auto-flow的缺省值。
column
自动布局算法把网格项按顺序填充到每一列,必要时添加新列。
dense
如果指定了dense,将使用“密集”填充算法,它试图把排在后面的体积小的网格项填充到“大个头”网格留下的空隙中,就像我们在汽车后备箱塞物品一样。这有可能会导致填充顺序和代码顺序不同。

如果未指定,则将使用“稀疏”填充算法,只是按顺序摆放,不回溯填空。这可以确保所有网格项保持原有的代码序,但有可能会出现页面空间浪费。

在下面的例子中,有3列,尺寸自动适应其内容。没有明确定义行。网格自动流属性是row,它指示网格逐行搜索3列,必要时添加行(row)直到有足够的空间放置所有自动布局网格项。

Image: A form arranged using automatic placement.
使用自动布局的表单

<style type="text/css">
form {
  display: grid;
  /* 定义三列,均为其内容大小,并命名相应的网格行。*/
  grid-template-columns: [labels] auto [controls] auto [oversized] auto;
  grid-auto-flow: row dense;
}
form > label {
  /* 将所有标签放在“标签”列中,并自动寻找下一可用行。*/
  grid-column: labels;
  grid-row: auto;
}
form > input, form > select {
  /* 将所有控件放在“控制”列中,并自动寻找下一行。*/
  grid-column: controls;
  grid-row: auto;
}

#department-block {
  /* 自动将此网格项放置在第一行的“大号”列中,
  其中一个区域跨越三行,不会覆盖其他显式放置的网格项或区域
  或任何在该区域之前自动放置的网格项。*/
  grid-column: oversized;
  grid-row: span 3;
}

/* 把所有的表单按钮放在明确定义的网格区域. */
#buttons {
  grid-row: auto;

  /* 确保按钮区域横跨整个行轴上的网格单元。*/
  grid-column: 1 / -1;
  text-align: end;
}
</style>
<form>
  <label for="firstname">First name:</label>
  <input type="text" id="firstname" name="firstname" />
  <label for="lastname">Last name:</label>
  <input type="text" id="lastname" name="lastname" />
  <label for="address">Address:</label>
  <input type="text" id="address" name="address" />
  <label for="address2">Address 2:</label>
  <input type="text" id="address2" name="address2" />
  <label for="city">City:</label>
  <input type="text" id="city" name="city" />
  <label for="state">State:</label>
  <select type="text" id="state" name="state">
    <option value="WA">Washington</option>
  </select>
  <label for="zip">Zip:</label>
  <input type="text" id="zip" name="zip" />

  <div id="department-block">
    <label for="department">Department:</label>
    <select id="department" name="department" multiple>
      <option value="finance">Finance</option>
      <option value="humanresources">Human Resources</option>
      <option value="marketing">Marketing</option>
    </select>
  </div>

  <div id="buttons">
    <button id="cancel">Cancel</button>
    <button id="back">Back</button>
    <button id="next">Next</button>
  </div>
</form>

你可以自己试试

网格定义速写:grid属性

名称: ‘grid’
可用取值: <‘grid-template’> | [ <‘grid-auto-flow’> [ <‘grid-auto-columns’> [ / <‘grid-auto-rows’> ]? ]? ]
初始值: 参见单独的属性
用于: grid containers
继承的: 参见单独的属性
百分比: 参见单独的属性
媒体: visual
计算值: 参见单独的属性
是否支持动画:

网格属性(grid)是一个所有的显式网格属性(网格模板行、网格模板列、网格模板区域)、隐式网格属性(网格自动行、网格自动列、网格自动流)以及槽(gutter)属性(网格列间隙和网格行间隙)的单一声明速写。

考虑到代码的可读性,我们不建议这样合并在一起写,所以这里不做更多描述。

限制过大的网格(Clamping Overlarge Grids)

由于内存不是无限的,用户代理可能会把网格大小限定在UA定义的限制中,而抛弃所有超出限制的网格线。如果一个网格项被放置在这个限制之外,它的网格区域必须被固定在这个有限的网格内。

限制方法如下:

  • 如果网格区域将跨越有限网格,它的跨度被限制在有限网格的最后一条网格线。
  • 如果网格区域完全在有限网格之外,它的跨度必须截断为1,并重新定位到最后的那条轨道中。