初识Grid布局

这里谈论的网格布局不是Bootstarp中的网格布局(貌似前几天Bootstarp发布v4.0版本了~),而是浏览器支持的一种新的布局方式。之前虽然略有耳闻,但一直没有去了解,最近发现貌似浏览器的支持还不错,于是决定系统地学习一下。

好像很久没有正儿八经地学习CSS了~

<!--more-->

建议使用Chrome或Firefox运行相关代码,可以直接看见相关的网格辅助虚线,十分方便。

参考:

1. 网格

要在某个容器上使用网格布局,只需要声明即可

display: grid

该容器下的第一代子元素(包括块级元素和内联元素)都会在网格中进行布局。

对于网格布局,我的理解是:想象成在容器上画横线和竖线,将容器变成一张网格,然后将其子元素摆放到指定的格子上,从而实现子元素的布局

其中由横线和竖线划分的最小格子,被称为网格单元;容器子元素所占据的位置,被称为网格区域

上面这个过程包含了几个概念:

  • 画横线,画竖线
  • 指定子元素的位置

还有几个隐含的概念:网格单元的宽度和高度、子元素之间的重叠等。接下来我们来看看这几个概念对应的语法

grid-template-columns

用来确定网格的列数,以及每一列的宽度

grid-template-columns: 200px repeat(3, 10px) 1fr;
  • 每一列用空格分隔
  • repeat函数用于生成重复的列,第一个参数是重复的数量,第二个参数是一个轨道列表(也可以使单个列)
    • 当显示指定列数后,即使列宽总和没有填满总容器的高度,或者容器宽度发生改变,列数也是不会发生改变的,
    • 数量还支持auto-fill关键字,表示根据容器宽度自动生成最大宽度为第二个参数的列轨道,数量由容器宽度控制
  • 支持任何CSS长度单位,除此之外还提供了fr单位,表示网格容器可用空间的一等份,跟flex-grow属性的作用类似,当混合使用固定长度单位和fr时,会从总容器尺寸中减去已被使用的,再计算fr代表的尺寸
  • 列宽度的优先级大于子元素本身的宽度,即不会由于子元素自身的宽度改变列宽,因此可以实现类似于负margin的效果
  • 在网格布局中,子元素的盒子模型以box-sizing:border-box处理

当声明了列数n之后,默认情况下前n个子元素就会依次摆放在对应的列下,后面的元素另起一行,依次类推(跟flex-wrap有点像)。当然,可以改变这种默认的处理方式,后面再提。

grid-template-rows

用于确定网格的行数

一般情况下不需要显示声明行数~

grid-auto-rows

用于指定隐使行高

 grid-auto-rows: 200px;
 grid-auto-rows: minmax(100px, auto);
  • 默认情况下行的高度由内容撑开
  • 如果显示使用grid-template-rows声明了行高,则grid-auto-rows的高度会被忽略
  • minmax函数用于指定行的最小高度和最大高度,类似于min-heightmax-height的展示效果

网格间距

  • grid-column-gap,用于指定两列之间的间距
  • grid-row-gap,用于指定两行之间的间距
  • grid-gap,上面两个属性的简写,第一个值是行间距,第二个值是列间距

需要注意的是间距与列宽以及容器自身宽度之间,可能发生过分受限的情形。这种情况下,可能会发生列超出容器范围的情形

2. 定位

2.1. 基于网格线的定位

上面通过指定列和行来绘制网格,每一列和每一行交叉绘制网格单元,他们的边界线即为网格线。网格线的编号顺序取决于文章的书写模式,在从左至右书写的语言中,编号为 1 的网格线位于最左边。

水平方向的网格线即为行线,竖直方向的网格线即为列线。相关语法文档里面说的很详细

坐标

有了网格线的概念后,我们就可以确定每一个网格单元的坐标。而对于网格容器内的子元素来说,我们也可以直接指定他们需要占据的的网格单元

 grid-column-start: 1;
 grid-column-end: 3;
 grid-row-start: 1;
 grid-row-end: 3;
  • grid-column-start,指定子元素的起始列
  • grid-column-end,指定子元素的终止列
  • grid-row-start,指定子元素的起始行
  • grid-row-end,指定子元素的终止行

可见网格区域只能是一个矩形框。如果终止行超过现有行数,则会隐式创建新行。

只有网格容器的第一代子元素会受网格布局的限制。当然,如果声明子元素也为display:grid,则可以实现嵌套的网格布局,需要注意的是网格属性不具备继承特性。

简写

CSS提供了指定行列的简写方式

grid-column: 1/3;
grid-row: 1/2;
  • grid-column: start-column/end-column,其中start-column表示起始列,end-column表示终止列
  • grid-row: start-row/end-row

除了手动指定指标之外,也可以通过关键字span来表明占据的网格数量

grid-column: 1/ span 2

表示起始列线为1,占据2个网格单元(即终止列线为3)

此外还可以使用grid-area这个终极大招

grid-area: 1 / 1 / 4 / 2;

在从左往右的书写顺序语言中,上面从左往右依次对应grid-row-startgrid-column-startgrid-row-endgrid-column-end

省略

可以省略grid-column-endgrid-row-end,默认情况下会分配单行或单列。

这意味着在简写方式中,可以省略分母

grid-coulmn: 2

表示grid-column-end:2

反向计数

可以从行和块结束线开始反方向计数,但是我感觉这种操作不是很直观~

层级

多个网格项目可以占据同一个网格单元,此时,默认后面元素覆盖前面元素的。可以通过z-index指定层级

2.2. 网格模板

讲道理,我第一次看到这里的时候,真的是被震惊到了:CSS还能这么玩儿!!

直接拿文档的demo来了

<style>
.header {
    grid-area: hd;
}

.footer {
    grid-area: ft;
}

.content {
    grid-area: main;
}

.sidebar {
    grid-area: sd;
}

.wrapper {
    display: grid;
    grid-template-columns: 1fr 2fr;
    grid-auto-rows: minmax(100px, auto);
    grid-template-areas: 
        "hd hd" 
        "sd main" 
        "ft ft";
}    
.wrapper > div{
    margin: 10px;
    background-color: red
}
</style>
<body>
     <div class="wrapper">
        <div class="header">Header</div>
        <div class="sidebar">Sidebar</div>
        <div class="content">Content</div>
        <div class="footer">Footer</div>
    </div>
</body>

这段代码实现了一个常见的布局。在前面我们了解了grid-area的用法,是基于网格线定位的简写方式。然而这里我们看到了它的另外一种用法:命名网格区域

注意grid-template-areas语法,通过命名完成了一个字符串模板,实际上渲染出来的页面,就是该模板的布局样式~这才是正儿八经的可视化布局啊!!

响应式布局

看到这个使用方式,想到的第一件事情就是响应式布局的实现。

通过媒介查询和grid-template-areas,我们可以很轻松地完成响应式布局,因为只需要改变模板,浏览器就会重新渲染。这跟Bootstrap中的栅格系统不同,栅格系统实现响应式布局的原理是

每一个列的宽度由百分比控制,然后在不同屏幕宽度下小屏幕的样式类被高屏幕的样式类覆盖。

然而grid-template-areas给予我们更大的灵活度,样式也更加简洁~

简写

命名网格方式提供了两个简写方式

 grid-template:
            "hd hd" minmax(100px, auto)
            "sd main" minmax(100px, auto)
            "ft ft" minmax(100px, auto) / 1fr 2fr

分别对应grid-template-areas网格模板,grid-auto-rows单行高度和grid-template-columns列。

此外还有grid的简写方式,可以应用跟grid-template相同的属性值。使用缩写容易让人困惑,这里还是要谨慎一点。

注意事项

网格模板中,命名的区域只能围城矩形区域,可以使用.来表示留白

2.3. 网格线命名

在用 grid-template-rowsgrid-template-columns 属性定义网格时,可以为网格中的部分或全部网格线命名

grid-template-columns: [col-1-start] 1fr [col-1-end] 1fr 1fr

上面为将第一根垂直网格线命名为col-1-start,将第二根网格线命名为col-1-end

网格线的名称与其序号具有相同的作用,即可以在grid-column等属性中使用。与数字序号相比,使用网格线的命名更加直观和语义化,且不会根据网格线数量轻易改变。

此外,甚至可以为同一根网格线取多个名字,名称间以空格分隔。

3. 对齐

网格包含对齐特征,提供了方便的对齐方式,用于子元素在其网格区域内的对齐。

aligin-itmes

用于指定网格容器子元素的对齐方式

flexalign-items类似的作用,具体取值可参考这里

align-self

用于指定子元素覆盖其网格容器指定的对齐方式

flexalign-self类似的作用

4. 小结

这里简单整理了CSS网格布局的相关用法,其中被网格模板布局给震惊到了。除此之外,还有默认布局规则、书写模式等内容没有去了解。

尽管近一段时间可能还不太敢尝试在项目中使用网格布局,不过了解相关的发展方向还是很有必要的。个人感觉,未来网格布局应该会一统江湖的哈哈~