网格布局(CSS Grid Layout)浅谈

浏览: 224 发布日期: 2017-01-01 分类: css

近几年,Flexbox的出现,带来了巨大的轰动效应,它使CSS变得更加强大,给我们带来了更大的施展空间,并在几乎所有的浏览器中都得到了很好地支持,你没有理由不使用它。我们发现Flexbox在很多情况下对我们非常有帮助,但是它绝对不是一个构建整个布局的理想候选方案。我们更倾向于使用浮动或者内联元素来构建整体布局,但是这并不是浮动、内联元素被创建出来的初衷。但很遗憾CSS从来没有一个这样的内置功能,为了建立布局,我们没有选择,只能用这些Hack。

好消息是 CSS Grid Layout Model 是一个转折点,我们可以用它的一些基础功能就可以重建一些标准布局。目前,浏览器对网格布局的支持情况还不是很理想。唯一支持它的浏览器是Edage和最新的Internet Explorer 。幸运的是,我们可以在Google Chrome,FireFox ,Safari 上手动启用该功能,在Chrome上我们在导航栏输入 chrome://flags 切换到“启用实验性Web平台”标识并重启浏览器,FireFox上我们在导航栏输入 about:config , 搜索 layout.css.grid.enabled 设置为 true ,Safari上我们需要下载 Safari Technology Preview 版本的浏览器,就可以使得浏览器支持网格布局。

博客布局的重新设计

博客的布局是我们比较熟知的常用布局之一,有页眉(header),内容(content),侧边栏(sidebar),和页尾(footer)组成。我们接下来就围绕博客布局去介绍网格布局的基本概念。

网格布局术语

  • 网格容器
  • 网格线
  • 网格轨道
  • 网格单元格
  • 网格区域

网格容器

网格容器为其中的内容建立新的 网格格式化上下文 ( grid formatting context ),网格容器构成了内部网格项的边界

网格线

网格线是水平和垂直分隔线。 我们将使用它们来构建网格轨道,网格单元格和网格区域。 他们有一个数字索引,或者我们也可以给他们一个特定的名字。

网格轨道

网格轨道是两条线之间的垂直或水平空间。

网格单元格

网格单元是在两个相邻的水平网格线和两个相邻的垂直网格线之间的项目。 它是我们可以把内容放入的最小单位。

网格区域

网格布局的完整实现

现在我们用网格布局实现一下博客布局:

<div class="blog">  
  <div class="header">Header</div>
  <div class="content">Content</div>
  <div class="sidebar">Sidebar</div>
  <div class="footer">Footer</div>
</div>

首先我们要设置 display 为 grid 属性,对于其他的设置,我使用绝对值(pixels)作为长度单位,当然,也有更好的其他尝试(例如百分比、em、rem、vw和vh)。 属性 grid-template-columns 和 grid-template-rows 将生成网格轨道划分最外面的网格容器。 这两个属性的值既可以用固定值也可以使用auto。

.blog {
  display: grid;
  grid-template-columns: 400px 20px 180px;
  grid-template-rows: 100px 20px 210px 20px 100px;
}

定义网格的外观,看下面的代码,以及代码下面的解释图片:

.header {
  grid-row-start: 1;
  grid-row-end: 2;
  grid-column-start: 1;
  grid-column-end: 4;
}
.content {
  grid-row-start: 3;
  grid-row-end: 4;
  grid-column-start: 1;
  grid-column-end: 2;
}
.sidebar {
  grid-row-start: 3;
  grid-row-end: 4;
  grid-column-start: 3;
  grid-column-end: 4;
}
.footer {
  grid-row-start: 5;
  grid-row-end: 6;
  grid-column-start: 1;
  grid-column-end: 4;
}

我们也可以使用缩写:

.header {
  grid-row: 1 /2;
  grid-column: 1 /4;
}
.content {
  grid-row: 3 /4;
  grid-column: 1 /2;
}
.sidebar {
  grid-row: 3 /4;
  grid-column: 3 /4;
}
.footer {
  grid-row: 5 / 6;
  grid-column: 1 / 4;
}

怎么样才能更短呢? grid-area 遵循以下顺序: grid-row-start , grid-column-start , grid-row-end , grid-column-end

.header {
  grid-area: 1 / 1 / 2 / 4;
}
.content {
  grid-area: 3 / 1 / 4 / 2;
}
.sidebar {
  grid-area: 3 / 3 / 4 / 4;
}
.footer {
  grid-area: 5 / 1 / 6 / 4;
}

最终代码是这样的:

.wrapper {
  display: grid;
  grid-template-columns: 400px 20px 180px;
  grid-template-rows: 100px 20px 210px 20px 100px;
}
.header {
  grid-area: 1 / 1 / 2 / 4;
}
.content {
  grid-area: 3 / 1 / 4 / 2;
}
.sidebar {
  grid-area: 3 / 3 / 4 / 4;
}
.footer {
  grid-area: 5 / 1 / 6 / 4;
}

上面这个例子很容易让你对即将到来的CSS网格布局充满憧憬,它真的是很好玩的东西,它入门很简单,通俗易懂,使人非常容易接受。但是更深入的接触之后会发现其实网格布局是很复杂的,甚至超过了Flexbox,它足足有17个新特性,并且围绕着我们编写CSS的方式介绍了许多新的概念,所以为了理解这个新的规范,弄清实战中它是怎样工作的,我们用它来创建一个圣杯布局。

什么是圣杯布局(Holy Grail Layout)

圣杯布局是一种网页布局,由四部分组成:一个页眉,页脚和一个主要内容区域,有两个侧边,每边一个。布局遵循一下规则:

  • 两边带有固定宽度中间可以流动(fluid)
  • 中心列最先出现在标记中
  • 所有三列不管其中内容如何变化,都应该是相同的高度
  • 页脚应该总是在浏览器视窗的底部,即便内容不填满整个适口的宽度
  • 响应式布局,在较小的视口中,各部分要进行折叠,宽度100%显示

圣杯布局在CSS中,如果不用任何Hack是很难去实现的。

用网格布局的解决方案

html

<body class="hg">  
  <header class="hg__header">Title</header>
  <main class="hg__main">Content</main>
  <aside class="hg__left">Menu</aside>
  <aside class="hg__right">Ads</aside>
  <footer class="hg__footer">Footer</footer>
</body>

它的CSS只有31行!

.hg__header { grid-area: header; }
.hg__footer { grid-area: footer; }
.hg__main { grid-area: main; }
.hg__left { grid-area: navigation; }
.hg__right { grid-area: ads; }

.hg {
    display: grid;
    grid-template-areas: "header header header"
                         "navigation main ads"
                         "footer footer footer";
    grid-template-columns: 150px 1fr 150px;
    grid-template-rows: 100px 
                        1fr
                        30px;
    min-height: 100vh;
}

@media screen and (max-width: 600px) {
    .hg {
        grid-template-areas: "header"
                             "navigation"
                             "main"
                             "ads"
                             "footer";
        grid-template-columns: 100%;
        grid-template-rows: 100px 
                            50px 
                            1fr
                            50px 
                            30px;
    }
}

分解代码

上面说过,CSS网格布局可以非常复杂,然后,我创建这个圣杯布局只用了17个新特性的4个:

  • grid-area
  • grid-template-areas
  • grid-template-columns
  • grid-template-rows

我们用这些网格属性去实现圣杯布局布局可分为5个步骤。

1.定义网格

我们要做的第一件事情就是确认网格的区域,所以我们可以在创建网格时通过这个别名来引用它们。 我们使用 grid-area 属性。

.hg__header { grid-area: header; }
.hg__footer { grid-area: footer; }
.hg__main { grid-area: main; }
.hg__left { grid-area: navigation; }
.hg__right { grid-area: ads; }

然后,使用 grid-template-areas 属性,我们可以用非常直观的方式指定网格的布局。 grid-template-areas 属性接受一个空格分隔的字符串列表,每个字符串表示一行。 在每个字符串中,我们有一个空格分隔的网格区域列表,定义的每个网格区域占用一列。 因此,如果我们想要一个区域跨越两列,我们定义它两次。 在我们的圣杯布局中,我们有3列和3行。 页眉和页脚行横跨3列,而其他区域各跨1列。

.hg {
    display: grid;
    grid-template-areas: "header header header"
                         "navigation main ads"
                         "footer footer footer";
}

使用这个标记,我们得到以下的结果:

2.定义列宽

下一步,我们要定义的列的宽度。我们使用 grid-template-columns 属性定义列的宽度。该属性接受空格分格的宽度列表,网格中的每一列都有一个宽度。因为我们的布局有3列,我们可以指定3个宽度:

grid-template-columns: [column 1 width]  [column 2 width]  [column 3 width];

对于圣杯布局,我们希望2个侧边宽度为150px。

.hg {
  grid-template-columns: 150px  [column 2 width] 150px;
}

我们还希望中间列占据空间的其余部分。 我们可以通过使用新的 fr 单位来做到这一点。 此单位表示网格中剩余的自由空间的一小部分。 在我们的例子中,剩余自由空间是网格的当前宽度减去300px(两个边栏的宽度)。

.hg {
    grid-template-columns: 150px 1fr 150px;
}

设置网格列之后,这是布局的样子 :

3.定义行高

接下来,我们要定义行的高度。 类似于我们 grid-template-columns 定义列宽,我们使用 grid-template-rows 定义行高。此属性还接受用空格分隔列表。虽然我们可以写在一行,但是我认为一行一行去写会更加直观清楚。

.hg {
    grid-template-rows: 100px 
                        1fr
                        30px;
}

因此,我们的标题高度是100px,我们的页脚高度是30px,中间行(主要内容和两个侧边栏)占用 .hg 元素的剩余可用空间。

4.固定页脚

在圣杯布局中,我们希望页脚始终位于视口的底部,即使页面上的内容不被充满一屏。 为了实现这一点,我们可以将 .hg 元素的最小高度设置为视口的高度。

.hg {
    min-height: 100vh;
}

因为我们指定中间行应该填充剩余的可用空间,它会伸展到填满屏幕。

5.设置响应式

最后,我们想让布局响应。 在较小的设备上,所有网格项目应该一个接一个地显示在一列中。 为此,我们需要重新定义之前定义的3个属性: grid-template-areas , grid-template-columns 和 grid-template-rows 。 首先,我们想要网格中的所有项目按照特定的顺序在一个列中:

@media screen and (max-width: 600px) {
    .hg {
        grid-template-areas: "header"
                             "navigation"
                             "main"
                             "ads"
                             "footer";
    }
}

接下来,我们想要所有项目占满网格宽度的100%:

@media screen and (max-width: 600px) {
    .hg {
        grid-template-columns: 100%;
    }
}

最后,我们需要重置每一行的高度。 除了主行之外,所有行限定它的高度:

@media screen and (max-width: 600px) {
    .hg {
        grid-template-rows: 100px /* Header */
                            50px /* Navigation */
                            1fr /* Main Content */
                            50px /* Ads */
                            30px; /* Footer */
    }
}

完成!在这里你可以看到它的 演示和源码 (你可能需要在浏览器中启用实验性的网络功能来查看它)

Grid Layout Module vs Flexbox

Flexbox适用于许多布局和很多“页面组件”元素,因为它们大多是基本线性的。 Grid适用于整体页面布局,以及非线性的复杂页面组件。

这两个可以任意组合,所以一旦广泛支持,我相信大多数页面将由一个外部网格的整体布局,混合嵌套flexbox和网格的页面组件,最后 block / inline-block / table 布局在页面装饰文本和内容。

网格布局资源

上面讲的两种布局只使用了网格布局的4种属性,没有涵盖所有的网格布局概念和语法,如果对网格布局有兴趣,可以去下面的资源中更深入学习:

CSS Grid Layout Module spec

A Complete Guide to CSS Grid Layout

CSS Grid Layout Examples Grid by Example

The future of layout with CSS: Grid Layouts

还有 Rachel Andrew 的关于网格布局的 最新信息和资源 。 她为网格布局做了许多贡献。

总结

正如你所看到的,即将到来的CSS网格布局是强大的,因为它的代码简洁易懂,你很容易去设计和改变布局顺序。这些功能可以帮助我们永久改变网络开发中创建布局的方式,所以,我相信网格布局是CSS布局的未来!

http://chris.house/blog/a-complete-guide-css-grid-layout/

https://en.wikipedia.org/wiki/Holy Grail (web_design)

https://bitsofco.de/holy-grail-layout-css-grid/

https://www.sitepoint.com/introduction-css-grid-layout-module/

 

来自:https://fe.ele.me/wang-ge-bu-ju-css-grid-layout-qian-tan/

 

返回顶部