前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Grid布局简介

Grid布局简介

作者头像
桃翁
发布2018-08-16 10:15:17
发布2018-08-16 10:15:17
7.4K20
代码可运行
举报
文章被收录于专栏:前端桃园前端桃园
运行总次数:0
代码可运行

Grid布局简介

开始之前,我们先来看一张图:

小草本

没错,这其实就是我们小时候写的小格子本本,其实它跟我们今天要讲的主题Grid布局非常类似,其实Grid布局就是它的升级加强版。

CSS网格布局(又称“网格”),是一种二维网格布局系统。

CSS在处理网页布局方面一直做的不是很好。一开始我们用的是table(表格)布局,然后用float(浮动),position(定位)和inline-block(行内块)布局,但是这些方法本质上是hack,遗漏了很多功能,例如垂直居中。后来出了flexbox(盒子布局),解决了很多布局问题,但是它仅仅是一维布局,而不是复杂的二维布局,实际上它们(flexbox与grid)能很好的配合使用。

Grid布局是第一个专门为解决布局问题而创建的CSS模块,2012年11月06日成立草案。

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

Grid === Table2.0?

既然说grid布局是网格布局,那是不是grid布局就是table布局的2.0升级版呢?其实不然。

他们是有相同之处的。比如都是把元素排列成行和列。但是表格和grid的区别在于,表格是有内容结构的,不能很自由地在里面做布局。而grid内部元素可以自由设定位置,允许重叠和设定层级的样。

浏览器兼容性

既然要使用最新的css布局,那浏览器对grid布局的兼容性这个点是逃避不了的,那我们接下来就来看看grid布局的兼容性如何呢。

在将兼容性之前,介绍一个非常实用的网站,https://caniuse.com,这个网站上面可以对我们用到的各种web相关的属性,包括html,css属性进行浏览器兼容性的查询。

  • Flex布局兼容性

可以看到,我们现在用的最多的Flex布局的浏览器兼容性已经达到了一个非常高的比例——95%,说明在如今的前端开发环境下,如果对浏览器要求不是非常苛刻,基本可以非常愉快的使用Flex布局了。

  • Grid布局兼容性

从图中可以看到,Grid布局和前面的Flex布局相比起来,虽然没有那么高的兼容比例,但是,经过了6年的沉淀与发展,也已经达到了86%,相对来说也已经比较完备了。所以,如果你们的代码基本都是在常见的最新的浏览器上进行允许,不用兼容万恶的前端克星IE,可以在平时的开发中尝试使用体验一下最新的Grid布局。

Grid和Flex对比

Grid与Flex布局的共同点是元素均存放在一个父级容器内,尺寸与位置受容器影响。最核心的区别是Flex布局使用单坐标轴的布局系统,而Grid布局中使用二维布局,使元素可以在二个维度上进行排列,如下图所示:

  • flex-layout

flex

  • grid-layout

grid

上面两张图片来自于w3c官方css规范对Grid布局的介绍中的一组对比图,我们可以看到,flex布局很明显的是一维布局,元素在容器中都是横向或者纵向进行排列,并不能跨越维度进行排列。

而grid布局相比于flex布局,很明显是二维布局,grid布局不仅可以在横向上像flex已经排列,某些子元素还可以跨越维度,同时可以在横向和纵向上进行布局。

一维 vs 二维

有这样一张图:

上面这个布局,我们其实主要是在一个方向上即横线上布局,比如在header里放3个button,此时,我们其实使用flex布局是最佳方案,我们可以使用很少的代码来实现这些布局。

又比如有这样一张图:

我们看到,其实这个布局已经不单单是一个维度了,他同时在横向和纵向上都有布局,这种情况下,其实我们使用Grid布局会更加灵活,并且会使你的标签更坚定,代码更容易维护。

你也可以结合两者一起使用,在上面的例子中最完美的做法是使用Grid来布局页面,使用Flex去对齐header里面的内容。

内容优先 vs 布局优先

再者,其实这两种布局方式的另一个核心区别是Flex是以内容为基础,而Grid是以布局为基础,听起来有些抽象,我们来用一个实际的例子来看一下。

我们有这样一段header的HTML代码:

代码语言:javascript
代码运行次数:0
运行
复制
<header>
    <div>Home</div>
    <div>Search</div>
    <div>Logout</div>
</header>

在没有使用任何布局时,他们是这样的:

当我们给外部header容器添加一个display: flex之后,他们会漂亮的在一条线上。

代码语言:javascript
代码运行次数:0
运行
复制
header {
    display: flex;
}

为了让logout button在最右边,我们可以给他指定一个margin:

代码语言:javascript
代码运行次数:0
运行
复制
header > div:nth-child(3) {
    margin-left: auto;
}

效果如下:

值得注意的是,让元素本身决定他放在哪里,我们除了display: flex之外没有添加任何东西。

这就是Flex和Grid的核心差别,当我们使用Grid来创建这个header时,这个差别会更加明显。

使用Grid来实现上面的header布局,有很多方法,我们这里用一种非常简单的去做,我们的Grid有十列,没一列都是一个单位宽度。

代码语言:javascript
代码运行次数:0
运行
复制
header {
    display: grid;
    grid-template-columns: repeat(10, 1fr);
}

添加上面的代码后,看起来其实和Flex的解决方案是一样的。

但是我们可以使用chrome的审查元素在上帝视角来看看两者有什么不同:

最关键的区别就是,这种方式必须先定义布局的列。从定义列的宽度开始,然后我们才能将元素放在可用的单元格中。这种方式强迫我们去分割我们的header有多少列。除非我们改变Grid,否则我们会被困死在这10列中,但是Flex中我们不会被这个麻烦困扰。

为了把logout放在最右边,我们会把他放在第十列:

代码语言:javascript
代码运行次数:0
运行
复制
header > div:nth-child(3) {
    grid-column: 10;
}

审查元素时,看起来是这样的:

我们不能简单的添加一个margin-left: auto;因为它引进被放在了第三个单元格中,想要移动它,我们得再找一个单元格把它放进去。

Grid和flex的区别,总结起来就是以下几点:

  • CSS Grid适用于布局整体页面。它们使页面的布局变得非常容易,甚至可以处理一些不规则和非对称的设计。
  • Flexbox非常适合对齐元素内的内容。你可以使用Flexbox来定位设计上一些较小的细节问题。
  • CSS Grid适用于二维布局(行与列)。Flexbox适用于一维布局(行或列)。
  • 同时学习它们,并配合使用。

重要术语

前面对Grid有了一个大概的了解后,我们来介绍以下Grid中比较重要的几个术语。

  • 网格容器(grid-container)

网格容器,类似于Flex的容器,我们可以通过添加display: grid将一个元素设置成一个网格容器。比如下面这段代码中的container就是一个网格容器。

代码语言:javascript
代码运行次数:0
运行
复制
<div class="conatiner">
    <div class="item item1">1</div>
    <div class="item item2">2</div>
    <div class="item item3">3</div>
</div>
  • 网格项目(grid-item)

网格项目,就是网格容器中的一个子元素。比如下面代码中的item就是一个网格项目,但要注意,sub-item不是一个网格项目。

代码语言:javascript
代码运行次数:0
运行
复制
<div class="conatiner">
    <div class="item"></div>
    <div class="item">
        <p class="sub-item"></p>
    </div>
    <div class="item"></div>
</div>
  • 网格线(grid-line)

网格线就是将网格划分开的线条。

  • 网格单元格(grid-cell)

网格单元格就是网格容器中划分出来最小的单元。

  • 网格轨道(grid-track)

网格轨道就是由若干个网格单元格组成的横向或者纵向区域,他的常见规格是1x8,或者8x1这种格式。

  • 网格区域(grid-area)

网格区域也是由若干个网格单元格组成的区域,但是不用与网格轨道,他的规格不局限与单个维度。

基本属性

前面我们对grid布局的一些重要术语进行了介绍,接下来我们来一一介绍以下grid布局相关的基本属性。

容器属性

容器属性,顾名思义,就是添加可以在网格容器中添加是属性,是对网格整体进行控制的一系列属性。

  • display
  • grid-template-columns
  • grid-template-rows

这三个属性是用来定义网格布局最基本的三个属性,我们通过添加display: grid来设置一个网格容器,通过设置grid-template-columnsgrid-template-rows来给网格容器定义具体的行和列。

代码语言:javascript
代码运行次数:0
运行
复制
.container {
    display: grid;
    grid-template-columns: 40px 50px auto 50px 40px;
    grid-template-rows: 25% 100px auto;
}
  • fr单位

fr单位是grid布局中的一个新单位,它代表的是网格容器中可用空间的一份。下面我举三个小例子来介绍以下这个单位,注意,我们这里只关注列的宽度。

1fr 1fr 1fr表示三个轨道三等分。

2fr 1fr 1fr表示三个轨道,空间四等分,两份给第一个轨道,剩下三个轨道各占一份。

400px 2fr 1fr表示三个轨道,第一个轨道400px,抽走400px后剩下空间三等分,两份给第二个轨道,一份给第三个轨道。

  • repeat()和minmax()

repeat和minmax是grid布局中的两个常用函数,可用减少我们代码的重复编写。

repeat(time, content),表示的是标记重复部分或整个轨道列表,第一个参数time表示重复的次数,第二个参数content表示重新的内容。具体见下面的三个小例子。

代码语言:javascript
代码运行次数:0
运行
复制
repeat(3, 1fr) = 1fr 1fr 1fr

20px repeat(3, 1fr) 20px = 20px 1fr 1fr 1fr 20px

repeat(3, 1fr 2fr) = 1fr 2fr 1fr 2fr 1fr 2fr

minmax(min, max),可用给网格定义一个尺寸的范围,第一个参数min表示网格尺寸的最小值,第二个参数表示网格尺寸的最大值。具体见下面的两个小例子。

代码语言:javascript
代码运行次数:0
运行
复制
minmax(100px, 200px):表示网格最小是100px,最大是200px

minmax(100px, auto):表示网格最小是100px,最大为auto,auto意思是行高将根据内容的大小自动变换
  • grid-template-areas

grid-template-areas表示的网格容器中的一个区域。通过获取网格项中的grid-area属性值(名称),来定义网格模版。重复网格区(grid-area)名称将跨越网格单元格,’.’代表空网格单元。

下面这个例子我们通过给a,b,c,d四个div添加grid-area属性定义了名字,如果通过grid-template-areas这个属性来快速的定义网格的布局。

代码语言:javascript
代码运行次数:0
运行
复制
.item-a {
    grid-area: header;
}
.item-b {
    grid-area: main;
}
.item-c {
    grid-area: sidebar;
}
.item-d {
    grid-area: footer;
}
.container {
    display: grid;
    grid-template-columns: 50px 50px 50px 50px;
    grid-template-rows: auto;
    grid-template-areas: 
        "header header header header"
        "main main . sidebar"
        "footer footer footer footer"
}
  • grid-column-gap
  • grid-row-gap
  • grid-gap

这三个属性,主要是用来定义网格项之间的间隙,类似于margin。grid-column-gap和grid-row-gap分别定义网格之间的列间距和行间距,而grid-gap则是简写,第一个值为行间距,第二个值为列间距。

代码语言:javascript
代码运行次数:0
运行
复制
.container {
    grid-template-columns: 100px 50px 100px;
    grid-template-rows: 80px auto 80px;
    grid-column-gap: 10px;
    grid-row-gap: 15px;
}

或者

代码语言:javascript
代码运行次数:0
运行
复制
.container {
    ...
    grid-gap: 15px 10px;
}
  • justify-items
  • align-items
  • justify-content
  • align-content

这四个属性主要是用来控制网格项的对齐方式,具体用法和效果与Flex类似,这里就不详细展开,看图说话吧。

  • grid-auto-columns
  • grid-auto-rows

这两个属性是自动生成隐式网格轨道(列和行),当你定位网格项超出网格容器范围时,将自动创建隐式网格轨道。

我们看下面这个例子。

代码语言:javascript
代码运行次数:0
运行
复制
.container {
    display: grid;
    grid-template-columns: 60px 60px;
    grid-template-rows: 90px 90px;
}

这是2x2的网格,但是我们来用grid-column 和 grid-row给网格项定位如下:

代码语言:javascript
代码运行次数:0
运行
复制
.item-a {
    grid-column: 1 / 2;
    grid-row: 2 / 3;
}
.item-b {
    grid-column: 5 / 6;
    grid-row: 2 / 3;
}

我们可以看出,网格项item-b定位在第五根列网格线(column line 5 )和第六根列网格线(column line 6 )之间。但是我们网格容器根本不存在这两条网格线,所以就用两个0宽度来填充。在这里我们可以用网格自动行(grid-auto-rows)和网格自动列(grid-auto-columns)来定义这些隐式轨道宽度。

  • grid-auto-flow

在没有设置网格项的位置时,这个属性控制网格项怎样排列。

他的属性值有:

代码语言:javascript
代码运行次数:0
运行
复制
row: 按照行依次从左到右排列。

column: 按照列依次从上倒下排列。

dense: 按先后顺序排列。

我们看下面的这个例子:

代码语言:javascript
代码运行次数:0
运行
复制
<div class="container">
    <div class="item-a">item-a</div>
    <div class="item-b">item-b</div>
    <div class="item-c">item-c</div>
    <div class="item-d">item-d</div>
    <div class="item-e">item-e</div>
</div>

我们定义一个5行2列的网格,同时定义grid-auto-flow:flow。

代码语言:javascript
代码运行次数:0
运行
复制
.container {
    display: grid;
  grid-template-columns: 60px 60px 60px 60px 60px;
  grid-template-rows: 30px 30px;
  grid-auto-flow: row;
}

然后对item-a和item-e进行布局。

代码语言:javascript
代码运行次数:0
运行
复制
.item-a{
    grid-column: 1;
    grid-row: 1 / 3;
}
.item-e{
    grid-column: 5;
    grid-row: 1 / 3;
}

由于我们设置了grid-auto-flow:row,item-b、item-c和item-d在行上是从左到右排列,如下:

如果我们设置 grid-auto-flow: column;结果如下:

网格项目属性

网格项目属性,是添加在具体的网格单元上来控制网格单元的属性。

  • grid-column-start
  • grid-column-end
  • grid-row-start
  • grid-row-end
  • grid-column
  • grid-row

这6个属性是通过网格线来定义网格项的位置。grid-column-start、grid-row-start定义网格项的开始位置,grid-column-end、grid-row-end定义网格项的结束位置。

这四个属性的值可以是:

代码语言:javascript
代码运行次数:0
运行
复制
line: 指定带编号或者名字的网格线。

span: 跨越轨道的数量。

span: 跨越轨道直到对应名字的网格线。

auto: 自动展示位置,默认跨度为1。

grid-column,grid-row是grid-column-start、grid-column-end 和 grid-row-start、grid-row-end 的简写。

  • gid-area

定义网格项名字,以便创建模块(容器属性grid-template-areas来定义模块)。可以是数字或网格线名字。看如下两个例子。

定义网格项名字:

代码语言:javascript
代码运行次数:0
运行
复制
.item-d {
    grid-area: header;
}

通过网格线定义网线项:

代码语言:javascript
代码运行次数:0
运行
复制
.item-d {
    grid-area: 1 / col-start / last-line / 6;
}
  • justify-self
  • align-self

这两属性用来定义单个网格项垂直于列网格线的对齐方式。

实际布局应用

说了这么多,下面我们就拿几个常见的布局来应用一下刚刚学到的grid布局。

  • 左右固定,中间自适应
代码语言:javascript
代码运行次数:0
运行
复制
<div class="container">
    <div class="left">left</div>
    <div class="middle">middle</div>
    <div class="right">right</div>
</div>
代码语言:javascript
代码运行次数:0
运行
复制
.container {
    display: grid;
    grid-template-columns: 100px 1fr 100px;
    height: 200px;
}
.container div {
    text-align: center;
}
.left {
    background: greenyellow;
}
.middle {
    background: lightblue;
}
.right {
    background: greenyellow;
}
  • 九宫格
代码语言:javascript
代码运行次数:0
运行
复制
<div class="container">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
</div>
代码语言:javascript
代码运行次数:0
运行
复制
.container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(3, 1fr);
    height: 400px;
    width: 400px;
    grid-gap: 8px;
}
.item {
    background: lightskyblue;
}
  • 圣杯布局和双飞翼布局
代码语言:javascript
代码运行次数:0
运行
复制
<div class="container">
    <div class="header">header</div>
    <div class="left">left</div>
    <div class="body">body</div>
    <div class="right">right</div>
    <div class="footer">footer</div>
</div>
代码语言:javascript
代码运行次数:0
运行
复制
.container {
    display: grid;
    grid-template-columns: 100px 1fr 100px;
    grid-template-rows: 50px 300px 50px;
}
.header {
    grid-area: 1 / 1 / 2 / 4;
    background: lightsalmon;
}
.left {
    background: lightseagreen;
}
.body {
    background: lightslategray;
}
.right {
    background: lightyellow;
}
.footer {
    grid-area: 3 / 1 / 4 / 4;
    background: yellowgreen;
}

结束语

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

大概可以设想,网格布局被广泛支持之后会出现很多网格布局内嵌flex的布局情形。

参考链接

  • https://www.w3.org/TR/css-grid-1/
  • https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Grid_Layout
  • https://caniuse.com/#feat=css-grid
  • http://griddy.io/
  • https://alialaa.github.io/css-grid-cheat-sheet/
  • http://www.w3cplus.com/css3/playing-with-css-grid-layout.html

本文来源于 陈钰博 的博客, http://www.chenyubo.me/2018/08/08/grid-layout-intro/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-08-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端桃园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Grid布局简介
  • Grid === Table2.0?
  • 浏览器兼容性
  • Grid和Flex对比
    • 一维 vs 二维
    • 内容优先 vs 布局优先
  • 重要术语
  • 基本属性
    • 容器属性
    • 网格项目属性
  • 实际布局应用
  • 结束语
  • 参考链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档