11.11 CSS 网格布局术语

网格布局中的基本概念和术语

网格布局中,网格容器(grid container)中的内容是通过在网格(grid)中定位和对齐来摆放的。 网格(grid)本质上是一个把网格容器(grid container)通过一组横竖向垂直相交的网格线(grid lines)所划分的格子区域,从而网格项(grid items)(代表grid container中的内容)可以被放进这些格子中。 有两组网格线(grid lines): 一组用来定义沿着块坐标轴(block axis)的列轴延伸的列(columns), 还有一个与之正交的组来定义行内坐标轴(inline axis)的行轴延伸的行(rows)

Image: Grid Lines.
网格线:3条位于列轴上和4条位于行轴上

网格轨道(Tracks)和单元(Cells)

Grid trackgrid columngrid row, 其实就是介于相邻grid lines之间的区域。 每个grid track都使用一个尺寸函数(sizing function)来控制行列可能延伸的宽高,以及和网格线边界的距离。

网格单元(grid cell) 和网格(grid)同义,表示由两个相邻列和两个相邻行网格线之间所限定的格子区域。 这是我们定位grid items时所引用的最小单位。

下面的例子中,有2列3行。第1列固定使用固定宽度150px。 第2列使用弹性尺寸1fr,代表Grid中的剩余空间,会随grid container宽度而变,最小值为0。 比如grid container的宽度为200px,那么第2列的宽度为50px。 如果grid container的宽度为100px,那么第2列的宽度为0,而位于该列中的内容将溢出grid container。


        #grid {
          display: grid;
          grid-template-columns: 150px 1fr;
          grid-template-rows: 50px 1fr 50px
        }
    

网格线(Grid Lines)

网格线是网格的水平和垂直分割线,位于行或列的两边。可以通过数字索引指定名字来引用。 网格项使用网格定位属性(grid-placement properties)引用网格线来确定其在网格中的位置。


        #grid {
          display: grid;
          grid-template-columns: 150px 1fr;
          grid-template-rows: 50px 1fr 50px
        }

        #item1 {
          grid-column: 2;
          grid-row-start: 1;
          grid-row-end: 4
        }
        

我们使用命名来引用网格线,实现和上面的例子相同的布局:


        #grid {
          display: grid;
          grid-template-columns: 150px [item1-start] 1fr [item1-end];
          grid-template-rows: [item1-start] 50px 1fr 50px [item1-end];
        }

        #item1 {
          grid-column: item1-start / item1-end;
          grid-row: item1-start / item1-end
        }
        

网格区域(Grid Areas)

grid area是用来摆放一个或多个grid item的逻辑空间。 它由构成其边界的4条网格线所包围,同时参与与之相交的网格轨道的尺寸。 grid area可以用grid container的grid-template-areas属性来显式命名,或者通过其边界网格线来隐式引用。 grid item通过网格定位属性(grid-placement properties)来赋予一个网格区域(grid area)。


        #grid {
          display: grid;
          grid-template-areas: ". a"
                               "b a"
                               ". a"
          grid-template-columns: 150px 1fr;
          grid-template-rows: 50px 1fr 50px
        }

        #item1 {
          grid-area: a;
        }
        #item2 {
          grid-area: b;
        }
        #item3 {
          grid-area: b;
        }
        /* 使用网格区域b来对齐items 2 和 3。 */
        /* 默认情况下,网格项会自动拉伸来匹配其所在的网格区域,并可能会重叠在一起。 */
        #item2 {
          align-self: start
        }
        #item3 {
          justify-self:  end; align-self:  end; 
        }
        

一个grid item所在的grid area构成其包容块(containing block)。 grid item上指定的百分比长度依据其包容块计算。margin-top,padding-top,margin-bottom和padding-bottom属性的百分比长度依据包容块的高度(而不是宽度)来计算。

在BFC中,块元素的垂直内外边距的百分比数值是依据其包容块(父元素)的宽度来计算的。

但是需要提醒的是,grid item的这种margin/padding行为是有争议的,所以最好进行实际的浏览器行为测试。

grid area中的grid items并不会直接影响彼此的布局。 但是grid item内容的尺寸可能会影响所在行列的grid line位置,从而间接影响其它grid item的位置和尺寸。

网格容器(Grid Containers)

何时创建网格容器

前面我们提到过,当我们把一个元素的display属性设置为grid或inline-grid的时候,就将创建一个网格容器。

grid
该取值将促使元素生成一个块级(block-level)网格容器框。
inline-grid
该取值将促使元素生成一个行内级(inline-level)网格容器框。

网格容器会为其内容建立一个GFC来负责空间渲染。

如果一个元素的display属性被指定为inline-grid,且该元素是浮动或绝对定位的,那么实际计算出来的display值为grid。

CSS 2.1 Display章节相应修订为: "Specified Value"列添加了inline-grid, "Computed Value"列添加grid

网格容器的尺寸

grid container通过其所在的格式化上下文的规则来确定尺寸。 当作为BFC中的一个块级框时,它的大小计算和其他块级框一样,还带有一个为文档流里的块框计算的auto内联尺寸。 当作为IFC中的一个行内级框时,As an inline-level box in an inline formatting context, 它被作为是一个原子的行内级框(如inline-block)来计算大小。 无论是在IFC还是GFC中,网格容器的auto 块尺寸是其最大内容尺寸(max-content size)

当grid的大小遵循max-content constraint时,max-content size是相应轴上grid container轨道尺寸的总和。

当grid的大小遵循min-content constraint时,min-content size是相应轴上grid container轨道尺寸的总和。

CSS3尺寸计算的完整术语定义,请查阅[CSS3-SIZING]

网格项(Grid Items)

grid container的内容由多个grid items组成:

  • 每个网格容器的子元素成为一个grid item。
  • 每一个直接包含在网格容器中的连续文本被一个匿名grid item所包装。
  • 仅包含空格的匿名grid item不会被渲染,和设置了display:none一样。
  • grid item的浮动属性被忽略。

下面的例子展示了一组不同的网格项:

grid item的display属性被块状化(blockified): 如果网格容器文档流中的子元素的display属性是一个行内级(inline-level)的取值,它将被转换成其等价的块级(block-level)属性值。

有些display值将触发生成匿名框,比如一个缺失父元素定义的table-cell将自动补足匿名的tabletable-row 元素。 这个修正(fixup)行为必须发生在grid container的子元素被提升为grid item之前。 比如,给定连续的2个子元素,display属性为table-cell,那么首先会生成匿名的table封装盒包含这2个元素,然后成为一个grid item。

grid item为其包含的内容生成一个新的格式化上下文,但是grid item本身是网格级框(grid-level box),而不是块级框,因此只参与其grid container的GFC,而不是BFC

和block-level box类似,grid item的尺寸通过在其包容块中的grid area来定义,除了自动外边距和框对齐属性有所不同(请查阅:§11 Alignment and Spacing.)。

重新排列(order属性)

grid item可以使用order属性,这将影响它们的自动排列和渲染顺序。order仅在需要调整视觉顺序的时候使用,不能替代文档代码序。

z轴排序:z-index属性

grid items可以重叠,发生重叠时,除了会受order属性的影响之外,其渲染顺序和行内块(inline blocks)元素一样,因此我们同样可以使用z-index来控制grid item的z轴顺序。 当z-index取值不为auto时,即使grid item位置是静态的,仍将会创建一个堆栈上下文(stacking context),位于grid item外部的后代仍参与该堆栈上下文。

网格项的最小尺寸

对于一个overflow属性为visible(默认值)的grid item,当其min-width(或min-height)属性设置为auto值(CSS3新引入的取值)时,其最小尺寸依据下面的方式进行计算:

Specified Size Transferred Size Minimum Size
content size
min(specified size, content size)
min(transferred size, content size)
min(specified size, content size)

这里:

规定尺寸(specified size)
如果grid item的计算宽高是明确的(definite),比如使用指定长度、容器的初始尺寸或相对于一个规定尺寸的百分比,那么specified size就是那个尺寸(会受到最大尺寸属性的约束)。 否则未定义。
转移尺寸(transferred size)
如果grid item有一个内在长宽比(aspect ratio),并且其计算宽高是明确的,那么transferred size就是按照比例转换过的尺寸(会受到最大、最小尺寸属性定义的约束)。 否则未定义。
内容尺寸(content size)
content size是某个维度上的最小内容尺寸,如果有一个固定的长宽比,会被其正交维度上定义的最大最小尺寸属性所约束,并进一步在该维度上受到最大尺寸属性的约束(如果尺寸是确定的)。

尽管基于内容的尺寸常常是合适的,可以防止内容重叠或溢出。但在某些情况下并不适用: 比如文档使用了弹性尺寸,一个基于内容的最小尺寸可能会因为图片的扩展所引起的内容区域超出设计区域,此外浏览器在确定其尺寸时需要首先读取其完整内容,这在内容很长的时候会导致性能下降。