Grid用于布局,Flexbox用于组件

800 阅读12分钟

介绍

在深入研究概念和示例之前,我想确保您了解CSS Grid和flexbox之间的主要区别。CSS Grid是一个多维布局模块,这意味着它具有列和行。Flexbox可以将其子项布置为列或行,但不能两者都布置。

如果您不了解CSS Grid和flexbox,建议您认真阅读该直观文章。如果您知道它们,那就太好了,让我们深入研究它们之间的区别以及何时使用它们和为什么使用它们。

Grid和Flexbox之间的区别

让我们清楚一点,CSS Grid和felxbox没有优劣之分,只有更适合的场景。本文是一个指南,针对特定用例使用哪一种技术更好。我将解释一般概念,然后进入示例,剩下的就是需要您的探索和更多的尝试了。

/* Flexbox wrapper */
.wrapper {
    display: flex;
}

/* Grid wrapper */
.wrapper {
    display: grid;
    grid-template-columns: 2fr 1fr;
    grid-gap: 16px;
}

你有注意到吗?Flexbox正在布置元素的内联列表,而Grid使它们成为列和行的网格。Flexbox正在连续对齐路线。如果需要,可以是一列。

/* Flexbox wrapper */
.wrapper {
    display: flex;
    flex-direction: column;
}

如何决定使用哪个

在CSS Grid和flexbox之间进行选择可能有些困难(有时),特别是如果您不熟悉CSS。我可以听见你!在选择它们时,我会问自己一些页面设计相关的问题:

  • 组件子项如何显示?内联还是列和行?
  • 该组件如何在各种屏幕尺寸上工作?

大多数时候,如果您正在查看的组件的所有子项都内联显示,那么flexbox可能是此处的最佳解决方案。考虑以下示例:

但是,如果您看到列和行,那么CSS Grid就比较适合您了。

现在,我解释了它们之间的主要区别,让我们继续更具体的示例并学习如何选择。

用例

在下一节中,我将详细讨论有关flexbox和grid的不同用例。

CSS Grid

主边栏和侧边栏 如果有侧边栏和主栏,则CSS Grid是构建它们的理想解决方案。考虑以下模型:

这是我在CSS中的处理方式:

<div class="wrapper">
    <aside>Sidebar</aside>
    <main>Main</main>
</div>
@media (min-width: 800px) {
    .wrapper {
        display: grid;
        grid-template-columns: 200px 1fr;
        grid-gap: 16px;
    }
    
    aside {
        align-self: start;
    }
}

如果align-self未用于该<aside>元素,则无论其内容长度如何,其高度都将等于主要元素。

卡片网格

像本文开头所讨论的,正如CSS Grid的名字,使用它来布局卡片网格是再合适不过了。

这是实现布局的方法:

.wrapper {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    grid-gap: 16px;
}

列的宽度至少为200px,并且如果空间不足,它将把卡片换行。值得一提的是,如果视口宽度较小,则以上内容可能会导致水平滚动200px

一个简单的解决方案是仅在视口宽度足够时添加网格定义。见下文:

@media (min-width: 800px) {
    .wrapper {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
        grid-gap: 16px;
    }
}

侧边栏布局

在下面的设计中,我们可以使用grid两次,第一次是将区域划分为两个区域(“ contact us”侧边栏,表单),第二次是对表单网格本身。

CSS代码如下:

@media (min-width: 800px) {
    .wrapper {
        display: grid;
        grid-template-columns: 200px 1fr;
    }
    
    .form-wrapper {
        display: grid;
        grid-template-columns: 1fr 1fr;
        grid-gap: 16px;
    }
    
    .form-message,
    .form-button {
        grid-column: 1 / 3; /* let them take the full width */
    }
}

这个示例是从我在Envato上有关使用CSS Grid构建Web表单布局的文章中借用的。我建议读一读。

CSS Flexbox

网站导航

网站导航应使用90%都是使用CSS flexbox构建。最常见的模式是logo位于左侧,导航位于右侧。这对于flexbox是完美的。

在上面的示例中,您需要设置以下所有内容:

.site-header {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
}

相同的代码也可以用于以下设计。

注意导航结构有一些不同,但是元素之间的间距仍然是通过justify-content属性来完成的。

动作清单

当您设计一个列表时,您可能会想到的第一件事是垂直列表。但是,列表可以内联显示,因此我只想确保此内容清晰可见。

动作清单的一个例子是我们可以从Facebook或Twitter借来的东西。操作列表由用户可以采取的操作按钮组成。请参阅以下屏幕截图:

如您所见,这些项目彼此相邻显示,并且它们水平分布。Flexbox就是完美的选择!那是它的核心用途之一。

.actions-list {
    display: flex;
}

.actions-list__item {
    flex: 1; /* expand the items to take the available space equally between them */
}

另一个变化形式是模式操作按钮或模式标题。

页眉和页脚都具有内联显示的子元素。如您所见,它们之间的间距如下。

对于标题,它看起来像这样:

.modal-header {
    display: flex;
    justify-content: space-between;
}

而对于页脚,则有所不同。Cancel操作使用自动边距将其向右推。我写了一篇详细的文章

.cancel__action {
    margin-left: auto;
}

在这里的名称命名.cancel__action可能并不完美,但是我不想在本文中涉及CSS命名规范。

表单元素

输入框与旁边的按钮的组合是Flexbox的完美用例。如下图:

在第一种形式中,输入框将占用所有剩余空间,从而使其具有动态宽度。第二种形式(Facebook Messenger)同样适用,文本字段占用了所有剩余空间。让我们仔细看看。

.input { flex: 1 1 auto; }

请注意,如果输入框不使用flex: 1 1 auto,它将不会展开并填充剩余空间。

主题和评论

flexbox的另一个常见用例是评论区,考虑以下示例。

我们有用户照片和评论本身。该文本将从其父元素中获取剩余空间。这是flexbox的完美用法。

卡片组件

卡片组件具有多种变体,但是最常见的设计是类似于下面的模型。

在左侧,卡片子项被堆叠,因为flex的方向是column。在右侧,则相反,flex的方向是row。请记住,该行是flexbox的默认row

.card {
    display: flex;
    flex-direction: column;
}

@media (min-width: 800px) {
    .card {
        flex-direction: row;
    }
}

卡片的另一个常见变体是图标下方带有文本标签的图标。它可以是按钮,链接或仅用于装饰。考虑以下实例:

注意图标和文本标签如何水平和垂直居中。多亏了flexbox,这很容易做到。

.card {
    display: flex;
    flex-direction: column;
    align-items: center;
}

内联样式默认为行,我们只需要删除flex-direction: column并将其保留为默认值(row)即可。

标签/底部菜单

当涉及到占据整个屏幕宽度的元素并且应该填充所有可用空间的元素时,flexbox是理想的选择。

在上面的示例中,每个项目都应填充可用空间,并且宽度应相等。通过将display设置为flex,可以轻松完成此操作。

.tabs__item {
    flex-grow: 1;
}

该技术在React Native框架中用于构建移动应用程序的标签栏。这是一个代码示例,与React Native中的代码相同。该代码是从该资源中借用的。

import React from 'react';
import { View } from 'react-native';

export default FlexDirectionBasics = () => {
    return (
      <View style=>
        <View style= />
        <View style= />
        <View style= />
      </View>
    );
};

功能清单

我最喜欢flexbox的是反转元素方向的能力。flexbox的默认方向是行,但是我们可以如下反转。

.item {
    flex-direction: row-reverse;
}

在下面的模型中,请注意如何反转偶数项,这是通过上述技术完成的。非常有用

集中部分的内容

让我们考虑一下,我们有一个内容区,内容需要水平和垂直居中。水平居中可能很容易,因为它可以通过文本对齐来完成。

.hero {
    text-align: center;
}

但是如何使用flexbox将元素垂直居中?

.hero {
    display: flex;
    flex-direction: column;
    align-items: center; /* centers items horizontally */
    justify-content: center; /* centers items vertically */
    text-align: center;
}

结合CSS Grid和Flexbox

不仅每个布局模块都有其用例,而且我们都可以使用它们。当我考虑将它们组合时,我得到的第一个用例是卡片清单。网格用于布局卡片,而弹性框用于卡片组件本身。

这是布局要求:

  • 每行卡片的高度应相等
  • 无论其高度如何,都应将Read more链接放置在卡的末尾。
  • 网格应该使用minmax()功能
<div class="wrapper">
    <article class="card">
        <img src="sunrise.jpg" alt="">
    <div class="card__content">
      <h2><!-- Title --></h2>
      <p><!-- Desc --></p>
      <p class="card_link"><a href="#">Read more</a></p>
    </div>
    </article>
</div>
@media (min-width: 500px) {
    .wrapper {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
        grid-gap: 16px;
    }
}

.card {
    display: flex; /* [1] */
    flex-direction: column; /* [2] */
}

.card__content {
    flex-grow: 1; /* [3] */
    display: flex; /* [4] */
    flex-direction: column;
}

.card__link {
    margin-top: auto; /* [5] */
}

让我解释一下上面的CSS。

  1. 将卡制作为Flexbox包装纸。
  2. 方向是列,这意味着卡元素被堆叠。
  3. 让卡片内容扩展并填充剩余空间。
  4. 使卡片内容作为Flexbox包装器。
  5. 最后,使用margin-top: auto向下推链接。无论卡高如何,都可以将其始终放置在末端。

如您所见,将CSS Grid和flexbox结合起来并不难。这两个工具可以为我们提供许多在Web上实现布局的方法。让我们正确使用它们,并仅在如上所述需要时将它们组合。

后备和支持旧浏览器

使用CSS @supports

几个月前,我收到一条推文,说我的网站在IE11中已损坏。检查后,我注意到一个非常奇怪的行为。网站的所有内容均折叠到左上方。我的网站无法使用!

是的,这是我的网站-IE11上的前端开发人员网站。起初,我很困惑,为什么会这样?我记得IE11支持CSS Grid,但这是Microsoft发布的旧版本。该解决方案非常简单,@supports仅用于新浏览器使用CSS Grid。

@supports (grid-area: auto) {
    body {
        display: grid;
    }
}

让我解释一下。我之所以使用grid-area,是因为从2017年3月到今天,新CSS Grid规范仅支持它。由于IE不支持@supports查询,因此整个规则将被忽略。结果,新的CSS Grid将仅用于支持的浏览器。

使用Flexbox作为CSS网格的后备

如果flexbox不适合显示项目网格,那并不意味着它对后备不利。对于不支持的浏览器,可以将flexbox用作CSS Grid的后备,我使用的工具可以做到这一点。

@mixin grid() {
  display: flex;
  flex-wrap: wrap;

  @supports (grid-area: auto) {
    display: grid;
    grid-gap: 16px 16px;
  }
}

@mixin gridAuto() {
  margin-left: -16px;

  > * {
    margin-bottom: 16px;
    margin-left: 16px;
  }

  @media (min-width: 320px) {
    > * {
      width: calc((99% / #{2}) - 16px);
      flex: 0 0 calc((99% / #{2}) - 16px);
    }
  }

  @media (min-width: 768px) {
    > * {
      width: calc((99% / #{3}) - 16px);
      flex: 0 0 calc((99% / #{3}) - 16px);
    }
  }

  @supports (grid-area: auto) {
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    margin-left: 0;

    > * {
      width: auto;
      margin-left: 0;
      margin-bottom: 0;
    }
  }
}

上面的后备代码的工作方式如下:

  1. display: flex和添加flex-wrap: wrap到wrapper元素。
  2. 检查是否支持CSS Grid,如果支持,则使用CSS Griddisplay: grid
  3. 通过使用选择器> *,我们可以选择包装器的直接子元素。选择它们后,我们可以为每个添加特定的宽度或尺寸。
  4. 当然,每一个之间的边距都是必需的,并且grid-gap在支持CSS Grid的情况下将被替换。

这是如何使用Sass mixin的示例。

.wrapper {
  @include grid();
  @include gridAuto();
}

demo

使用CSS Grid作为网站标题

本文的动机之一就是这个错误。我注意到我的好友正在使用CSS Grid来实现网站标头。

他提到了诸如“这很复杂,css网格很难...等”之类的东西。由于使用了不正确的布局方法,他发现CSS Grid很复杂。并非如此,他的所有困惑都来自将其用于不合适的东西的事实。

考虑以下我注意到的示例。

.site-header {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
}

.site-nav {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
}

CSS Grid使用了两次,第一次是用于整个标头,第二次是用于导航。他曾经使用grid-column微调元素之间的间隔以及其他我不记得的奇怪事物,但是您明白了么!

对选项卡使用CSS Grid

不正确的CSS代码如下所示:

.tabs-wrapper {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
}

从上面的代码中,我可以看到开发人员假定选项卡数仅为3。结果,他习惯于1fr 1fr 1fr布置列。如果列数更改,这很容易中断。

过度使用Flexbox或Grid

请记住,旧的布局方法可能非常适合这项工作。过度使用flexbox或Grid会随着时间增加CSS的复杂性。我并不是说它们很复杂,但是按照本文示例中的解释正确地并在正确的上下文中使用它们会更好。

例如,您有以下部分,要求将其所有内容水平居中。

可以使用来完成text-align: center。有更简单的解决方案时,为什么要使用flexbox?

结论

关于如何去选择CSS Grid布局和flexbox布局的话题已经持续了很长一段时间了,看了很多文章,觉得这篇文章真的很不错,所以就翻译了下。如果有什么问题的话,请评论区留言!