将来布局之星Grid

grid是一个趋势

Grid-layout不是为了取代flex-layout,它是flex的补充。grid擅长二维布局,flex擅长一维布局。他们须要各司其职。css

千呼万唤始出来的grid-layout终于在2017年3月开始支持获得了部分浏览器的支持。
css3


flex并不能知足咱们对于页面总体布局的需求, Don't use flexbox for overall page layout这篇文章阐述了这么一个观点:不要用弹性盒子布局总体的页面。而咱们在日常使用中也能感觉到flex在作总体页面布局的时候,仍是有不完善的地方,仍是须要大量的inline-box、float来排布内容(// TODO 售后单详情页做为例子);另一个问题咱们后面了解了grid以后会再说

grid = table2.0?

二维布局方式,能够按照行列方式排列内容。把页面划分为几块,指定不一样内容区块的大小、位置和层级。算法

有观点说grid很像table2.0,他们是有相同之处的。好比都是把元素排列成行和列。可是表格和grid的区别在于,表格是有内容结构的,不能很自由地在里面作布局。而grid内部元素能够自由设定位置,容许重叠和设定层级的样。segmentfault

几个术语

网格容器 grid-container

网格容器为其内容创建新的网格格式化上下文,是内部网格项的边界。数组

网格线 grid-line

水平垂直分割线,构建出网格轨道、网格单元格和网格区域。就像经纬,分割出南北半球、东西半球,热带、南北温带、南北寒带。网格线是有数字索引的,也能够本身取名字。经纬线都是有数字的,也能够命名,好比本初子午线、赤道。浏览器

网格轨道 grid-track

网格内容块之间的水平或垂直的空间。滨盛、滨和、滨兴、滨安、滨康,江陵、江晖、江汉、江虹。(郊区的经典命名,摊手)bash

网格单元格 grid-cell

网格内容的单位区块,是能够放置内容的最小区块。好比用横纵三条网格线划分了页面,那么单元格就是九宫格中的一块网络

网格区域 grid-area

以网格线为界划定一块区域。本来网易和阿里巴巴都是占用一个单元格,如今都要扩建了,占用两个,两个加起来就是它们各自的网格区域。框架

两个例子

在了解具体的属性以前,来一个最简单的例子ide

这样看会以为grid仍是颇有趣的,先分块,而后指定每一块的区域范围。块是能够重叠的。可是这只是开始,grid为咱们带来了17个新特性,在了解属性以前再来看一个例子,经典布局方案 —— 圣杯布局 holy grail layout。

  • 网页常见布局:页眉、页脚、主要内容区块、两边都有一个侧边列。
  • 两边带有固定宽度,中间宽度可变
  • 中间三列内容等高
  • 页脚总处于窗口的底部,即便内容没有填满整个窗口的高度
  • 响应式布局,在较小的视窗中全部模块都100%宽度显示

你们能够迅速在脑子里码一下这个界面写个样式,不至于说复杂 但总之不简单吧。咱们看看grid是怎么作的

// key code
.hg__header { grid-area: header;}
.hg__footer { grid-area: footer;}
.hg__main { grid-area: main;}
.hg__left { grid-area: navigation;}
.hg__right { grid-area: ads;}

.hg {
    display: grid;
    grid-template-areas:    "header header header"
                            "navigation main ads"
                            "footer footer footer";
    grid-template-columns: 250px 1fr 300px;
    grid-template-rows: 100px 
                        1fr
                        80px;
    min-height: 100vh;
}复制代码

步骤:

  1. 定义网格

    1. 设定网格区域别名,grid-area: ,指定块所在区域的时候方便引用。前一个简单的例子,grid-area是用来指定网格区域上下左右的网格线各是什么,因此grid-area既能够指定网格区域的大小和位置,还能够设定区域的别名。
      grid-area: main;
           grid-row-start: main;
           grid-column-start: main;
           grid-row-end: main;
           grid-column-end: main;复制代码
    2. grid-template-areas: "- - -" "- - -" "- - -";能够很是直观指定网格的布局。它的值是空格分隔的字符串数组,每个字符串表明一行。每个字符串中是空格分隔的网格单元格列表,一个网格区域要跨几列就写几回。好比例子中header、footer写了三次,它们都是跨整个区域宽度的。
  2. 设定单元格的高度和宽度

    有一个css3的新单位,fr,在一串数值中出现的话表示根据比例分配某个方向上的剩余空间。设定行高的时候分行写是为了清晰一点。

  3. 设定固定位置的页脚

  4. 响应式布局,使用媒体查询。重置布局和行高

grid-container

1. grid-template-columns | grid-template-rows

grid-template-columns: <track list>定义网格的行数、列数、网格大小

有不少中形式,常见的是这么几种:

grid-template-columns: 100px 1fr;
grid-template-columns: [linename] 100px;    // 定义网格线名字
grid-template-columns: [linename1] 100px [linename2 linename3]; // 一条网格线多个名字
grid-template-columns: minmax(100px, 1fr);  // 最小100px, 最大满屏
grid-template-columns: fit-content(40%);    // 指定最大值不超过屏宽40%
grid-template-columns: repeat(3, 200px);    // 三列200px复制代码
// 给网格线指定名字
.box {
    grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
    grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}复制代码

2. grid-template-areas

定义网格区域,使用grid-area调用声明好的网格区域名称放置对应的网格项目。定义一个显式的网格区域。

3. grid-row-gap、grid-column-gap

定义网格之间的间距(不包括grid-item到容器边缘的间距)

4. justify-items: start | end | center | stretch(默认);

定义网格子项的内容水平方向上的对齐方式,相似于flex-container的justify-content,只不过没有space-around和space-between

1bc096d4ee73927e.png
1bc096d4ee73927e.png

35fecd4fbf754a84.png
35fecd4fbf754a84.png

9a2b4b82c9b6a65b.png
9a2b4b82c9b6a65b.png

85e7fb64351898e4.png
85e7fb64351898e4.png

5. align-items: start | end | center | stretch(默认);

定义网格子项的内容垂直方向上的对齐方式,相似于flex-container的align-items

7a410b6d17acd72e.png
7a410b6d17acd72e.png

20f8f733235797ea.png
20f8f733235797ea.png

9e1f32b77d573d04.png
9e1f32b77d573d04.png
85e7fb64351898e4.png
85e7fb64351898e4.png

6. justify-content: start | end | center | stretch | space-around | space-between | space-evenly;

当出现网格容器容量大于网格总大小,好比每个网格子项都用了固定值的时候,指定网格在网格容器中和纵轴的对齐方式。后面三个属性值的区别在:

  1. space-around: 始末两端的间距是网格间距的一半
  2. space-between: 始末两端的间距为零
  3. space-evenly: 始末两端的间距与网格间距相等




7. align-content: start | end | center | stretch | space-around | space-between | space-evenly;

和justify-content对齐方向垂直,指定网格和横轴的对齐方式。

e14e12bdfbf2e3e4.png
e14e12bdfbf2e3e4.png

8006fb09977ce5c8.png
8006fb09977ce5c8.png

61ffebd9e0da3f0b.png
61ffebd9e0da3f0b.png
28e49f66a9c4455a.png
28e49f66a9c4455a.png

b9bfc04642c818d7.png
b9bfc04642c818d7.png

f1845a4b578d8191.png
f1845a4b578d8191.png

f06633de75642a36.png
f06633de75642a36.png

8. grid-auto-columns、grid-auto-rows; grid-auto-flow

grid-auto-columns | grid-auto-rows做用是网格单元格不够的时候建立隐式的网格放置grid-item。看一个例子

咱们只定义了一个1×1的网格容器,box1放了进来,而后其余的三个怎么办呢?漏出来。box2接在box1后面渲染至屏幕右侧,box3和box4在底下渲染,高度仅仅为内容高度。

指定了grid-auto-columns: 200px; grid-auto-rows: 200px;,至关于在容器中横纵都建立了更多的隐式的200*200的网格单元来盛放可能多出来的元素。

与之相关的还有另外一个属性:grid-auto-flow,在咱们没有设定这个属性的时候,多余的元素也按照从左到右从上到下的顺序排列,这个属性是控制自动布局算法的。

grid-auto-flow: row | column | row dense | column dense;

  1. row为默认值,表明自动布局算法在每一行中依次填充,只有必要时才会添加新行。
  2. column表明自动布局算法在每一列中依次填充,只有必要时才会添加新行。
  3. dense表明告诉自动布局算法若是更小的子项出现时尝试在网格中填补漏洞。(不建议使用,可能会使布局产生混乱)

grid-item

1. grid-column-start | grid-column-end | grid-row-start | grid-row-end

grid-row: grid-row-start / grid-row-end
grid-column: grid-column-start / grid-column-end | grid-column-start | span <value>复制代码

f0988aebf7ce8786.png
f0988aebf7ce8786.png

若是没有显式设置grid-column-end/grid-row-end,网格子项将默认跨越一个网格单元。此外,网格子项能够互相重叠,可使用z-index来控制他们的层叠顺序。

有一些元素,咱们想让它贯穿整个视口,好比像 header、footer,对于小屏幕,两列布局:

.header, .footer {
  grid-column: 1 / 3;
}复制代码

不幸的是,当咱们换到大屏的时候,一行12列,这些元素将仅仅占满前两列,并不会占满12列,咱们须要定义新的grid-column-end,而且把他的值设为 13. 这种方式比较麻烦,还有一种简单的方式,grid-column: 1 / -1;,这样不论在什么屏幕尺寸下,它们都是占满整行的了。就像下面这样:

.header, .footer {
  grid-column: 1 / -1;
}复制代码

2. grid-area

grid-area: <name> | grid-row-start / grid-column-start / grid-row-end / grid-column-end

3. justify-self: start | end | center | stretch 网格单元格内容水平方向上的对齐方式 。与flex中的justify-self。

c096a95f6300d932.png
c096a95f6300d932.png

bb01f2f4ea312d78.png
bb01f2f4ea312d78.png

3ca2ef564834e834.png
3ca2ef564834e834.png

caddebe3320088bf.png
caddebe3320088bf.png

4. align-self: start | end | center | stretch 网格单元格内容垂直方向上的对齐方式 。相似与flex中的align-self。

1f1b1806e925fe2b.png
1f1b1806e925fe2b.png

grid-align-self-end.png
grid-align-self-end.png

0ad87bbf53ecc6a3.png
0ad87bbf53ecc6a3.png

caddebe3320088bf.png
caddebe3320088bf.png

grid-layout带来的函数

1. repeat()

repeat()提供了一个紧凑的声明方式。若是行列太多而且是规则的分布,咱们能够用函数来作网格线的排布。

grid-template-columns: repeat(3, 20px [col-start]) 5%;
// 等价于
grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start] 5%;
}复制代码

2. minmax()

minmax()至关于为网格线间隔指定一个最小到最大的区间。若是min>max,这个区间就失效了,展现的是min。

3. fit-content()

fit-content()至关于 min('max-content', max('auto', argument));

flex布局的另外一个问题

flex-layout的布局另一个问题是,在有大量内容绘制到页面上、或者内容更改的状况下,在2g或者网络加载不稳定的时候,页面是不稳定的。Flexbox vs Grid page layout。内容以流式从服务端获取用户能够在页面所有加载出来以前就看到内容,可是在flex布局下会致使布局的重排。正是由于flex自己就是一个弹性的布局。但grid也不是彻底能够避免布局重排的问题——有前提:

必须让你的网格划分是能够预先肯定的,好比是根据视窗宽高肯定的。若是是根据内容而定,那么也是会崩坏的。复制代码

下面的例子中,网格的列宽根据内容而定,所以也会根据内容而变。后面的aside并无定义在网格容器当中,是一个动态建立的元素。一旦被建立就会致使页面重绘

.container {
    display: grid;
    grid-template-columns:
    (foo)   max-content,
    (bar)   min-content,
    (hello) auto;
}

aside {
    grid-column: 4;
}复制代码

可是也不要放弃flex-layout,它是目前为止最厉害的页面布局属性,是时代召唤的结果,只是它并不适合布局整个页面框架。flex在响应式布局中是很关键的,它是内容驱动型的布局。不须要预先知道会有什么内容,能够设定元素如何分配剩余的空间以及在空间不足的时候如何表现。显得较为强大的是一维布局的能力,而grid优点在于二维布局。这也是他们设计的初衷。

大概能够设想,网格布局被普遍支持以后会出现不少网格布局内嵌flex的布局情形。

subgrid暂时尚未浏览器支持,规范也是在改动之中的,因此先不介绍了。

参考

Don't use flexbox for overall page layout

(译)原生CSS网格布局学习笔记

网格布局(CSS Grid Layout)浅谈

CSS Grid Layout

拥抱将来的CSS布局方式:flex与grid布局

A Complete Guide to CSS Grid Layout

相关文章
相关标签/搜索