ext grid 重新布局_CSS Grid 布局从基础到应用

32f015edde41b8c22827bf6946a4b35c.png

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

a8f649c3b739d16df806d8c671f3dd71.png
小草本

没错,这其实就是我们小时候写的小格子本本,其实它跟我们今天要讲的主题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布局兼容性
3d545fa4ee90dbc106502c98b8cb9f8a.png

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

  • Grid布局兼容性
ce0b26f9c8c2e9bbd81c89e8c646d648.png

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

Grid和Flex对比

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

  • flex-layout
529dd590e638e57dc35d714fe802371b.png
flex
  • grid-layout
bcf0ba2ffbc650041b64a61e5e246e20.png
grid

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

一维 vs 二维

有这样一张图:

bdb0edceca624e9cddc6e67e4c78d929.png

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

又比如有这样一张图:

0cfc2cd5ecedd1ffb0a926d2f565836b.png

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

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

内容优先 vs 布局优先

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

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

<header>
<div>Homediv>
<div>Searchdiv>
<div>Logoutdiv>
header>

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

eade6d3393b8f673a4593495fb746407.png

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

header {
display: flex;
}
be76944c126c33a3d609ba8ff031735e.png

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

header > div:nth-child(3) {
margin-left: auto;
}

效果如下:

9d95515f91c614eb593a97387ed47a1e.png

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

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

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

header {
display: grid;
grid-template-columns: repeat(10, 1fr);
}

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

be76944c126c33a3d609ba8ff031735e.png

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

883d4d41e3343b854f789172935574bb.png

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

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

header > div:nth-child(3) {
grid-column: 10;
}

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

0efe83bb580e41c5362c78e4acd5d692.png

我们不能简单的添加一个margin-left: auto;因为它引进被放在了第三个单元格中,想要移动它,我们得再找一个单元格把它放进去。Grid和flex的区别,总结起来就是以下几点:

  • CSS Grid适用于布局整体页面。它们使页面的布局变得非常容易,甚至可以处理一些不规则和非对称的设计。

  • Flexbox非常适合对齐元素内的内容。你可以使用Flexbox来定位设计上一些较小的细节问题。

  • CSS Grid适用于二维布局(行与列)。Flexbox适用于一维布局(行或列)。

  • 同时学习它们,并配合使用。

重要术语

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

  • 网格容器(grid-container)

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

<div class="conatiner">
<div class="item item1">1div>
<div class="item item2">2div>
<div class="item item3">3div>
div>
  • 网格项目(grid-item)

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

<div class="conatiner">
<div class="item">div>
<div class="item">
<p class="sub-item">p>
div>
<div class="item">div>
div>
  • 网格线(grid-line)

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

dfd07b37c111ab2ad8b120129589f6e2.png
  • 网格单元格(grid-cell)

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

bf1f8bd3c68add2676784191204cb56e.png
  • 网格轨道(grid-track)

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

7cbd9d31e0e67f7978d70bf50c3750af.png
  • 网格区域(grid-area)

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

e9f9cf933cf2cac8ae3c55485adfac94.png

基本属性

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

容器属性

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

  • display

  • grid-template-columns

  • grid-template-rows

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

.container {
display: grid;
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
}
6a08ee804b5464a99c362f6545646b87.png
  • fr单位

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

7199ae987b57d33817e9bf90bc71518b.png

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

c68a5e239a3bef10df9073a860af68b3.png

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

a83575c4f8368b90d2b444e948b3c55a.png
  • repeat()和minmax()

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

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

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表示网格尺寸的最小值,第二个参数表示网格尺寸的最大值。具体见下面的两个小例子。

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这个属性来快速的定义网格的布局。

.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"
}
b9be71ae0f97f0693997a65c71bb8945.png
  • grid-column-gap

  • grid-row-gap

  • grid-gap

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

.container {
grid-template-columns: 100px 50px 100px;
grid-template-rows: 80px auto 80px;
grid-column-gap: 10px;
grid-row-gap: 15px;
}

或者

.container {
...
grid-gap: 15px 10px;
}
75e43fe7d80a1a761bd9bcc02c8a15bf.png
  • justify-items

  • align-items

  • justify-content

  • align-content

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

62a63a984112f5d67494c9b212febb36.png
8d6cc1e246b69b7fa664801ca5628467.png
692b34c28a2d84463b9572ebac00725f.png
832f66a2333d605c718a7603aaef7a0a.png
  • grid-auto-columns

  • grid-auto-rows

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

.container {
display: grid;
grid-template-columns: 60px 60px;
grid-template-rows: 90px 90px;
}
70846c155a79aa85cda2f1f2260b3bdb.png

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

.item-a {
grid-column: 1 / 2;
grid-row: 2 / 3;
}
.item-b {
grid-column: 5 / 6;
grid-row: 2 / 3;
}
d81286d0fe1cc1f7f04caab383f5108b.png

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

36224e2a329190be42c2e71e6a244822.png
  • grid-auto-flow

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

row: 按照行依次从左到右排列。

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

dense: 按先后顺序排列。

我们看下面的这个例子:

<div class="container">
<div class="item-a">item-adiv>
<div class="item-b">item-bdiv>
<div class="item-c">item-cdiv>
<div class="item-d">item-ddiv>
<div class="item-e">item-ediv>
div>

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

.container {
display: grid;
grid-template-columns: 60px 60px 60px 60px 60px;
grid-template-rows: 30px 30px;
grid-auto-flow: row;
}

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

.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在行上是从左到右排列,如下:

d4caee479caf0735e122460f756c45b1.png

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

d7aac31c0c6ae2b32eb11ade13c58d86.png

网格项目属性

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

  • 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定义网格项的结束位置。这四个属性的值可以是:

line: 指定带编号或者名字的网格线。

span: 跨越轨道的数量。

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

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

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

6fdc62a72b29dd8623da6e1003f35264.png
  • gid-area

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

.item-d {
grid-area: header;
}

通过网格线定义网线项:

.item-d {
grid-area: 1 / col-start / last-line / 6;
}
eee45ed622e3bf292c170a722f5fcdd3.png
  • justify-self

  • align-self

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

08255b6e4f6cd057965e977eba759bc1.png
4889a2c22e0d8a1b5e417e0fce9c5f78.png

实际布局应用

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

  • 左右固定,中间自适应

HTML 如下:

<div class="container">
<div class="left">leftdiv>
<div class="middle">middlediv>
<div class="right">rightdiv>
div>

CSS 如下:

.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;
}
9f8b4732db2985fa824cd7498430c438.png
  • 九宫格

HTML 如下:

<div class="container">
<div class="item">1div>
<div class="item">2div>
<div class="item">3div>
<div class="item">4div>
<div class="item">5div>
<div class="item">6div>
<div class="item">7div>
<div class="item">8div>
<div class="item">9div>
div>

CSS 如下:

.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;
}
69ea2fe39d40440745ed0990019f1abc.png
  • 圣杯布局和双飞翼布局

HTML 如下:

<div class="container">
<div class="header">headerdiv>
<div class="left">leftdiv>
<div class="body">bodydiv>
<div class="right">rightdiv>
<div class="footer">footerdiv>
div>

CSS 如下:

.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;
}

e9422e0993047a529cb134690b18869a.png

结束语

但是也不要放弃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

● 1.5万字概括ES6全部特性

● 妙用CSS变量,让你的CSS变得更心动

● 拒绝删库跑路!上手 Docker 容器数据管理

·END·

图雀社区

汇聚精彩的免费实战教程

12b532abf49ba1412c00bcbd14684190.png

关注公众号回复 z 拉学习交流群

喜欢本文,点个“在看”告诉我

95928d39efc685a8df3b2f1ad12b61d6.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值