Grid —— CSS网格布局初探

原文链接

前言

CSS网格布局是CSS中最强大的布局系统。 这是一个二维系统,这意味着它可以同时处理列和行, 不像flexbox那样主要是一维系统。 你可以通过将CSS规则应用于父元素(网格容器) 和该元素的子元素(网格元素)来使用网格布局。

通过网格布局和媒体查询的结合,不需要修改任何文档结构就可以重新排列元素布局的顺序,达到理想的布局效果。

下文中可点击”点击展开“查看具体代码及效果,可以点击“show in codepen”跳转到codepen自行调试,如没有,请点击原文链接查看原文。

先看一个例子: demo 这种布局已经司空见惯了。我们看用grid的话,可以有哪些骚操作:

<div class="grid">
    <div class="item header">header</div>
    <div class="item content">content</div>
    <div class="item sidebar">sidebar</div>
    <div class="item footer">footer</div>
</div>
.grid {
    display: grid;
    grid-gap: 5px;
    height: 400px;
    grid-template-areas: "header  header"
                         "content sidebar" 
                         "footer  footer";
    grid-template-columns: 1fr 100px;
    grid-template-rows: 80px 1fr 80px;
}

.header {
    grid-area: header;
    background-color: #009688;
}

.content {
    grid-area: content
}

.sidebar {
    grid-area: sidebar;
    background-color: #ff5722;
}

.footer {
    grid-area: footer;
    background: #9c27b0;
}
点击展开

几个概念

网格容器(Grid Container)

顾名思义,真个望各位布局的容器,所有网格项目的父元素,例如上面例子中.grid。

网格项目(Grid Item)

网格容器里的子元素(直接子元素),上例中的.item。

网格线(Grid Line)

简单理解,就是网格元素之间的缝隙。它们既可以是垂直的,也可以是水平的,并位于行或列的任一侧。 demo

网格轨道(Grid Track)

两个相邻网格线之间的空间。 可以把它们想象成网格的列或行。 demo

网格单元(Grid Cell)

两个相邻的行和两个相邻的列网格线之间的空间。它是网格的一个“单元”。 demo

网格区域(Grid Area)

四个网格线包围的总空间。 网格区域可以由任意数量的网格单元组成。 demo

属性列表

网格容器

  • display
  • grid
  • grid-template
  • grid-template-columns
  • grid-template-rows
  • grid-template-areas
  • grid-gap(grid-column-gap/grid-row-gap)
  • grid-auto-flow
  • grid-auto-columns
  • grid-auto-rows
  • justify-items
  • align-items
  • justify-content
  • align-content

网格项目

  • grid-column(grid-column-start/grid-column-end)
  • grid-row(grid-row-start/grid-row-end)
  • grid-area
  • justify-self
  • align-self

下面我们一起详细地学习这些属性——

display

.grid {
    display: grid | inline-grid | subgrid;
}
  • grid – 生成一个块级(block-level)网格
  • inline-grid – 生成一个行级(inline-level)网格
  • subgrid – 如果你的 grid container 本身就是一个 grid item(即,嵌套网格),你可以使用这个属性来表示你想从它的父节点获取它的行/列的大小,而不是指定它自己的大小。

grid-template-columns / grid-template-rows

.grid {
    grid-template-columns: <track-size> ... | <line-name> <track-size> ...;
    grid-template-rows: <track-size> ... | <line-name> <track-size> ...;
}

用空格分隔的值来定义网格的列和行,值表示的是轨道大小。 如果轨道值之间有line name,表示自定义的网格线名称,如果没有,系统会自动分配从1开始递增的数字名称。

轨道值

任何非负值,长度可以是px、%、em等长度单位的值。 如:

grid-template-columns: 100px 30% 200px;
grid-template-rows: 50px 100px;

demo

点击展开

定义了一个2行3列的网格,第二列占据30%父元素宽度。

grid-template-columns: 100px 2fr 1fr;
grid-template-rows: 50px 100px;

demo

点击展开

fr单位可以创建一个弹性的网格轨道。这个例子中,网格容器的列分成了100px和3等份(1 + 2 = 3),每一份(1fr)是网格容器宽度的三分之一。所以第二个item和第三个item的宽度分别是网格容器宽度的三分之二和三分之一。

如果定义中包含重复的部分,则可以使用repeat()方法来简化写法:

grid-template-columns: repeat(2, 100px 1fr);

参数1是可以是重复的次数,参数2是重复的内容。

点击展开

参数1也可以是auto-fill和auto-fit。

auto-fill创建了许多与网格容器相匹配的轨道,而不会导致网格溢出。

auto-fit与auto-fill类似,只是在网格项放置之后,它只会在需要时创建尽可能多的轨道,而重复的空轨道会堆叠在一起(合并)。

对于同样的四个项目的结构,二者的区别见下图:

grid-template-columns: repeat(auto-fill, 100px);效果着这样婶儿的: demo

grid-template-columns: repeat(auto-fill, 100px);效果是这样婶儿的: demo

具体有什么用?😰 额。。。我也不太清楚,这里先不深究了。

minmax

grid-template-columns/rows的参数还可以使用minmax函数,具体怎么使用可以看这里minmax()函数如何工作

grid-gap

.grid {
    grid-gap: <grid-row-gap> <grid-column-gap>;
}

这个简单,是grid-column-gap和grid-row-gap的缩写形式,分别定义列与列、行与行之间的间隙。上面的例子已经用到了。

grid-column / grid-row

grid-column:grid-column-start / grid-column-end的缩写

grid-row:grid-row-start / grid-row-end的缩写

可使用grid-column / grid-row来定义网格的大小(跨度)定位网格。定位我们一会再说,先看下如何定义网格的大小。 这类似于table的合并单元格(rowspan、colspan),不同的是网格项数目并不会增减。

grid-column: span 2;
grid-row: span 2;

demo

点击展开

通过网格线名称定位

grid-column: 2 / 4;
grid-row: 3 / 5;

相当于

grid-column-start: 2;
grid-column-end: 4;
grid-row-start: 3;
grid-row-end: 5;

也相当于

grid-column: 2 / 4;
grid-row: 3 / 5;

grid-column: 2;
grid-row: 3;

相当于

grid-column-start: 2;
grid-column-end: auto;
grid-row-start: 3;
grid-row-end: auto;

demo

点击展开
grid-column: 2 / span 2;
grid-row: 3 / span 2;

demo

点击展开

通过网格区域定位

grid-area

grid-area: grid-row-start / grid-column-start / grid-row-end / grid-column-end的缩写,可以是默认的数字网格线名称,也可以是自定义的网格线名称,

还可以是一个具体的自定义的名称,见开头的例子: 给每个块定义grid-area名称,然后通过grid-template-areas定义块的布局。这种写法简单明了,一眼就能看出整体布局。

点击展开

隐式网格(Implicit Grid)

想象一下:网格容器中,我们定义了一个3行4列的网格,但是容器的直接子元素多余3×4=12个,那个多余的子元素该怎么安排呢。 css规定,没有显式地定义的网格项目(即显式网格外面的项目)会形成一个隐式网格。这一部分元素可通过grid-auto-columns、 grid-auto-rows和grid-auto-flow控制。

grid-auto-columns / grid-auto-rows

分别定义隐式网格列和行的尺寸。

点击展开

grid-auto-flow

默认值是row,定义网格的展示方式:网格项目是按列的方式还是行的方式排列。

.grid {
  	grid-auto-flow: row | column | row dense | column dense
}

tip

可以给grid-auto-flow属性添加另外一个关键词dense(密集的),这个属性值相当有用:系统会利用自动排列算法尽可能的填补空缺, 使布局变得密集。但这可能打乱元素原来的顺序,这也意味着它不能友好地反映文档流顺序,这一点对于一些用户而言并不总是有用的。

看下前后对比图:

前:demo

后:demo

点击展开

对齐相关

justify-items、justify-self指定网格项目沿着轴对齐方式。

align-items、align-self指定网格项目沿着轴对齐方式。

align-content指定网格轨道沿着轴对齐方式; justify-content指定网格轨道沿着轴对齐方式。

他们所对应的值及具体表现形式,可参考这里,不再赘述了。

浏览器调试

firefox里,可以通过设置显示网格的名称、行号等信息,点这里看详情,非常方便, 如下图: demo

tip

从图中可以看出,grid-column/row-start/end是可以为负数的,正负值差别是,位置将从相反的方向开始。

这样看来*-end也是可以小于*-start的。

chrome的高一点版本(我的是67),可以显示对应网格线,不知道能不能进一步设置?。。。 如下图: demo 但是chrome有一个网格布局高亮插件可以帮助到我们。

总结

关于Grid布局,本文讲解的东西对于全民啊理解网格布局还只是杯水车薪,其中的好多细节都没有涉及到。 若发现有错误的地方,欢迎不吝指教!🙏

想要了解更多,推荐进这里或者这里的一些demo进一步学习。

参考资料

欢迎关注

赏不赏,看您心情