前端开发者学堂 - fedev.cn

CSS Grid布局:合并单元格布局

发布于 大漠

CSS Grid布局:网格单元格布局》一文中通过一些简单的实例介绍了如何给容器定义网格,并且怎么使用网格线或者网格区域来实现单元格这样的简单的布局。在文章结尾之处也提到过,这样的单元格如同表格一样,仅仅一个个独立的单元格是无法满足一些复杂的Web布局,我们需要将多个单元格合并在一起,拼装成一个稍为复杂一点的布局。简单点说,就是由单元格慢慢过渡到具有合并单元格的布局(在脑海中想想曾经爱过的table)。

那么接下来我们要介绍的是如何使用CSS Grid Layout实现一些更有意思的布局。

##期待中的布局...

在脑海中有很多种布局效果,那我们先来看一种常见的,简单的布局模板,如下图所示:

布局模板

上图也是这一章需要实现的一种布局方式,就将其称为网格的合并单元格布局,因为他和表格中的合并单元格是非常的相似。

大家是否还记得,在《CSS Grid布局:网格单元格布局》一文中通过网格线的grid-column-startgrid-column-endgrid-row-startgrid-row-end(或者grid-column: start / endgrid-row: start / end)可以非常方便的实现单元格的布局,那么这种方式同样可以运用于合并的单元格布局中。如此一来,如果我们需要实现上图展示的布局,就可以给每个子元素设置网格线,然后划分出各自的占位区。来看看其对应的网格线:

网格线

有了这样的示意图,我想要实现这个布局对于大家来说并不是一件复杂的事情。接下来我们通过实例来演示。

##基于网格线实现单元格合并

从示图中不难发现:

  • A区(.a)跨越了三列和两个列间距,对应网格布局中,他占了五个网格,从网格线上来划分,他是列网格线line1line6和行网格线line1line2圈起的空间
  • C、D、E、G和H几个区与以前介绍的单元格并无不同之处,对于的网格线可以看上面的网格线展示示意图
  • F区(.f)跨越了两列和一个列间距,对应网格布局中,他占了三个网格,从网格线上来划分,他是列网格线line1line4和行网格线line5line6圈起的空间
  • I区(.i)和F区类似,只不过他是列网格线line3line6和行网格线line7line8圈起的空间
  • J区(.j)和A区类似,只不过他是列网格线line1line6和行网格线line9line10圈起的空间
  • B区(.b)和前面几个区都有点不一样,他是将行合并在一起,跨越了网格中所有的行,从网格线上来划分,他是列网格线line7line8和行网格线line1line10圈起的空间

从外观上看,这跟平时看到的两列布局非常的相似。不同之处是这里通过网格来实现。来看看具体代码:

#####HTML

<div class="wrapper">
  <div class="box a">A</div>
  <div class="box b">B</div>
  <div class="box c">C</div>
  <div class="box d">D</div>
  <div class="box e">E</div>
  <div class="box f">F</div>
  <div class="box g">G</div>
  <div class="box h">H</div>
  <div class="box i">I</div>
  <div class="box j">J</div>
</div>

#####CSS

body {
  padding: 50px;
}
.wrapper {
  display: grid;
  grid-template-columns: 100px 10px 100px 10px 100px 10px 100px;
  grid-template-rows: auto 10px auto 10px auto 10px auto 10px auto;
}
.box {
  background-color: #444;
  color: #fff;
  font-size: 150%;
  padding: 20px;
  text-align: center;
}
.a{
  grid-column: 1 / 6; 
  grid-row: 1 / 2;
}
.b {
  grid-column: 7 / 8; 
  grid-row: 1 / 10; 
  background: orange;
}
.c { 
  grid-column: 1 / 2; 
  grid-row: 3 / 4;
}
.d { 
  grid-column: 3 / 4; 
  grid-row: 3 / 4;
}
.e { 
  grid-column: 5 / 6; 
  grid-row: 3 / 4;
}
.f { 
  grid-column: 1 / 4; 
  grid-row: 5 / 6;
}
.g {
  grid-column: 5 / 6; 
  grid-row: 5 / 6;
}
.h {
  grid-column: 1 / 2; 
  grid-row: 7 / 8;
}
.i {
  grid-column: 3 / 6; 
  grid-row: 7 / 8;
}
.j {
  grid-column: 1 / 6; 
  grid-row: 9 / 10;
}

效果如下:

基于网格线合并单元格

在线案例

从效果图中,不难发现,虽然在B区通过网格线定义了跨行:

.b {
  grid-column: 7 / 8; 
  grid-row: 1 / 10; 
  background: orange;
}

但浏览器实际解析并不是跟我们想象的一样。为什么跨行没有效果呢?具体是什么原因,说实在的,我也不知道,或许有一天会更正这个问题。那么有没有方法能解决呢?我们先继续往下看吧。或许你能找到你需要的答案。

##基于网格线使用关键词span实现单元格合并

在CSS Grid Layout布局中除了使用网格线合并单元格之外,还可以使用关键词span来实现单元格合并。接下来的实例,将使用span关建词完成上例一样的效果。

.wrapper {
  display: grid;
  grid-template-columns: 100px 10px 100px 10px 100px 10px 100px;
  grid-template-rows: auto 10px auto 10px auto 10px auto 10px auto;
}
.a{
  grid-column: 1 / span 5; 
  grid-row: 1;
}
.b {
  grid-column: 7; 
  grid-row: 1 / span 9; 
  background: orange;
}
.c { 
  grid-column: 1; 
  grid-row: 3;
}
.d { 
  grid-column: 3; 
  grid-row: 3;
}
.e { 
  grid-column: 5; 
  grid-row: 3;
}
.f { 
  grid-column: 1 / span 3; 
  grid-row: 5;
}
.g {
  grid-column: 5; 
  grid-row: 5;
}
.h {
  grid-column: 1; 
  grid-row: 7;
}
.i {
  grid-column: 3 / span 3; 
  grid-row: 7;
}
.j {
  grid-column: 1 / span 5; 
  grid-row: 9;
}

实现的效果一样:

基于网格线合并单元格

在线案例

##自定义网格线名称

前面的示例,都是使用默认的网格线名称来制作网格布局,其实在CSS Grid Layout模块中还提供了自定义网格线名称,然后使用定义好的名称来制作网格布局。在CSS Grid Layout自定义网格线名称都放置在()内。比如在下面的示例中,定义了列第一网格线名称为col1-start(对应的列网格线line1),然后后面紧跟第一列的轨道宽度100px,然后就是第一列后面的网格线col1-end(对应的列网格线line2)。行网格线也是类似。如下图所示:

自定义网格线名称

在网格定义网格线的方式如下:

.wrapper {
  display: grid;
  grid-template-columns: (col1-start) 100px (col1-end) 10px (col2-start) 100px (col2-end) 10px (col3-start) 100px (col3-end) 10px (col4-start) 100px (col4-end);
  grid-template-rows: (row1-start) auto (row1-end) 10px (row2-start) auto (row2-end) 10px (row3-start) auto (row3-end) 10px (row4-start) auto (row4-end) 10px (row5-start) auto (row5-end);
}

写个实例,通过自定义的网格线实现上例一样的网格布局效果:

.wrapper {
  display: grid;
  grid-template-columns: (col1-start) 100px (col1-end) 10px (col2-start) 100px (col2-end) 10px (col3-start) 100px (col3-end) 10px (col4-start) 100px (col4-end);
  grid-template-rows: (row1-start) auto (row1-end) 10px (row2-start) auto (row2-end) 10px (row3-start) auto (row3-end) 10px (row4-start) auto (row4-end) 10px (row5-start) auto (row5-end);
}
.a{
  grid-column: col1-start / col3-end; 
  grid-row: row1-start;
}
.b {
  grid-column: col4-start / col4-end; 
  grid-row: row1-start / row5-end; 
  background: orange;
}
.c { 
  grid-column: col1-start; 
  grid-row: row2-start;
}
.d { 
  grid-column: col2-start; 
  grid-row: row2-start;
}
.e { 
  grid-column: col3-start; 
  grid-row: row2-start;
}
.f { 
  grid-column: col1-start / col2-end; 
  grid-row: row3-start;
}
.g {
  grid-column: col3-start; 
  grid-row: row3-start;
}
.h {
  grid-column: col1-start; 
  grid-row: row4-start;
}
.i {
  grid-column: col2-start / col3-end; 
  grid-row: row4-start;
}
.j {
  grid-column: col1-start / col3-end; 
  grid-row: row5-start;
}

效果和预期的一样,可以打示演示案例查看效果。

在线案例

##自定义网格线配合关键词span合并单元格

上面那种自定义网各线的方法好是好,但也有一个问题,如果网格线少,还是蛮方便的,不过网格一多,网格线也多起来,每条网格线都定义名称是不是太费时费力了。其实在CSS Grid Layout中不需要这么做,你完全可以给网格线定义相同的名称,然后使用关键词span添加到特定的目标网格线。这种方法对于创建一些复杂的网格(包括多个网格与列间距)是非常方便的。

在实际使用中,可以在网格内容轨道前的网格线都定义为col,而在列间距轨道前的网格线都定义为gutter。在调用时,可以使用col <line number>来指定开始的网格线,配合关键词span <number of lines of that name>来指写网格的跨度。这样说或许有些搞不明白,我们来看一个简单的示例,比如说我们要实现下图网格效果:

自定义网格线名称

看看代码要怎么写,才能完成上图的网格效果:

.wrapper {
  display: grid;
  grid-template-columns: (col) 100px (gutter) 10px (col) 100px (gutter) 10px (col) 100px (gutter) 10px (col) 100px (gutter) 10px (col) 100px (gutter) 10px (col) 100px (gutter); 
  grid-template-rows: (row) auto (gutter) 10px (row) auto (gutter) 10px (row) auto (gutter) 10px (row) auto;
}

.a{
  grid-column: col / span gutter 2; 
  grid-row: row;
}
.b {
  grid-column: col 3 / span gutter 2; 
  grid-row: row;
}
.c { 
  grid-column: col 5 / span gutter 2; 
  grid-row: row;
}
.d { 
  grid-column: col / span gutter 3; 
  grid-row: row 2;
}
.e { 
  grid-column: col 4 / span gutter 3; 
  grid-row: row 2;
}
.f { 
  grid-column: col / span gutter 2; 
  grid-row: row 3;
}
.g {
  grid-column: col 3 / span gutter 1; 
  grid-row: row 3;
}
.h {
  grid-column: col 4 / span gutter 2; 
  grid-row: row 3;
}
.i {
  grid-column: col 6 / span gutter 1; 
  grid-row: row 3;
}
.j {
  grid-column: col  / span gutter 6; 
  grid-row: row 4;
}

效果如下:

自定义网格线名称

在线案例

##repeat关键词

在上例中,不难发现列和行都有很多重复的,比如:列网格线有六个(col) 100px (gutter) 10px,而行网格线有四个(row) auto (gutter) 10px。其实在CSS Grid Layout没有必要这么痛苦,他提供了一个关键repeat,完全可以使用repeat来让你的代码变得更简洁。

使用repeat的代码如下:

.wrapper {
  display: grid;
  grid-template-columns:repeat(6, (col) 100px (gutter) 10px); 
  grid-template-rows: repeat(4, (row) auto (gutter) 10px );
}

你将看到效果:

在线案例

是不是一模一样呀。是不是变得轻松多了。

##网格区域制作合并单元格

在上一节中,介绍了网格区域制作单元格,其实根据网格区域的定义,也可以使用网格区域实现单元格的效果。回到文章第一个示例,使用网格区域,只需要这样写,就可以轻松实现所需要的效果:

.wrapper {
  display: grid;
  display: grid;
    grid-template-columns: 100px 10px 100px 10px 100px 10px 100px;
    grid-template-rows: auto 10px auto 10px auto 10px auto 10px auto;
}
.a{
  grid-area: 1 / 1 / 2 / 6;
}
.b {
  grid-area: 1 / 7 / 10 / 8;
  background: orange;
}
.c { 
  grid-area: 3 / 1 / 4 / 2; 
}
.d { 
  grid-area: 3 / 3 / 4 / 4;
}
.e { 
  grid-area: 3 / 5 / 4 / 6;
}
.f { 
  grid-area: 5 / 1 / 6 / 4;
}
.g {
  grid-area: 5 / 5 / 6 / 6;
}
.h {
  grid-area: 7 / 1 / 8 / 2;
}
.i {
  grid-area: 7 / 3 / 8 / 6;
}
.j {
  grid-area: 9 / 1 / 8 / 6;
}

效果如下:

在线案例

##模拟合并行

从上面演示的众多示例可以得知,在CSS Grid Layout中合并行并没有像合并列来得那么简单。换句话说,要实现下图的效果,到目前为止仅使用CSS Grid Layout的网格线或者网格区域是无法实现的。

布局模板

或许大家会说,抛开浏览器的兼容性问题,如果我真要实现上图的布局风格,怎么破呢?我尝试了一下,如果需要强制实现上图效果,可以在.b容器中添加一段代码:

.b {
  grid-area: 1 / 7 / 10 / 8;
  background: orange;
  height: 100%;
  box-sizing:border-box;
}

如果就模拟出上图需要的效果。

在线案例

##总结

单元格的合并对于实现一个复杂的网格布局是不可或缺的,那么这篇文章主要向大家介绍了如何使用网格线制作网格的合并效果。实现方法有很多种,可以用网格线来划分,也可以使用关键词span来跨列,当然还可以使用repeat来减少网格线定义的重复工作。除了网格线之外,还可以使用网格区域来实现合并单元格的效果。不知道你掌握了几种方法呢?

在网格布局中,除了上篇文章《CSS Grid布局:网格单元格布局》,介绍网格单元格布局和这篇文章介绍网格合并单元格布局,都可以说是CSS Grid Layout中最简单,最基础的部分。这样说来什么才是复杂的部分呢?如果您感兴趣,敬请观注下一篇文章,将向大家介绍CSS Grid Layout中的“显式和隐式网格”、“自定义网格区域”、“媒体查询中的网格区域”等内容。如果你那有相关的使用经验,欢迎与我们与起分享。