CSS进阶12-网格布局 Grid Layout

(注1:如果有问题欢迎留言探讨,一起学习!转载请注明出处,喜欢可以点个赞哦!)
(注2:更多内容请查看我的目录。)

1. 导读

网格布局是由CSS3引入的一种新的布局方式,提供了强大的布局能力。我们先来看一下W3C对于它的描述。

This CSS module defines a two-dimensional grid-based layout system, optimized for user interface design. In the grid layout model, the children of a grid container can be positioned into arbitrary slots in a predefined flexible or fixed-size layout grid.

翻译过来就是,这个CSS模块定义了一个二维的基于网格的布局系统,为用户界面设计进行了优化。在网格布局模型中,网格容器的子节点可以定位到预定义的可伸缩的或者固定大小的布局网格中的任意插槽中。

2. 简介

(注:本节内容不是规范性的)。
网格布局是一种新的CSS布局模型,它具有强大的能力来控制箱子及其内容的大小和位置。与面向单轴的Flexible Box Layout不同,Grid Layout针对二维布局进行了优化:在两个维度中都需要对齐内容。

Figure 1示例性的Flex布局示例

Figure2 示例性的网格布局示例

此外,由于能够明确定位网格中的项目,网格布局允许在视觉布局结构中进行戏剧性的转换,而不需要相应的标记更改。通过将媒体查询与控制网格容器及其子节点布局的CSS属性相结合,作者可以使其布局适应设备形状因素,方向和可用空间的变化,同时保持演示文稿内容的理想语义结构。

虽然许多布局可以用Grid或Flexbox来表示,但它们都有其特色。网格强制执行二维对齐,使用自上而下的布局方式,允许项目的显式重叠,并具有更强大的跨越能力。Flexbox专注于轴内的空间分布,使用更简单的自下而上的布局方法,可以使用基于内容大小的换行系统content-size–based line-wrapping system来控制其次轴,并依靠底层标记层次来构建更复杂的布局。预计这两者都将成为CSS作者的宝贵和补充工具。

2.1 背景和动机

随着网站从简单的文档发展到复杂的交互式应用程序,文档布局技术(例如浮动)不一定非常适合应用程序布局。通过组合使用表格,JavaScript或对浮动元素进行仔细测量,作者发现了实现所需布局的解决方法。适应可用空间的布局通常很脆弱,并且在空间受到限制时导致反直觉行为。作为替代方案,许多Web应用程序的作者选择固定布局,无法利用屏幕上可用渲染空间的更改。

网格布局的能力解决了这些问题。它为作者提供了一种机制,使用一组可预测的大小调整行为将可用空间分配给列和行。然后,作者可以将其应用程序的构造块元素精确定位和设置到由这些列和行的交叉点定义的网格区域grid area中。以下示例说明了网格布局的自适应功能,以及它如何更清晰地分离内容和样式。

2.1.1 将布局调整为可用空间

网格布局可用于智能调整网页中的元素的大小。下列例子表示一个游戏,其布局中包含五个主要组件:游戏标题,统计区域,游戏板,评分区域和控制区域。作者的意图是划分游戏空间,使得:

  • 统计区域总是直接出现在游戏标题下。
  • 游戏板显示在统计和标题的右侧。
  • 游戏标题和游戏板的顶部应始终对齐。
  • 当游戏达到最小高度时,游戏板的底部和统计区域的底部对齐。在所有其他情况下,游戏板将会扩展以充分利用所有可用的空间。
    *控件集中在游戏板下。
  • 得分区域的顶部与控制区域的顶部对齐。
    *得分区域在统计区域下方。
  • 得分区域与统计区域下方的控件对齐。


    Figuer 4 根据内容大小和可用空间排列五个网格项目

    Figuer 5 由于可用空间增加导致网格增长

    以下网格布局示例显示作者如何以声明方式实现所有尺寸,放置和对齐规则。

/* EXAMPLE 1 */
/**
* Define the space for each [grid item](https://www.w3.org/TR/css3-grid-layout/#grid-item) by declaring the grid
* on the [grid container](https://www.w3.org/TR/css3-grid-layout/#grid-container)
*/
#grid {
  /**
 * Two columns:
 *  1. the first sized to content,
 *  2. the second receives the remaining space
 *     (but is never smaller than the minimum size of the board
 *     or the game controls, which occupy this column [Figure 4])
 *
 * Three rows:
 *  3. the first sized to content,
 *  4. the middle row receives the remaining space
 *     (but is never smaller than the minimum height
 *      of the board or stats areas)
 *  5. the last sized to content.
 */
  display: grid;
  grid-template-columns:
    /* 1 */ auto
    /* 2 */ 1fr;
  grid-template-rows:
    /* 3 */ auto
    /* 4 */ 1fr
    /* 5 */ auto;
}

/* Specify the position of each [grid item](https://www.w3.org/TR/css3-grid-layout/#grid-item) using coordinates on
 * the 'grid-row' and 'grid-column' properties of each [grid item](https://www.w3.org/TR/css3-grid-layout/#grid-item).
 */
#title { grid-column: 1; grid-row: 1; }
#score { grid-column: 1; grid-row: 3; }
#stats { grid-column: 1; grid-row: 2; align-self: start; }
#board { grid-column: 2; grid-row: 1 / span 2; }
#controls { grid-column: 2; grid-row: 3; justify-self: center; }

<div id="grid">
  <div id="title">Game Title</div>
  <div id="score">Score</div>
  <div id="stats">Stats</div>
  <div id="board">Board</div>
  <div id="controls">Controls</div>
</div>

注意:有多种方式可以指定网格的结构以及网格项目grid items的位置和大小,每个网格项每种场景都进行了优化。

2.1.2 源顺序独立性 Source-Order Independence

继续前面的例子,作者还希望游戏适应不同的设备。此外,当纵向或横向观看时,游戏应该优化组件的放置(Figuer6和7)。通过将网格布局与媒体查询相结合,作者能够使用相同的语义标记,但可以重新排列元素的布局,而不是独立于源顺序,从而在两个方向上实现所需的布局。


FIguer 6 适合“肖像”方向的布局

Figuer 7 适合“风景”定位的布局

以下示例使用网格布局的能力来命名将被网格项grid item占据的空间。这允许作者避免在网格的定义改变时为网格项目重写规则。

/* EXAMPLE 2 */

@media (orientation: portrait) {
  #grid {
    display: grid;

    /* The rows, columns and areas of the grid are defined visually
     * using the grid-template-areas property.  Each string is a row,
     * and each word an area.  The number of words in a string
     * determines the number of columns. Note the number of words
     * in each string must be identical. */
    grid-template-areas: "title stats"
                         "score stats"
                         "board board"
                         "ctrls ctrls";

    /* The way to size columns and rows can be assigned with the
     * grid-template-columns and grid-template-rows properties. */
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto 1fr auto;
  }
}

@media (orientation: landscape) {
  #grid {
    display: grid;

    /* Again the template property defines areas of the same name,
     * but this time positioned differently to better suit a
     * landscape orientation. */
    grid-template-areas: "title board"
                         "stats board"
                         "score ctrls";

    grid-template-columns: auto 1fr;
    grid-template-rows: auto 1fr auto;
  }
}

/* The grid-area property places a grid item into a named
 * area of the grid. */
#title    { grid-area: title }
#score    { grid-area: score }
#stats    { grid-area: stats }
#board    { grid-area: board }
#controls { grid-area: ctrls }



<div id="grid">
  <div id="title">Game Title</div>
  <div id="score">Score</div>
  <div id="stats">Stats</div>
  <div id="board">Board</div>
  <div id="controls">Controls</div>
</div>

注:网格布局的重新排序功能特意仅针对视觉渲染,而不影响基于源顺序的语言顺序和导航。这使得作者可以操作视觉呈现,同时保持源顺讯的完整性并针对非CSS UA和线性模型(如语言和顺序导航)进行优化。
注:网格项目的放置和重新排序不能用于替代正确的源排序,因为这可能会破坏文档的可访问性。

3. 浏览器的兼容性

CSS网格布局从Safari 10.1, Firefox 52, Opera 44, Chrome 57开始受到支持,微软Edge在Edge 15会更新对网格布局的支持。

微软的浏览器(IE10–11和Edge 13-14)有一种比较旧的实现,所以有不少限制,我们会简单介绍新的实现方式和老的实现方式之间的区别,这样你能知道如何规避他们。

对于大多数布局,我们会使用下面的query特性来让老的浏览器对他们理解的特性也能工作:

@supports (display: grid) {
    .grid {
        display: grid;
    }
}

不支持浏览器@supports或网格的浏览器将不会生效。

为了能正确展示文中的示例,你需要使用支持网格布局的浏览器

4. 网格布局概念和术语

在网格布局中,一个网格容器的内容排列是依靠于他里面网格的位置与对齐方式。网格是由水平和垂直网格比交织组成,他将网格容器的空间分为网格区域,网格项目将放置在这些网格区域中。在网格中有两套网格线:一套是沿着水平方向的轴定义列的网格张,另一套是沿着垂直方向的轴定义行。


Figure 8 网格线:三个块轴和四个内嵌轴

4.1 网格线 Grid Lines

网格线是网格的水平和垂直的分界线。一个网格线存于行或列的两侧。他们可以参后数值指数,也可以由设计师指定名称。一个网格项目引用网格线来确定其网格中的位置属性。

下面两个例子创建了三个列网格线和四行网格线。第一个示例演示了设计师如何将一个使用网格行号的位置来确定网格项目的位置,第二个例子显式的设置了网格线。

/*具有三个列网格线和四个行网格线*/   
#grid {
  display: grid;
  grid-definition-columns: 150px 1fr; /*两列*/
  grid-definition-rows: 50px 1fr 50px;/*三行*/
}

#item1 { 
  grid-column: 2;
  grid-start: 1; 
  grid-end: 1; 
}   
/* 使用命名行,实现先前例子相等效果布局 */
#grid {
  display: grid;
  grid-definition-columns: 150px "item1-start" 1fr "item1-end";
  grid-definition-rows: "item1-start" 50px 1fr 50px "item1-end";
}

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

4.2 网格轨道和单元格 Grid Tracks and Cells

网格轨道是“grid column”或者“grid row”的另一种术语,换句话说,他就是两条相邻网格线之间的空间。每个网格轨道可以设置一个大小,用来控制宽度或高度或者行可能会增长。
网格单元是网格行和网格列的交集。它是定位网格项时可以引用的网格的最小单元。
在接下来的例中定义了一个三行两列的网格。第一列设置一个固定宽度“150px”,第二列设置是一个弹性尺寸,它是一个未赋值的网格空间,从而根据网格容器的变化而进行宽度的改变。如果网格容器的宽度是“200px”,那么第二列的宽度是“50px”。

#grid {
  display: grid;
  grid-definition-columns: 150px 1fr; /* 两列*/
  grid-definition-rows: 50px 1fr 50px /* 三行  */
}   

4.3 网格区域 Grid Areas

网格区域是一个逻辑空间,主要用来放置一个或多个网格项目。他有四条网格线,网格区域每边一条,四边相交组织的网格轨道可以调整网格区域大小。可以使用“grid-template”属性为网格容器显式的设置网格区域,或者隐式的使用网格线创建网格区域。网格项目可以使用“grid-placement”属性将其分配给一个网格区域。

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

#item1 { grid-area: a }
#item2 { grid-area: b }
#item3 { grid-area: b }

#item2 { align-self: head }
#item3 { justify-self: end; align-self: foot }   

4.4 网格容器 Grid Containers

通过“display”属性给一个元素显式的设置了“grid”或者“inline-grid”属性值,这个元素将自动变成网格容器

一个网格容器将会创建一个新的网格格式化上下文内容(grid formatting context)。除是网格布局代替了块布局之外,网格格式化上下文和块格式化上下文是相同的。浮动对网格容器不会有影响,而且网格容器的margin不会和内容的margin相互层叠。

因为网格容器不是块容器,所以一些属性在网格布局中将会失效:

  • 多栏布局模块中的所有“column-*”属性运用在网格容器上将失效。
  • “float”和“clear”使用在网格项目上将失效
  • “vertical-align”使用在网格项目上将失效
  • “::first-line”和“::first-letter”这样的伪元素不能应用在网格容器上。
    注意:如果一个元素指定了“display”值为“inline-grid”,并且此元素具有“float”或绝对定位时,这个元素将的“display”值将会以“grid”显示。

4.5 子网格容器 Subgrids

有时候我们需要给网格项目设置为网格容器。那么我们可以使用“display:grid”,在这种情况之下,他是独立于网格布局的。而在某些情况下,要为内容设置多个网格,让网格项目相互一致,在这种情况之下,我们需要通过“dsplay”属性显式的设置为“subgrid”,让其显示为次网格。

例如,我们一个标签和输入框组成的列表表单:

<ul>
  <li><label>Name:</label> <input name=fn></li>
  <li><label>Address:</label> <input name=address></li>
  <li><label>Phone:</label> <input name=phone></li>
</ul>   

我们希望这个标签和输入文本框对齐,我们想给每个列表标签设置一个边框样式,这次就可以通过次网格布局实现。
ul {
display: grid;
grid-auto-flow: rows;
grid-definition-columns: auto 1fr;
}
li {
display: subgrid;
margin: 0.5em;
border: solid;
padding: 0.5em;
}
label {
grid-column: 1;
}
input {
grid-column: 2;
}

4.6 网格项目 Grid Items

在一个网格容器中包含了0个多个网格项目。网格容器的子元素称为网格项目以及运行在网格容器的文本将自动变成一个匿名的网格项目,然后如果只是一个空格,这个匿名项目就相当于“display:none”一相被隐藏在网格容器之中。

一个网格项目创建一个新的格式化上下文内容。这种格式化上下文内容类型取决于它的“display”值。

4.7 网格项目顺序order

网格项目顺序可以像flexobx模块一样,通过order属性来对网格项目进行顺序的重排。

5. 基本示例

以下示例显示了一个三列轨道网格,其中创建的行最小为100像素,最大为自动。条目使用线性定位放置在网格上。

.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 10px;
  grid-auto-rows: minmax(100px, auto);
}
.one {
  grid-column: 1 / 3;
  grid-row: 1;
}
.two { 
  grid-column: 2 / 4;
  grid-row: 1 / 3;
}
.three {
  grid-row: 2 / 5;
  grid-column: 1;
}
.four {
  grid-column: 3;
  grid-row: 3;
}
.five {
  grid-column: 2;
  grid-row: 4;
}
.six {
  grid-column: 3;
  grid-row: 4;
}



<div class="wrapper">
  <div class="one">One</div>
  <div class="two">Two</div>
  <div class="three">Three</div>
  <div class="four">Four</div>
  <div class="five">Five</div>
  <div class="six">Six</div>
</div>

参考

https://www.w3.org/TR/css3-grid-layout/#grid-formatting-context
前端精选文摘:css之GFC 神奇背后的原理(整理)
Getting to know CSS Grid Layout
翻译 | CSS网格(CSS Grid)布局入门
MDN-网格布局
MDN-CSS Grid Layout

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,738评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,377评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,774评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,032评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,015评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,239评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,724评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,374评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,410评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,457评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,132评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,733评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,804评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,022评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,515评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,116评论 2 341

推荐阅读更多精彩内容