网站的布局是一个网站设计的根本,CSS的Grid布局已经成为了未来网站布局的基本方式。
今天这篇文章我们通过图文,一起看看如何自己实现Grid布局方式。
CSS
首先我们看看最基本的Grid布局是什么样的,HTML页面的代码如下所示。
HTML代码
然后设置其CSS属性,这里主要展示容器的CSS属性,给子元素添加的color属性就不在这里展示了。
CSS属性
在页面上看到的效果如下,目前因为没有对子div元素做任何设置,会自动将子div沿垂直方向排列。
页面效果
为了让外层的div(wrapper)为一个网格容器,需要设置其行数和列数,就像一个表格一样。
此时就需要用到grid-template-columns和grid-template-rows两个属性值。
grid-template-columns
用于设置网格容器的列属性,其实就相当于列的宽度。当我们需要几列展示时,就设置几个值,这个属性可以接收具体数值比如100px,也可以接收百分比值,表示占据容器的宽度。
需要注意的是:当给容器设定了宽度时,grid-template-columns设定的百分比值是以容器的宽度值为基础计算的。如果未设置宽度时,会一直向上追溯到设置了宽度的父容器,直到body元素。
比如我们设置了以下的CSS属性。
CSS属性
可以看出三列宽度加起来的百分比值为120%,而且wrapper容器并未设置宽度,会一直向上追溯到body元素,这样三列的总宽度已经超过了body的宽度,因此会出现滚动条。
页面效果
grid-template-rows
用于设置网格容器的行属性,其实就相当于行的高度,其特性与grid-template-columns属性类似。
下面简单修改grid-template-columns和grid-template-rows两个属性的值。
CSS值
得到的效果图如下所示。
效果图
接下来我们看看别的情况,通过CSS属性设置3*3的网格。
CSS属性
在页面上的呈现方式如下所示。
页面呈现
从页面上看我们看不出有什么问题,但是打开控制台后可以发现,这个网格已经占据了3*3的空间。它后面的元素只能排列在所有的网格后面。
页面实际情况
当我们需要得到特殊的排列方式,比如占满整行,占满整列,二三行合并等等。
这就需要用到grid-column和grid-row属性,表示行网线和列网线的序号。通过设置start和end值,来进行网格的合并。
网线序号
我们重新给wrapper容器内部的div添加class类。
HTML代码
然后添加以下的CSS代码,给不同的网格特定的行号和列号。
CSS代码
最终得到的效果图如下所示。
页面效果图
今天这篇文章介绍了CSS中Grid布局的基础知识,应该可以很快掌握,其他的复杂点的网格布局大家也可以自己去尝试。
先看一个例子:
网格布局
简单来说网格布局就是display: grid,将元素定义为一个网格容器,内部的子元素则变成网格元素。
display: grid; // 定义网格容器
grid-template-columns: 1fr 1fr 1fr; // 定义等宽的3列
grid-template-rows: 1fr 1fr; // 定义等高的两行
grid-gap: .5em; // 给每个网格的单元格子间加上间隔
fr是一种新的单位,代表每一行或者列的分数单位(fraction unit)。
网格线(grid line):网格线构成了网格的框架。一条网格线可以水平或垂直,也可以位于一行或一列的任意一侧。如果指定了grid-gap,它就位于网格线上。
网格轨道(grid track):一个网格轨道是两条相邻网格线之间的空间。网格有水平轨道和垂直轨道。
网格单元(grid cell):网格上的单个空间,水平和垂直的网格轨道交叉重叠的部分。
网格区域(grid area):网格的矩形区域,由一个到多个网格单元组成。
网格轨道定义好后,要将每个网格元素放到特定的位置上。浏览器给网格里的每个网格线都赋予了编号。
网格线编号
可以在grid-column和grid-row属性中间用网格线的编号指定网格元素的位置。如果想要一个网格元素在垂直方向上跨越1号网格线到3号网格线,就需要给元素设置grid-column:1 / 3。
需要注意的是,网格的高度是随着内容的高度自动计算的,比如上面a、c两个网格分别占据了两行,一共有5行,最终每行的高度是a、c内容高度的最大值除以所占的行数(2),如果我们设置a只占一行,那么每一行的高度就会放大接近2倍:
有时候记录所有网格线的编号实在太麻烦了,为了能简单点,可以给网格线命名:
grid-template-column: [start] 2fr [center] 1fr [end];
这条声明定义了两列的网格,三条垂直的网格线分别叫做start、center、end。之后在grid-colum中可以这样写:
grid-column: start / center;
可以将网格区域命名,然后将元素放到指定的网格中:
命名网格区域
需要注意的是,网格的命名一定要准确,并且不能少,不然网格就会错位!
SS 网格布局(Grid Layout) 是CSS中最强大的布局系统。 这是一个二维系统,这意味着它可以同时处理列和行,不像 flexbox 那样主要是一维系统。 你可以通过将CSS规则应用于父元素(成为网格容器)和该元素的子元素(网格元素),来使用网格布局。
引言
CSS网格布局(又名“网格”)是一个二维的基于网格的布局系统,其目的只在于完全改变我们设计基于网格的用户界面的方式。 CSS一直用来布局网页,但一直都不完美。 一开始我们使用table 做布局,然后转向浮动、定位以及inline-block,但所有这些方法本质上都是 Hack 的方式,并且遗漏了很多重要的功能(例如垂直居中)。 Flexbox的出现在一定程度上解决了这个问题,但是它的目的是为了更简单的一维布局,而不是复杂的二维布局(Flexbox和Grid实际上一起工作得很好)。 只要我们一直在制作网站,我们就一直在为解决布局问题不断探索, 而Grid是第一个专门为解决布局问题而生的CSS模块。
有两个东西,启发我写这篇指南。 第一个是雷切尔·安德鲁(Rachel Andrew)的书为CSS Grid布局准备。 这本书对网格布局做了彻底、清晰的介绍,也是是整篇文章的基础,我强烈建议你购买并阅读他的书。 我的另一个重要灵感是Chris Coyier的Flexbox完全指南,当需要查阅 flexbox 的一切资料时我就会找这篇文章。 这篇文章帮助了很多人学习 Flex 布局,也是 Google 上搜索“flexbox”关键字排名第一的文章。你会发现他的文章和我的很多相似之处,有最好的范例在那放着为什么咱不偷师学着写呢?
本指南的目的是介绍网格概念,因为它们存在于最新版本的规范中。 因此我不会覆盖过时的IE语法,而且随着规范的成熟,我会尽最大努力保存更新本指南。
基础知识以及浏览器支持情况
一开始你需要使用display:grid把容器元素定义为一个网格,使用grid-template-columns和grid-template-rows设置列和行大小,然后使用grid-column 和 grid-row把它的子元素放入网格。 与flexbox类似,网格子元素的原始顺序不重要。 你的可以在 CSS 里以任意顺序放置它们,这使得使用媒体查询重新排列网格变得非常容易。 想象一下,我们需要定义整个页面的布局,然后为了适应不同的屏幕宽度完全重新排列,我们只需要几行CSS就能实现这个需求。 网格是有史以来最强大的CSS模块之一。
截至2017年3月,许多浏览器都提供了原生的、不加前缀的对CSS Grid的支持,比如 Chrome(包括Android),Firefox,Safari(包括iOS)和Opera。 另一方面,Internet Explorer 10和11支持它,但需要使用过时的语法。 Edge浏览器已经宣布将支持标准的Grid语法,但暂未支持。
浏览器支持的详细数据可在Caniuse查看。其中里面的数字表示该版本以上的浏览器支持Grid。
桌面浏览器
移动端 / 平板
除了微软之外,浏览器制造商在 Grid 规范完全落地以前似乎并没有放手让 Gird 野生也长的打算。 这是一件好事,这意味着我们不需要再去学习各种浏览器兼容版本的旧语法。
在生产环境中使用Grid只是时间问题,但现在是我们该学习的时候了。
重要术语
在深入了解网格的概念之前,理解术语是很重要的。 由于这里所涉及的术语在概念上都是相似的,如果不先记住它们在网格规范中定义的含义,则很容易将它们彼此混淆。 但是不用太担心,这些术语并不多。
Grid Container
设置了 display: gird 的元素。 这是所有 grid item 的直接父项。 在下面的例子中,.container 就是是 grid container。
<div class="container"> <div class="item item-1"></div> <div class="item item-2"></div> <div class="item item-3"></div> </div>
Grid Item
Grid 容器的孩子(直接子元素)。下面的 .item 元素就是 grid item,但 .sub-item不是。
<div class="container"> <div class="item"></div> <div class="item"> <p class="sub-item"></p> </div> <div class="item"></div> </div>
Grid Line
这个分界线组成网格结构。 它们既可以是垂直的(“column grid lines”),也可以是水平的(“row grid lines”),并位于行或列的任一侧。 下面例中的黄线就是一个列网格线。
Grid Track
两个相邻网格线之间的空间。 你可以把它们想象成网格的列或行。 下面是第二行和第三行网格线之间的网格轨道。
Grid Cell
两个相邻的行和两个相邻的列网格线之间的空间。它是网格的一个“单元”。 下面是行网格线1和2之间以及列网格线2和3的网格单元。
Grid Area
四个网格线包围的总空间。 网格区域可以由任意数量的网格单元组成。 下面是行网格线1和3以及列网格线1和3之间的网格区域。
Grid 属性列表
Grid Container 的全部属性
Grid Items 的全部属性
父容器(Grid Container)的属性
display
将元素定义为 grid contaienr,并为其内容建立新的网格格式化上下文(grid formatting context)。
值:
.container { display: grid | inline-grid | subgrid; }
注意:column, float, clear, 以及 vertical-align 对一个 grid container 没有影响
grid-template-columns / grid-template-rows
使用以空格分隔的多个值来定义网格的列和行。这些值表示轨道大小(track size),它们之间的空格代表表格线(grid line)。
.container { grid-template-columns: <track-size> ... | <line-name> <track-size> ...; grid-template-rows: <track-size> ... | <line-name> <track-size> ...; }
例子:
(如果未显示的给网格线命名),轨道值之间仅仅有空格时,网格线会被自动分配数字名称:
.container { grid-template-columns: 40px 50px auto 50px 40px; grid-template-rows: 25% 100px auto; }
但你可以给网格线指定确切的命名。 注意中括号里的网格线命名语法:
.container { 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条网格线有两个名字:row1-end 和 row2-start:
.container { grid-template-rows: [row1-start] 25% [row1-end row2-start] 25% [row2-end]; }
如果你的定义中包含重复的部分,则可以使用repeat() 符号来简化写法:
.container { grid-template-columns: repeat(3, 20px [col-start]) 5%; }
上面的写法和下面等价:
.container { grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start] 5%; }
“fr”单位允许您将轨道大小设置为网格容器自由空间的一部分。 例如,下面的代码会将每个 grid item 为 grid container 宽度的三分之一:
.container { grid-template-columns: 1fr 1fr 1fr; }
自由空间是在排除所有不可伸缩的 grid item 之后计算得到的。 在下面的示例中,fr单位可用的自由空间总量不包括50px:
.container { grid-template-columns: 1fr 50px 1fr 1fr; }
grid-template-areas
通过引用 grid-area属性指定的网格区域的名称来定义网格模板。 重复网格区域的名称导致内容扩展到这些单元格。 点号表示一个空单元格。 语法本身提供了网格结构的可视化。
值:
举例:
.item-a { grid-area: header; } .item-b { grid-area: main; } .item-c { grid-area: sidebar; } .item-d { grid-area: footer; } .container { 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"; }
这将创建一个四列宽三行高的网格。 整个第一行将由 header 区域组成。 中间一行将由两个 main 区域、一个空单元格和一个 sidebar 区域组成。 最后一行是footer区域组成。
你的声明中的每一行都需要有相同数量的单元格。
您可以使用任意数量的相邻的.来声明单个空单元格。 只要这些点号之间没有空格,他们就代表了一个单一的单元格。
需要注意的是你不是在用这个语法命名网格线,而是在命名区域。 当你使用这种语法时,区域两端的网格线实际上是自动命名的。 比如,如果网格区域的名称是foo,那么区域的起始的行网格线和列网格线名称是 foo-start,并且区域终点的行网格线和列网格线名称是 foo-end。 这意味着某些网格线可能有多个名称,比如上面的例子中最左边的一条网格线有三个名字:header-start,main-start 和 footer-start。
grid-template
在单个声明中定义 grid-template-rows、grid-template-columns、grid-template-areas 的简写。
值:
.container { grid-template: none | subgrid | <grid-template-rows> / <grid-template-columns>; }
它也可以使用一个更复杂但相当方便的语法来指定这三个值。 一个例子:
.container { grid-template: [row1-start] "header header header" 25px [row1-end] [row2-start] "footer footer footer" 25px [row2-end] / auto 50px auto; }
以上等价于:
.container { grid-template-rows: [row1-start] 25px [row1-end row2-start] 25px [row2-end]; grid-template-columns: auto 50px auto; grid-template-areas: "header header header" "footer footer footer"; }
由于 grid-template 不会重置隐式网格属性(grid-auto-columns,grid-auto-rows和grid-auto-flow),而这可能是大多数情况下你想要做的。因此建议使用grid属性来代替grid-template。
grid-column-gap / grid-row-gap
指定网格线的大小,你可以把它想象为设置列/行之间的间距的宽度。
值:
.container { grid-column-gap: <line-size>; grid-row-gap: <line-size>; }
举例:
.container { grid-template-columns: 100px 50px 100px; grid-template-rows: 80px auto 80px; grid-column-gap: 10px; grid-row-gap: 15px; }
只能在列/行之间创建缝隙,而不是在外部边缘创建。
grid-gap
grid-row-gap 和 grid-column-gap 的缩写
.container { grid-gap: <grid-row-gap> <grid-column-gap>; }
Example:
.container { grid-template-columns: 100px 50px 100px; grid-template-rows: 80px auto 80px; grid-gap: 10px 15px; }
如果没有指定 grid-row-gap,则会被设置为与 grid-column-gap 相同的值。
justify-items
沿着行轴对齐网格内的内容(与之对应的是 align-items, 即沿着列轴对齐),该值适用于容器内的所有的 grid items。
值:
.container { justify-items: start | end | center | stretch; }
举例:
.container { justify-items: start; }
.container{ justify-items: end; }
.container { justify-items: center; }
.container { justify-items: stretch; }
也可以通过给单个 grid item 设置justify-self属性来达到上述效果。
align-items
沿着列轴对齐grid item 里的内容(与之对应的是使用 justify-items 设置沿着行轴对齐),该值适用于容器内的所有 grid items。
值:
.container { align-items: start | end | center | stretch; }
举例:
.container { align-items: start; }
.container { align-items: end; }
.container { align-items: center; }
.container { align-items: stretch; }
也可以通过给单个 grid item 设置align-self属性来达到上述效果。
justify-content
有时,网格的总大小可能小于其网格容器的大小。如果你的所有 grid items 都使用像px这样的非弹性单位来设置大小,则可能发生这种情况。此时,你可以设置网格容器内的网格的对齐方式。 此属性沿着行轴对齐网格(与之对应的是 align-content, 沿着列轴对齐)。
值:
.container { justify-content: start | end | center | stretch | space-around | space-between | space-evenly; }
举例:
.container { justify-content: start; }
.container { justify-content: end; }
.container { justify-content: center; }
.container { justify-content: stretch; }
.container { justify-content: space-around; }
.container { justify-content: space-between; }
.container { justify-content: space-evenly; }
align-content
有时,网格的总大小可能小于其网格容器的大小。如果你的所有 grid items 都使用像px这样的非弹性单位来设置大小,则可能发生这种情况。此时,你可以设置网格容器内的网格的对齐方式。 此属性沿着列轴对齐网格(与之对应的是 justify-content, 即沿着行轴对齐)。
值:
.container { align-content: start | end | center | stretch | space-around | space-between | space-evenly; }
举例:
.container { align-content: start; }
.container { align-content: end; }
.container { align-content: center; }
.container { align-content: stretch; }
.container { align-content: space-around; }
.container { align-content: space-between; }
.container { align-content: space-evenly; }
grid-auto-columns / grid-auto-rows
指定自动生成的网格轨道(又名隐式网格轨道)的大小。 隐式网格轨道在你显式的定位超出指定网格范围的行或列(使用 grid-template-rows/grid-template-columns)时被创建。
值:
.container { grid-auto-columns: <track-size> ...; grid-auto-rows: <track-size> ...; }
为了说明如何创建隐式网格轨道,思考如下代码:
.container { grid-template-columns: 60px 60px; grid-template-rows: 90px 90px }
这里创建了一个 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; }
这里我们指定 .item-b开始于列网格线 5 并结束于在列网格线 6,但我们并未定义列网格线 5 或 6。因为我们引用不存在的网格线,宽度为0的隐式轨道的就会被创建用与填补间隙。我们可以使用 grid-auto-columns 和 grid-auto-rows属性来指定这些隐式轨道的宽度:
.container { grid-auto-columns: 60px; }
grid-auto-flow
如果你存在没有显示指明放置在网格上的 grid item,则自动放置算法会自动放置这些项目。 而该属性则用于控制自动布局算法的工作方式。
值:
.container { grid-auto-flow: row | column | row dense | column dense }
需要注意的是,dense 可能导致您的 grid item 乱序。
举例, 考虑如下 HTML:
<section 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> </section>
你定义一个有5列和2行的网格,并将 grid-auto-flow 设置为 row(这也是默认值):
.container { display: grid; grid-template-columns: 60px 60px 60px 60px 60px; grid-template-rows: 30px 30px; grid-auto-flow: row; }
当把 grid item 放在网格上时,你只把其中两个设置了固定的位置:
.item-a { grid-column: 1; grid-row: 1 / 3; } .item-e { grid-column: 5; grid-row: 1 / 3; }
因为我们将 grid-auto-flow 设置为row,所以我们的grid就像这样。 注意观察我们没有做设置的三个项目(item-b,item-c和item-d)是如何在剩余的行水平摆放位置的:
如果我们将 grid-auto-flow 设置为 column,则 item-b,item-c 和 item-d 以列的顺序上下摆放:
.container { display: grid; grid-template-columns: 60px 60px 60px 60px 60px; grid-template-rows: 30px 30px; grid-auto-flow: column; }
grid
在单个属性中设置所有以下属性的简写:grid-template-rows,grid-template-columns,grid-template-areas,grid-auto-rows,grid-auto-columns和grid-auto-flow。 它同时也将 sets grid-column-gap 和 grid-row-gap 设置为它们的初始值,即使它们不能被此属性显示设置。
值:
.container { grid: none | <grid-template-rows> / <grid-template-columns> | <grid-auto-flow> [<grid-auto-rows> [/ <grid-auto-columns>]]; }
举例:
以下代码写法等价
.container { grid: 200px auto / 1fr auto 1fr; } .container { grid-template-rows: 200px auto; grid-template-columns: 1fr auto 1fr; grid-template-areas: none; }
以下代码写法等价
.container { grid: column 1fr / auto; } .container { grid-auto-flow: column; grid-auto-rows: 1fr; grid-auto-columns: auto; }
它也可用使用一个更复杂但相当方便的语法来一次设置所有内容。 你可以指定 grid-template-areas、grid-template-rows 以及 grid-template-columns,并将所有其他子属性设置为其初始值。 你现在所做的是在其网格区域内,指定网格线名称和内联轨道大小。 可以看下面的例子:
.container { grid: [row1-start] "header header header" 1fr [row1-end] [row2-start] "footer footer footer" 25px [row2-end] / auto 50px auto; }
上述代码等价于
.container { grid-template-areas: "header header header" "footer footer footer"; grid-template-rows: [row1-start] 1fr [row1-end row2-start] 25px [row2-end]; grid-template-columns: auto 50px auto; }
孩子(Grid Items)的属性
grid-column-start / grid-column-end / grid-row-start /grid-row-end
使用特定的网格线确定 grid item 在网格内的位置。grid-column-start/grid-row-start 属性表示grid item的网格线的起始位置,grid-column-end/grid-row-end属性表示网格项的网格线的终止位置。
值:
.item { grid-column-start: <number> | <name> | span <number> | span <name> | auto grid-column-end: <number> | <name> | span <number> | span <name> | auto grid-row-start: <number> | <name> | span <number> | span <name> | auto grid-row-end: <number> | <name> | span <number> | span <name> | auto }
举例:
.item-a { grid-column-start: 2; grid-column-end: five; grid-row-start: row1-start grid-row-end: 3 }
.item-b { grid-column-start: 1; grid-column-end: span col4-start; grid-row-start: 2 grid-row-end: span 2 }
如果没有声明 grid-column-end / grid-row-end,默认情况下,该网格项将跨越1个轨道。
网格项可以相互重叠。 您可以使用z-index来控制它们的堆叠顺序。
grid-column / grid-row
grid-column-start + grid-column-end, 和 grid-row-start + grid-row-end 的简写形式。
值:
.item { grid-column: <start-line> / <end-line> | <start-line> / span <value>; grid-row: <start-line> / <end-line> | <start-line> / span <value>; }
举例:
.item-c { grid-column: 3 / span 2; grid-row: third-line / 4; }
如果没有指定结束行值,则该网格项默认跨越1个轨道。
grid-area
给 grid item 进行命名以便于使用 grid-template-areas 属性创建模板时来进行引用。另外也可以做为 grid-row-start + grid-column-start + grid-row-end + grid-column-end 的简写形式。
值:
.item { grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>; }
举例:
给一个网格项命名
.item-d { grid-area: header }
作为 grid-row-start + grid-column-start + grid-row-end + grid-column-end 的简写:
.item-d { grid-area: 1 / col4-start / last-line / 6 }
justify-self
沿着行轴对齐grid item 里的内容(与之对应的是 align-self, 即沿列轴对齐)。 此属性对单个网格项内的内容生效。
值:
举例:
.item-a { justify-self: start; }
.item-a { justify-self: end; }
.item-a { justify-self: center; }
.item-a { justify-self: stretch; }
要为网格中的所有grid items 设置对齐方式,也可以通过 justify-items 属性在网格容器上设置此行为。
align-self
沿着列轴对齐grid item 里的内容(与之对应的是 justify-self, 即沿行轴对齐)。 此属性对单个网格项内的内容生效。
值:
.item { align-self: start | end | center | stretch; }
举例:
.item-a { align-self: start; }
.item-a { align-self: end; }
.item-a { align-self: center; }
.item-a { align-self: stretch; }
要为网格中的所有grid items 统一设置对齐方式,也可以通过 align-items 属性在网格容器上设置此行为。
译者:若愚老师
原文链接:https://zhuanlan.zhihu.com/p/33030746
*请认真填写需求信息,我们会在24小时内与您取得联系。