您现在的位置: 365建站网 > 365学习 > CSS Grid和Flexbox实际的布局用法和区别

CSS Grid和Flexbox实际的布局用法和区别

文章来源:365jz.com     点击数:186    更新时间:2018-06-11 11:25   参与评论

Grid布局方式借鉴了平面装帧设计中的格线系统,将格线运用在屏幕上,而不再是单一的静态页面,可以称之为真正的栅格。本文将详细介绍grid布局

引入

  对于Web开发者来说,网页布局一直是个比较重要的问题。但实际上,在网页开发很长的一段时间当中,我们甚至没有一个比较完整的布局模块。总的来说 Web 布局经历了以下四个阶段:

  1、table表格布局,通过 Dreamweaver 拖拽表格或者手写 table 标签布局

  2、float浮动及position定位布局,借助元素元素盒模型本身的特性以及 float position 等属性等进行布局

  3、flex弹性盒模型布局,革命性的突破,解决传统布局方案上的三大痛点 排列方向、对齐方式,自适应尺寸。是目前最为成熟和强大的布局方案

  4、grid栅格布局,二维布局模块,具有强大的内容尺寸和定位能力,适合需要在两个维度上对齐内容的布局

  Grid Layout 是一种基于二维网格的布局系统,旨在完全改变我们设计基于网格的用户界面的方式,弥补网页开发在二维布局能力上的缺陷

  与flex分为伸缩容器和伸缩项目类似,grid也分为网格容器和网格项目

 

网格容器

display


  通过display属性设置属性值为grid或inline-grid可以创建一个网格容器。网格容器中的所有子元素就会自动变成网格项目(grid item)

display: grid
display: inline-grid

  网格项目默认放在行中,并且跨网格容器的全宽

 

显式网格


  使用grid-template-columns和grid-template-rows属性可以显式的设置一个网格的列和行 

【grid-template-rows】

  默认值为none

  grid-template-rows指定的每个值可以创建每行的高度。行的高度可以是任何非负值,长度可以是px、%、em等长度单位的值

grid-template-rows: 60px 40px

  item1和item2具有固定的高,分别为60px和40px。因为只定义了两个行的高度值,所以item3和item4的高度是根据其自身的内容来定义。


【grid-template-columns】

  默认值为none

  像行一样,通过grid-template-columns指定的每个值来创建每列的列宽

grid-template-columns: 40px 50px 60px

  item4和item5放置在新的一行(第二行),因为grid-template-columns只定义了三列的大小,它们也分别放置在列1、列2和列3;其中列1、列2和列3的尺寸大小等于item1、item2和item3宽度。item1、item2和item3具有固定的宽度值,分别为40px、50px和60px



在深入介绍Flexbox和Grid结合优势之前,先来看看这样的一个需求。需要做一个响应式设计,这个设计效果看起来复杂,在不同的视窗中,改变顺序和布局的效果。这个设计效果看起来复杂,但用CSS的Grid和Flexbox来实现这样的布局,就会显得容易多了。

先来看我们需要的设计风格:

上面的是设计草图。从草图上可以看出,不管是什么样的屏幕下,整个Card有四个区域:A、B、C和D。那么我们就很容易借助Grid来构建这几个区域了。

构建CSS Grid

从上面的草图我们可以看出,我们可以把整个卡片分成四个区域。如下图:

如果你接触过CSS的Grid,你肯定知道,有一些属性是浏览器还不支持的。不过这里咱们不纠结这一部分,在这个示例中,使用浏览器已支持的属性。那么回到示例中来,我们整个Card分为四个区域。那么对应的HTML中,我们也是使用四个区域:

<div class="card">
    <div class="grid-area grid-area_a">A区</div>
    <div class="grid-area grid-area_b">B区</div>
    <div class="grid-area grid-area_c">C区</div>
    <div class="grid-area grid-area_d">D区</div></div>

你可以具体化每个区域。但暂时我们不处理每个区域内部内容。

移动端优先

了解响应式布局的同学都应该知道,在响应式布局中,遵循的原则是移动端先行。那咱们先实现移动端的布局。

这是一个非常简单的网格布局。我们可以使用CSS的Grid来实现:

.card {    display: grid;
    grid-template-rows: repeat(3, min-content);
    grid-template-columns: 33% calc(67% - 55px) 55px;
    grid-auto-rows: min-content;}.grid-area_a {    grid-row: 1 / span 2;
    grid-column: 1;
    background-color: green;}.grid-area_b {    grid-row: 1;
    grid-column: 2 / span 2;
    background-color: orange;}.grid-area_c {    grid-row: 2;
    grid-column: 2 / span 2;
    background-color: lime;}.grid-area_d {    grid-row: 3;
    grid-column: 1 / span 3;
    background-color: yellow;}

通过Firefox浏览器网格调试工具,我们可以看很清楚的看出我们的网格分布图:

再给.card添加一下基本样式:

.card {    max-width: 300px;
    position: relative;
    padding: 15px 10px;
    background-color: gray;}

可以看到的效果如下:

上面看到的效果仅是几个区域的布局效果。我们接下来给里面添加内容,并加上对应的效果,看到的卡片效果如下:

上面的草图对于移动端还有第二种风格。

.card {    display: grid;
    grid-template-rows: repeat(3, min-content);
    grid-template-columns: 33% calc(67% - 95px) 95px;
    grid-auto-rows: min-content;}.grid-area_a {    grid-row: 1 / span 3;
    grid-column: 1;}.grid-area_b {    grid-column: 2;}.grid-area_c {    grid-row: 2;
    grid-column: 2;}.grid-area_d {    grid-row: 1 / span 3;
    grid-column: 3;    }

PC端布局

移动端先行,上面我们实现了两种移动端的布局。接下来处理PC端,也就是桌面端。这个我们通过媒体查询来处理。

@media only screen and (min-width: 768px) {    .card {        grid-template-rows: repeat(4, min-content);
        grid-template-columns: 100%;
    }

    .grid-area {        grid-column: 1;
    }

    .grid-area_a {        grid-row: 1;
    }

    .grid-area_b {        grid-row: 2;
    }

    .grid-area_c {        grid-row: 3;
    }

    .grid-area_d {        grid-row: 4;
    }

    .grid-area_d {        flex-direction: row;
    }}

效果如下:

多卡片

上面看到的效果,我们只是一张卡片。如果我们有N张卡片呢?首先我们在HTML中复制一下.card的结构。让我们的页面具有N张卡片。

同样是移动端先行。代码稍做调整:

.card {    max-width: calc(100vw - 10px);}body {    display: grid;
    grid-auto-rows: min-content;}@media only screen and (min-width: 768px) {    body {        grid-template-columns: repeat(4, auto);
    }
    .card {        max-width: 400px;
        grid-template-rows: repeat(4, min-content);
        grid-template-columns: 100%;
        margin: 5px;
    }
    ...
}

拖动你的浏览器,可以看到的效果如下:

2017年3月,CSS Grid在几个星期内就被发送到Chrome、Firefox和Safari的生产版本中。很高兴,大家可以使用它来解决实际问题。

CSS Grid是一种不同的布局方式,在大家开始使用规范的时候,有很多常见的问题。这篇文章的目的是回答其中的一些问题,并且将会是Smashing Magazine中有关于CSS Grid一系列文章中的一篇。

为什么使用CSS Grid而不是CSS Flexbox?

在CSS网格布局在浏览器中可用之前,很多人都认为Flexbox是我们所有设计相关问题的答案。然而,Flexbox并没有提供比浮动更好的网格系统,尽管它确实比浮动创建一个网格系统更简单。一个真正的网格是二维的。这两个维度就是行和列,并且使用网格布局,你可以同时控制它们。使用Flexbox,你可以选择是否将这些项列成一行或列,一个或另一个,而不是两个。

这里有一个简单的示例,突出其区别。第一个布局使用Flexbox,为了能尽可能多的使用盒子,以适合可用的宽度。这里我们控制了整个行中的布局。允许Flex项目进行包裹,因此会创建新的行,但是每一行都是一个新的Flex容器。空间分布在行中发生,所以取决于最后一行多少项,它们有时不会与上面的Flex项对齐。

第二个示例使用CSS Grid实现相同的布局,但是,你可以看到,最后一行中的项目始终保持在它们的列中。这是因为在网格中,我们将项目排列成行和列 —— 二维布局。

你还可以在第二个示例中看到,在CSS Grid布局中,我们不需要向网格添加任何内容来进行布局。所有东西都被放在容器上。在Flexbox布局中,你必须针对Flex项目来设置flex-grow、flex-shrink和flex-basis属性。这是理解网格布局关键所在,也可能是大家有很多困惑的地方。Grid主要是关于包含元素的,而我们之前的所有布局方法都依赖于我们在布局中设置的宽度,使某些东西看起来像一个网格。

如果你使用一个简化版本的浮动12列“网格”,我们必须计算每一列的百分比大小,加上每个列之间间距的百分比大小。要创建跨多个列的项,需要将所有项的宽度加上用于分隔它们的边界宽度。

使用Flexbox创建的网格也是如此。当我们在父节点上通过display:flex创建Flex布局时,Flex所有的大小都需要在单个Flex项目上进行。为了制作一个Flexbox的“网格”,我们必须阻止Flexbox做灵活的操作,而是应该设置百分比宽度,就像我们前面的浮动网格示例一样。使用Flexbox要比浮动更有一些优势,比如控制对齐和列等高之类的要简易得多。然而,在Flexbox和浮动的方法中仍然没有网格,只是通过设置项目的大小,并将它们排列起来,让其看起来像网格的东西。

在网格中,所有的大小都发生在容器上。一旦我们创建了我们的网格轨道,我们就可以告诉单个项目(Grid项目)有多少个轨道可以跨越,但我们却有一个实际的网格。我们可以完全抛弃行的容器,因为网格已经有行了。这也意味着,我们也可以使用相同的方式进行跨列。这对于以前而言是件很难做的事情。

是否应该将网格用于主布局和Flexbox用于组件布局

随着大家开始接触和学习CSS Grid的布局,这个神话不断涌现。也许它来自于网格系统的使用,比如在Bootstrap或Foundation,大家关心的是一个整体网格上放置项目。这当然是使用网格布局的一种方法。不过,我还是会考虑在上一节提到的不同之处。问问你自己,这个布局是一维的还是二维的?

如果你可以使用你的组件,并且用行和列在它的上面绘制一个网格。它是二维的,那就使用CSS Grid来布局。

如果相反,你希望单个项目在一行中进行扩展,而不考虑上面一行中发生的情况,那就应该使用Flexbox布局更为合适。

不管你想要展示的是一个完整的页面,还是一个很小的组件。重要的是你想在布局里面的项目分配空间和相互关联。

网格轨道大小是否由内容来决定?

我们已经看到了如何在使用网格布局时,在容器上设置网格和网格大小。但是,网格中的项可以指定网格轨道大小。这里要记住的关键是,一个单元格大小的改变将会改变整个轨道的大小。如果你不希望这种情况发生,你可能需要一个单一维度的Flexbox布局。

最简单的方法就是使用auto,因为它会默认在隐式网格中创建网格轨道。一个自动大小的网格轨道将扩展到包含所有的内容。在下面的示例中,我有一个两列布局,在右边的列中添加更多的内容会导致整个行的扩展。第二行也是自动大小,再扩展以包含内容。

我们可以使用两个参数来控制网格轨道大小,例如创建一个最小的网格轨道,但其仍然会增长以适应较大的网格项目。我们可以使用minmax()函数来做这个。传给minmax()函数的第一个值,它是网格轨道最小的值,第二个值是网格轨道最大的值。因此,你可以设置200px的行,但通过auto设置为网格轨道最大值,那么当有较多的内容时,不会出现内容溢出。

也有一些有趣的关键词可以设置大小,将在以后的文章中对它们进行适当的阐述。这些关键词在指定网格中允许内容来改变网格轨道大小,并且可以在CSS内部和外部的大小模块(CSS Intrinsic and Extrinsic Sizing Module)中找到相关的详细内容。例如min-content关键词的示例,使用它创建一个网格轨道时,将会创建尽可能小的网格轨道。

在我的例子中,这个词意味着其成为最宽的东西,网格轨首缩小以适应它。

相反,如果你使用的是max-content,你会得到一个尽可能大的网格轨道。这可能会导致溢出情况,在下面的示例中,使用了overflow: scroll设置了网格溢出,所以max-content的网格轨道会导致滚动条出现。

关键要记住的是,这将会发生在整个网格轨道上。你需要确保网格轨道的其他网格项目也能巧妙地吸收额外的空间。

了解了如何对网格轨道大小进行调整,以及内容将如何改变网格轨道大小,这可能是新手使用CSS Grid布局中会感到最为困惑的事情之一。这需要花一点时间来理解 —— 我们之前没有任何类似的行为。这是理解事物如何运作的最好方法。

可以使用CSS Grid来实现瀑布流布局?

很多同学有一种误解,认为网格布局与瀑布流或Pinterest布局一样的。这通常是基于在网格布局中自动放置网格项目,这样的效果看上去的确有点像瀑布流布局。在下一个示例中,我有一个布局,使用grid-auto-flow设置为dense,实现网格项目自动流的布局。这将导致网格项目从源程序中取出,并尝试在网格填充空白区域。

然而这并不是真正的瀑布流布局,因为我们仍然有一个网格(具有行和列),并且潜在的网格项目从源代码中移出。一个真正的瀑布流布局将使事物在源代码中工作。项目被推上去填充部分空间。它更像是在两个维度上做Flexbox布局。

你可以通过对所有的Grid项目进行定位处理来得到一个瀑布流外观的网格布局,但是自动流的瀑布流布局,网格布局还无法具备这方面的能力。不过,未来的规范正在做这方面的考虑。

如何向网格区域添加背景和边框?

一个网格尚未完成的问题,网格区域本身的背景和边框的样式。能在网格区域上直接添加背景和边框的样式吗?到目前是不可能的,如果要实现这样的一个效果需要插入一个元素或者添加一个伪元素来完成。

下面的这个示例中,我在网格中通过伪元素来完成,将其放置在基于行的位置,然后添加一个背景和边框到该网格区域。

有时候可以绕过背景和边框来实现,比如通过网格间距(grid-gap) —— 用一个1px来模拟背景或边框,比如下面的这个示例:

为了能够对网格区域进行适当的样式化,我们需要引入网格区域伪元素的概念,这是一种特殊的生成内容。在 CSS WG上有一个关于这方面的问题,所以你可以在这里参加讨论,把你的想法与大家一起参与讨论。

跨越到网格的末端

网格布局具有隐式和显式网格的概念。显式网格是我们使用grid-template-rows和grid-template-columns定义的网格。这个网格轨道定义了显式网格的范围。当我们在显式网格之外放置一个网格项目,或者我们通过自动旋转更多的网格项目时,隐式网格就将被创建。

除非你使用grid-auto-rows或grid-auto-columns创建的网格轨道,否则在隐式网格中创建的网格轨道的大小将是自动的。

在很多情况下,隐式和显式网格的渲染行为是相同的,对于很多的布局,你会发现你定义了列,然后允许将行创建为隐式网格。不同的是,当你开始使用负的行号来引用网格的最后一行时,你会发现还是有一定区别的。

对于网格布局中的写作模式。在从左到右的语言(ltr)中,列第一行是在左边,而你可以用-1来指向右边的列。在从右到左的语言(rtl)中,列的第一行在右侧,而-1则指向左边的列。

或许你已经发现了,只有显式的网格才可以向后计数。如果你在隐式网格中添加了行,然后尝试以-1来指定目标,你将会发现你得到是显式网格的最后网格线,而不是实际网格最末端的网格线。

百分比的问题

在文章开头之处,我描述了网格布局与之前的布局方法与众不同之处。由于浮动和基于Flexbox的网格的限制,我们需要变得擅长计算百分比来做布局,所以大多数人做的第一件事就是尝试在他们的网格布局中使用相同的方法。然而,在这样做之前不要忘记我们有一个新单位fr。这个单位是专门为网格布局设计的,因为网格设置父元素的大小。

fr单位允许我们分配可用网格布局中的可用空间。其通过查看网格容器中可用的空间(去掉间距所需的空间、固定宽度的网格项目或定义网格轨道),然后按照我们为网格轨道指定的比例来对剩余的网格空间进行分配。这意味着,我们使用浮动或Flexbox布局的场景,必须有灵活的间距。

在大多数情况下,fr单位是一个比百分比更好的选择。你可能选择使用百分比的原因是你需要一个网格布局,以便与其他元素匹配使用其他布局方法,并依赖于百分比大小。然而,如果不是这样的话,看看fr单位是否能满足你的需求,然后对其进行计算。

网格可以嵌套使用?

网格项目也可以成为网格容器,就好比Flex项目也可以成为一个Flex容器一样。但是,这些嵌套网格也父网格没有任何关系,因此不能使用它们与其他嵌套网格对齐内部元素。

在将来的网格布局中,很可能会有一种创建嵌套网格的方法,它可以维护与父网格的关系。这意味着,除了网格的直接子节点,其他网格项目可能参与整个网格布局。

网格布局有对应的Polyfill吗?

我经常会被问到是否有网格布局的Polyfill,大家都想知道是否有一种方法可以支持旧的浏览器。

我的建议是,这并不是你需要做的事情。这可能会为那些已经在努力渲染现代网站的浏览器造成一定的性能影响,带来不好的用户体验。如果你南非要较旧的浏览器与现代浏览器相同,那么你可能要考虑在这个项目中是否使用网格布局。不过,在大多数情况下,可以使用较老的方法来为不支持的设备创建一个简单的降级处理,而不需要创建两个完全不同的CSS代码。这方面真的需要用一篇文章来详细阐述,所以我将尽快在Smashing Magazine发布这方面的教程。

调试网格布局

当你开始使用网格布局时,你肯定希望能看到你的网格和其网格项目是如何布局的。我建议你使用Firefox Nightly,并在Firefox 浏览器开发者工具中使用网格检查器。如果你选择一个网格,可以点击这个小网格图标 —— 我喜欢把它想像成一个华夫饼(Waffle) —— 来显示网格。

如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛


发表评论 (186人查看0条评论)
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
用户名: 验证码: 点击我更换图片
最新评论
------分隔线----------------------------