Grid —— CSS网格布局初探

1,444 阅读13分钟

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;
}
See the Pen &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia/pen/QxYqLm/&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;demo&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Denzel (&amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;@_tianxia&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. show in codepen 点击展开

几个概念

网格容器(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

See the Pen &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia/pen/vrbJPG/&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;1&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Denzel (&amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;@_tianxia&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. show in codepen 点击展开

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

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

demo

See the Pen &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia/pen/oymOLJ/&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;2&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Denzel (&amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;@_tianxia&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. show in codepen 点击展开

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

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

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

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

See the Pen &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia/pen/GGzLbj/&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;3&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Denzel (&amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;@_tianxia&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. show in codepen 点击展开

参数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

See the Pen &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia/pen/rKPgNo/&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;4&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Denzel (&amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;@_tianxia&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. show in codepen 点击展开

通过网格线名称定位

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

See the Pen &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia/pen/ERrzLa/&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;6&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Denzel (&amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;@_tianxia&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. show in codepen 点击展开
grid-column: 2 / span 2;
grid-row: 3 / span 2;

demo

See the Pen &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia/pen/GGzavE/&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;5&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Denzel (&amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;@_tianxia&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. show in codepen 点击展开

通过网格区域定位

grid-area

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

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

See the Pen &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia/pen/dKaEjN/&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;7&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Denzel (&amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;@_tianxia&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. show in codepen 点击展开

隐式网格(Implicit Grid)

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

grid-auto-columns / grid-auto-rows

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

See the Pen &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia/pen/GGzVrR/&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;8&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Denzel (&amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;@_tianxia&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. show in codepen 点击展开

grid-auto-flow

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

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

tip

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

看下前后对比图:

前:demo

后:demo

See the Pen &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia/pen/eKQNYm/&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;9&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Denzel (&amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io/_tianxia&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;@_tianxia&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a href=&amp;amp;amp;amp;amp;quot;https://codepen.io&amp;amp;amp;amp;amp;quot; data-v-ba9b4902&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. show in codepen 点击展开

对齐相关

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进一步学习。

参考资料