CSS Flexbox vs CSS Grid

7,536 阅读16分钟

CSS Flexbox vs CSS Grid

CSS是一项非常重要的Web开发技术。很长一段时间以来,我们使用常见的CSS属性来布置HTML元素。这些属性包括浮动、inline-block和位置样式。近年来,我们看到了许多现代的CSS技术,使创建动态的HTML布局变得更加容易。

其中一些强大的技术包括CSS网格和CSS Flexbox。它们以一种令人难以置信的简单方式改变了我们布局HTML元素的方式。

当我们谈论Flexbox和Grid布局时,我们理解容器和项目的概念。在这种情况下,容器是一个HTML块,可以包含其他HTML元素。项目是一个可以放在容器内的HTML元素。

这里有一个简单的例子,展示了HTML容器内的HTML项目。

<div>
    <div>One</div>
    <div>Two Two</div>
    <div>Three Three Three</div>
    <div>Four Four Four Four</div>
    <div>Five Five Five Five Five</div>
</div>

在这个例子中,最外层的div 是一个容器元素,其他divs 是容器项目。

本指南将讨论Grid和Flexbox布局之间的区别和关系。

什么是CSS Flexbox

Flexbox是CSS3中的一种布局模式。它是一种更熟练的设计、对齐和传播容器中项目之间空间的方法,以控制其排列。

通过Flexbox,我们可以从左到右、从右到左、从上到下或从下到上排列项目,同时控制容器中项目的间距、对齐方式和顺序。

什么是CSS网格

CSS网格是一个样式集合,允许你根据行和列来控制页面布局。在一个网格系统中,包含元素被用来定义布局中的一行。

然后,你将类属性应用于项目元素,然后将它们跨越所需的列数。这允许你创建更复杂的嵌套式布局。

CSS网格与CSS Flexbox

让我们来看看这两种布局的一些共同区别。

一维与二维

Flexbox以一维布局的方式排列项目。这可以是行,也可以是列。

image

图片来源

Flexbox布局最适合在水平或垂直方向上排列项目。它是一维的,只能适合一行或一列。

image 2

image 3

一个完美的单维布局的例子是标题导航栏或页脚。

让我们来看看如何使用Flexbox实现一个页眉导航菜单。

<div class="nav">
    <div>HOME</div>
    <div>ABOUT</div>
    <div>CONTACT</div>
    <div>SIGN UP</div>
    <div>SIGN IN</div>
</div>

用一些CSS来设计页眉。

.nav {
    display: flex;
    background: seagreen;
    height: 50px;
    align-items: center;
    gap: 10px;
}

.nav div {
    color: whitesmoke;
    margin-left: 20px;
}

flex image

大多数常见的页眉布局都是朝一个方向布局的,由于Flexbox的一维功能,使用它就更容易了。

另一方面,网格是一个二维的布局,这意味着你可以在行和列中布局项目。

image grid

一个基本的二维布局的例子。

<div class="container">
    <div class="item item1"></div>
    <div class="item item2"></div>
    <div class="item item3"></div>
    <div class="item item4"></div>
    <div class="item item5"></div>
    <div class="item item6"></div>
</div>
.container {
    display: grid;
    grid-template-columns: 150px 150px 150px;
    grid-gap: 1rem;
    grid-template-rows: 150px 150px;
}

.item {
    background-color: #1EAAFC;
    color: #fff;
    border: 6px solid #171717;
}

grid example

我们用display: grid 指定一个网格,然后用grid-template-columnsgrid-template-rows 确定行和列。这就定义了一个二维布局。在这种情况下,每一列和每一行的大小都是150px

内容与布局

Flexbox是基于内容的,所以内容是第一位的。所谓内容优先,我们的意思是,它可以帮助你对齐内容,并在容器中移动块和项目。

另一方面,CSS网格的重点是布局页面的外部/骨架布局。

为了理解内容与布局的概念,让我们回到上面讨论的标题导航栏设计。我们可以针对页眉(容器)内的一个项目,决定在哪里显示它。

为了得到核心区别,假设我们想把Sign InSign Up 菜单移到左边,我们可以用Flexbox和CSS Grid来做。

使用Flexbox。

.nav {
    display: flex;
    background: seagreen;
    height: 50px;
    align-items: center;
    gap: 1px;
}

.nav div {
    margin-left: 20px;
    margin-right: 20px;
    color: whitesmoke;
}

div:nth-child(4) {
    margin-left: auto;
}

Flex Content First

我们指定容器的一个子项(第n个子项(4)并确定其位置)。这就是我们所说的Flexbox是基于内容的。

另一方面,我们也可以用CSS Grid实现同样的效果。页眉是一维的,Flexbox在这方面更胜一筹,但我们将通过一个使用CSS Grid的例子来区分布局和内容。

.nav {
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    background: seagreen;
    height: 50px;
    align-items: center;
    gap: 1px;
}

.nav div {
    margin-left: 20px;
    margin-right: 20px;
    color: whitesmoke;
}

而结果看起来也是差不多的。

header nav

但请注意,我们指定了十列,每列占用一个单位的一小部分。为了推动这一点,让我们看看网格布局在内部是如何工作的。

使用网络浏览器来检查父级div 元素。

grid header

这真是太棒了。我们可以看到网格被分成了十个单元。这就是首先应用布局概念的地方。首先,我们定义布局,然后将项目固定到网格单元中。

如果我们要把项目Sign InSign Up 移到左边,应用margin-left: auto ,就像我们在Flexbox例子中做的那样,就不会成功。我们可以用CSS Grid这样做。

.nav {
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    background: seagreen;
    height: 50px;
    align-items: center;
    gap: 1px;

}

.nav div {
    margin-left: 20px;
    margin-right: 20px;
    color: whitesmoke;
}

div:nth-child(4) {
    grid-column: 9;
    color: rgb(64, 35, 97);
}

div:nth-child(5) {
    grid-column: 10;
    color: rgb(64, 35, 97);
}

nav layout

该布局有十列。要把这些项目移到左边,先指定你想显示内容的单元格(布局先)。

layout

这些简单的例子解释了内容和布局优先的概念。

间隙属性

通常情况下,你会包含一个margin属性来在项目周围创建空隙。

CSS Grid和CSS Flexbox之间的结构性差异之一是,你只在使用Grid布局的项目周围创建间隙。

好消息是,CSS增加了一些功能,支持在项目周围实现缝隙,这些功能称为间隙属性。两种布局都支持这个属性。

它可以让你控制容器内项目周围的空间,在列和行之间。

让我们来看看我们如何实现这个。

这里,我在一个Flexbox容器内有九个项目。

<div class="gap">
    <div>A</div>
    <div>B</div>
    <div>C</div>
    <div>D</div>
    <div>E</div>
    <div>F</div>
    <div>G</div>
    <div>H</div>
    <div>I</div>
</div>
.gap {
    display: flex;
    flex-wrap: wrap;
}

.gap>div {
    background-color: rgba(10, 129, 209, .5);
    border: 1px solid #000;
    color: #000;
    padding: 20px;
    font-size: 150%;
}

gap

使用margin来创建项目周围的沟槽。

.gap {
    display: flex;
    border: 3px solid rgba(6, 109, 243, 0.911);
    flex-wrap: wrap;
    max-width: 800px;
}

.gap>div {
    background-color: rgba(10, 129, 209, .5);
    border: 1px solid #000;
    color: #000;
    padding: 20px;
    font-size: 150%;
    margin: 6px;
}

gap margin

wrapped margin

当我引入margin of 6px ,注意项目周围的空间是如何创建的。margin创造了一些额外的白色空间,使用gap属性可以避免。

间隙属性明显地创建了沟槽。你可以选择在行和列之间创建空格。

通过指定column-gap ,应用间隙。

.gap {
    display: flex;
    border: 3px solid rgba(6, 109, 243, 0.911);
    flex-wrap: wrap;
    column-gap: 6px;
    max-width: 800px;
}

.gap>div {
    background-color: rgba(10, 129, 209, .5);
    border: 1px solid #000;
    color: #000;
    padding: 20px;
    font-size: 150%;
}

column gap

gap column

当我们应用wrap时,我们强制Flexbox在小屏幕上创建行和列。我们也可以使用row-gap ,在它们周围创建沟槽。

.gap {
    display: flex;
    border: 3px solid rgba(6, 109, 243, 0.911);
    flex-wrap: wrap;
    column-gap: 6px;
    row-gap: 6px;
    max-width: 800px;
}

.gap>div {
    background-color: rgba(10, 129, 209, .5);
    border: 1px solid #000;
    color: #000;
    padding: 20px;
    font-size: 150%;
}

row gap

简称

为了创建行和列之间的间距,我们可以使用间隙并指定两者的单位。

例如,gap: 6px 6px ,我们将得到与应用column-gap: 6pxrow-gap: 6px 相同的结果。

注意,在使用间隙属性时,你可以混合使用像素和百分比的值。你不必坚持使用单一单位。例如,6px 6%,6px 6rem6% 6rem

当使用网格时,你会使用grid-gapgrid-gap 已被废弃,我们有一个gap 属性,在两种布局上都适用。

注意这不是两者之间的区别。以前只有Grid支持间隙的时候是这样的。由于这是一个最新的更新,你可能会发现一个教程说明间隙是一个属性的区别。

包裹

包裹是一个用于包裹容器内的项目的属性。当你希望项目适合容器的可用空间时,它就会被应用。

这是解决一些问题所需的常见属性之一,比如子元素不在容器元素内停留。

包裹允许我们在当前内容列中没有足够的空间容纳元素时,将其包裹到下一行。

这两种布局都采用了包覆的概念。它们处理包覆的方式不同。

下面是一个例子。

我们正在检查根据我们容器中的可用空间大小来拉伸和收缩项目的能力。

下面是一个使用Flexbox布局的非常基本的包覆例子。

<div class="row-flex">
    <div>1 2 3 4 5 6 7 8 9 0</div>
    <div>1 2 3 4 5 6 7 8 9 0</div>
    <div>1 2 3 4 5 6 7 8 9 0</div>
    <div>1 2 3 4 5 6 7 8 9 0</div>
    <div>1 2 3 4 5 6 7 8 9 0</div>
    <div>1 2 3 4 5 6 7 8 9 0</div>
    <div>1 2 3 4 5 6 7 8 9 0</div>
    <div>1 2 3 4 5 6 7 8 9 0</div>
    <div>1 2 3 4 5 6 7 8 9 0</div>
    <div>1 2 3 4 5 6 7 8 9 0</div>
</div>
.row-flex {
    display: flex;
}

当你调整屏幕大小到600px以下时,并不是每个项目都是可见的--这就是wrap的概念的作用。在容器内指定wrap属性,就可以解决这个问题。

.row-flex {
    display: flex;
    flex-wrap: wrap;
}

我们正在使用容器内的wrap来将Flexbox项目包裹到可用的容器大小。

差异

下面是一个Flexbox和Grid布局的例子。

<h1>Flexbox</h1>
<div class="flex">
    <div>One</div>
    <div>Two Two</div>
    <div>Three Three Three</div>
    <div>Four Four Four Four</div>
    <div>Five Five Five Five Five</div>
</div>

<h1>Grid</h1>
<div class="grid">
    <div>One</div>
    <div>Two Two</div>
    <div>Three Three Three</div>
    <div>Four Four Four Four</div>
    <div>Five Five Five Five Five</div>
</div>

用一些CSS来设计容器和项目的样式。

/* Flexbox row styles */
.flex {
    margin-bottom: 2em;
    border: 3px solid #000;
    display: flex;
    flex-wrap: wrap;
    gap: 2px 2px;
    max-width: 700px;
}

.flex>div {
    background-color: rgba(130, 184, 219, 0.5);
    border: 2px solid rgb(104, 182, 235);
    color: #000;
    padding: 20px;
    font-size: 150%;
    flex: 1 1 250px;
}

/* Grid row styles */
.grid {
    max-width: 700px;
    border: 3px solid #000;
    background-color: #fff;
    color: #444;
    gap: 2px 2px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}

.grid>div {
    background-color: rgba(170, 132, 167, 0.5);
    border: 2px solid rgb(239, 189, 235);
    color: #000;
    padding: 20px;
    font-size: 150%;
}

flex grid

对容器应用wrap属性,因为它是这些项目的包含元素。它将控制这些项目的包裹性。

让我们来做这个。

当我们应用wrap属性时,CSS的样式应该是这样的。

/* Flexbox row styles */
.flex {
    margin-bottom: 2em;
    border: 3px solid #000;
    display: flex;
    flex-wrap: wrap;
    gap: 2px 2px;
    max-width: 700px;
}

.flex>div {
    background-color: rgba(130, 184, 219, 0.5);
    border: 2px solid rgb(104, 182, 235);
    color: #000;
    padding: 20px;
    font-size: 150%;
    flex: 1 1 250px;
}

/* Grid row styles */
.grid {
    max-width: 700px;
    border: 3px solid #000;
    background-color: #fff;
    color: #444;
    gap: 2px 2px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}

.grid>div {
    background-color: rgba(170, 132, 167, 0.5);
    border: 2px solid rgb(239, 189, 235);
    color: #000;
    padding: 20px;
    font-size: 150%;
}

flexible-wrapped

对于Flexbox布局,我们正在应用。

  • flex-wrap: wrap 将项目推入行或列。
  • flex: 1 1 250px 给项目一个250的宽度,并允许它们随着屏幕尺寸的缩小而增长和缩小。

在Grid的情况下。

  • grid-template-columns 创建列。
  • minmax() 给每个项目一个250px的宽度的函数。
  • repeat() 函数将列重复包装成行和列。

观察到的情况是: 灵活的布局失去了它的背景。如果你看一下第5项,当应用包覆时,它就失去了它的上下文。包裹试图挤压项目以填补可用空间。另外,当被推倒时,第5项与其他项目的大小不一样。

这是因为Flexbox是一维的,它将项目排列成行或列。Wrap迫使Flexbox形成行和列,使Flexbox失去了一维的背景。

你可以说网格只是一个网格。项目不会失去其网格背景。它们的大小都是一样的,都落在网格线里。它并没有失去作为一个网格的上下文。

这与网格布局是二维的有关,这很适合有行和列的布局。在我们的例子中,网格包装已经将项目强制到了行和列中,并没有失去它的二维背景。

在应用方面,当你想在保持宽度不变的情况下推送项目时,网格包覆的概念效果最好。一个很好的例子是我们在网页设计中使用的图片部分(本指南后面有解释)。

image section

Flexbox包装的一个公平的使用案例是这个订阅表,当你把项目推送到不同的屏幕尺寸时,这些项目不一定要有相同的尺寸。

<div class="subscribe-container">
    <form>
        <input type="email" placeholder="Email Address">
        <input type="text" placeholder="Name">
        <input class="subscribe-button" type="submit" value="Subscribe">
    </form>
</div>
.subscribe-container {
    max-width: 800px;
    margin: 60px auto;
    background-color: rgba(130, 184, 219, 0.5);
    border: 5px solid rgb(98, 143, 228);
}

.subscribe-container form {
    display: flex;
    flex-wrap: wrap;
}

.subscribe-container form input {
    margin: 15px;
    border: 1px solid rgb(98, 143, 228);
    padding: 0.4rem;
}

.subscribe-container form input {
    flex: 1 1 200px;
}

.subscribe-container form input[type="submit"] {
    border-radius: 3px;
    background-color: rgba(17, 228, 10, 0.5);
    color: rgb(98, 143, 228);
}

.subscribe-container form input[type="email"] {
    flex: 1 1 250px;
}

subscribe-form

在这种情况下,当容器在不同的屏幕尺寸上展开或缩小时,每个项目都会尽可能地占用空间。

subscribe

Flexbox布局和网格布局

关于这两者最常见的一些问题包括。

  • CSS Grid是否取代了CSS Flexbox?它比CSS Flexbox更好吗?
  • 我应该使用CSS Grid而不是CSS Flexbox,还是使用CSS Flexbox而不是CSS Grid?
  • 什么时候应该使用其中之一?
  • 哪个是设计网页布局的最佳选择?

每种布局都有其优势。它们的工作方式都不同。最好和最简单的方法是将这两种布局结合起来,以一种突出的方式产生复杂、简单的设计。

让我们来说明一下CSS网格可以在什么地方实现,与CSS Flexbox一起工作,创造出令人敬畏的东西。

content-alignment

上面是一个网页设计表现的例子。通过实施,该设计是用网格布局完成的。看看用来实现的代码

在实施过程中,有些情况下需要你使用Flexbox布局,如页眉和页脚。

当设计实现后,我们可以表示这个例子的内容和设计。

web-design

继续查看用于实现上述设计的代码

主要的布局骨架是用CSS网格制作的,正如使用网页浏览器检查器工具所预览的那样。

under-the-hood

.container {
    max-width: 1250px;
    margin: 0 auto;
    padding: 0 60px;
    display: grid;
    grid-template-columns: 0.4fr 0.3fr 0.3fr;
    grid-column-gap: 10px;
    grid-row-gap: 15px;
    background-color: #fff;
}

让我们来分解一下这个网页。

正如我们所说,该布局及其内容融合了CSS网格和CSS Flexbox属性。

页首由一个导航菜单和一个标志组成。它们在一个方向上对齐,因此Flexbox布局将完美地处理其对齐。

<div class="header">
    <p class="logo"><a href="#"><i class="fa fa-home" aria-hidden="false"></i></a></p>
    <nav>
        <ul>
            <li><a href="#">HOME</a></li>
            <li><a href="#">ABOUT</a></li>
            <li><a href="#">Contact</a></li>
            <li><a href="#">SIGN UP</a></li>
            <li><a href="#">SIGN IN</a></li>
        </ul>
    </nav>
</div>

在这种情况下,页眉是在CSS网格内实施Flexbox的完美例子。

.header {
    grid-column: 1 / 4;
    grid-row: 1 / 2;
    text-transform: uppercase;
    border-bottom: 2px solid #b0e0ea;
    padding: 20px 0;
    display: flex;
    gap: 5px;
    align-items: center;
}

header-content

同样,导航菜单也能很好地适应Flexbox布局。

.header nav ul {
    display: flex;
    list-style-type: none;
}

nav-header-content

另一个拥抱一维灵活性的案例是额外内容部分。

<div class="extra">
    <div class="content-block-info">
        <h3>View Grid Help</h3>
        <p>See tips and tricks for CSS Grid Layouts...</p>
        <button>Read</button>
    </div>

    <div class="content-block-info">
        <h3>View Flexbox Help</h3>
        <p>See tips and tricks for Flexbox layouts...</p>
        <button>Read</button>
    </div>

    <div class="content-block-info">
        <h3>View Combined Help</h3>
        <p>See tips and tricks for combined layouts...</p>
        <button>Read</button>
    </div>
</div>
.extra {
    grid-column: 2 / 4;
    grid-row: 4 / 5;
    padding: 1rem;
    display: flex;
    flex-wrap: wrap;
    border: 1px solid #ececec;
    justify-content: space-between;
}

extra-content

每个content-block-info ,都是垂直排列的;因此,一维布局适合其设计。

为了包装这个插图,图片部分由图片组成。用Flexbox布局可以实现这一点,通过包装图像来适应布局的大小。

但是用网格布局,图像在二维布局上就可以正常工作。

.related-images {
    grid-column: 1 / 3;
    grid-row: 5 / 6;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-gap: 1rem;
}

images-section

CSS网格和Flexbox布局可以做很多事情。但在某些方面,CSS Grid更好、更方便,而在其他方面,Flexbox则更方便,是正确的选择。

结论

何时应考虑使用Flexbox

  • 当你需要小规模的布局时,它是实现页眉和页脚等项目较少的布局的理想选择。

  • 如果你考虑将你的内容向一个方向对齐,那么Flexbox是理想的选择。它允许我们创建一个Flexbox容器,并确定其方向,无论是水平还是垂直。这将有助于将你的内容均匀地分布在一个方向上。

  • 当你考虑内容优先的情况下,Flexbox将是一个完美的选择。

何时考虑网格

  • 具有多行和多列的较大规模的布局是二维的。CSS网格将帮助你进行复杂的设计,就像我们在上面的网页设计中使用的那样,因为它能够支持多方向的设计。它使你能够设计出你的布局和组件的大画面。

  • 当你的布局的设计是选择安排你的容器中的项目时,CSS网格将是操纵你的布局设计的理想选择。

最好的选择是结合两种布局。Flexbox容器可以用在Grid容器里面,反之则不行。在设计网页时,采用在网格容器内使用Flexbox布局的做法,使你的内容向正确的方向移动。

我更喜欢将Flexbox用于特定的布局,而将CSS Grid用于一般或整体设计。与其说我在选择上有偏差,不如说我一般在更需要它们的地方同时使用它们。它们都有不同的使用情况,我使用更适合手头工作的那一种。