CSS网格如何改变内容结构

至少做了一些网站开发工作的人都知道<div>标签是控制布局的重要组成部分。

HTML5引入了新的语义元素来帮助实现这一目标。 尽管它们是该语言的绝佳补充,但它们有点像用<div>元素装饰我们的汤。



随着CSS Grid的问世,我们不再需要依赖<div>元素来创建页面结构甚至更复杂的组件。 从字面上看,结构是由父元素确定的,而不是由内容在其中的位置确定的。

这意味着我们可以得到一个很好的简单布局,该布局可以对内容进行结构化,而无需注意最初使用<div>元素进行组织的方式。



CSS Grid可能很复杂,但是Flexbox也是如此


我听说许多人抱怨网格太复杂,而Flexbox却做同样的事情。 我要说的是,他们只是习惯使用Flexbox,因此不希望了解有关CSS Grid的更多信息。

CSS Grid技术确实引入了许多新的属性和值,所以是的,这是一条学习曲线。 但是Flexbox也相当复杂。

您能谈谈使用flex-basis属性代替width的好处吗? 或者,如果我们没有明确定义Flexbox,Flexbox如何计算flex元素的宽度?

例如,如果将下面的示例显示给从未使用过Flexbox的用户,您将如何解释两组列都具有相同布局和样式的事实? 更糟的是,两种情况下的第二列都是50%宽。 显然,宽度为50%实际上不会将元素大小设置为50%。


“好吧,这一切都始于容器中没有足够空间的情况下元素被压缩的事实,因此,即使我们将元素宽度设置为50%,也没有足够的空间,所以它开始压缩以挤压到容器中,因为另一个<div>需要更多空间。 50%可能是该块的理想尺寸,而不是实际尺寸。”

“因此,在上面的示例中,第一个块的内容太大,以至于产生了问题,因为默认情况下,作为flex元素,它倾向于收缩以容纳该内容。 在此示例中,此元素具有很多内容,因此...

所以,是的,flexbox很棒,并且在创建布局方面做得很好,但是请不要告诉我这很简单。 当您从理想的示例转到工作任务时,这种行为往往远非凭直觉就能理解的,而且有时可能很奇怪。

网格很复杂,因为它需要许多新的属性和值,但是与flexbox相比,它们为我们提供了更多的控制权。

在本文中,我想考虑一下这种附加的控制级别如何帮助简化我们的标记并允许我们编写更少的代码,而所有这些甚至都无需学习如何使用其许多奇怪的功能。

Flexbox的局限性


即使我们采用一个简单的组件并使用flexbox创建它,由于它仅在1维上起作用(flex元素既可以是行也可以是列,它们不能同时是两者),所以我们有很多东西用于创建行的元素数,然后可以将其划分为列。

例如,如果我们正在处理这样的卡片:



这不是一个复杂的布局,但是我们仍然需要以一种非常特定的方式来组织我们的内容以使其正常工作。



在这种情况下,需要黄色和橙色块,以便在添加.card元素的display:flex属性(红色块)时,将创建两列。 因此,要构造所有内容,我们将获得如下所示的标记:

 <div class="card"> <div class="profile-sidebar"> <!--       --> </div> <div class="profile-body"> <!-- , ,  --> </div> </div> 

一旦了解了Flexbox的工作原理,就很容易理解这种结构。

当为.card元素添加display: flex属性时,我们得到两列,之后我们需要分别对它们进行样式化。

这是所有样式的工作示例:


事实是,当我们创建内容列时,我们得到了稍微复杂一些的标记,并且我们也限制了自己,因为我们迫使内容的不同部分组合在一起。

使用CSS Grid简化一切


由于CSS Grid是二维的,因此它允许我们同时创建行和列,这意味着网格容器(我们将display: grid设置为display: grid属性)可以完全控制内部布局。

以前,这需要其他元素,如上面的Flexbox示例中所示。 使用网格,我们可以完全摆脱它们。

 <div class="card"> <img src="https://i.pravatar.cc/125?image=3" alt="" class="profile-img"> <ul class="social-list"> ... </ul> <h2 class="profile-name">Ramsey Harper</h2> <p class="profile-position">Graphic Designer</p> <p class="profile-info">Lorem ipsum ...</p> </div> 

从标记的角度来看,这更有意义吗?

.card类中有一个元素,我们在其中放置了直接内容。 我们不必担心元素的结构和布局,只需放置所需的内容并继续前进。

布局布局


就像使用Flexbox一样,我们仍然需要对布局进行结构化,尽管由于Grid的特性,它看起来有些不同。

在这种情况下,人们可以说网格更加复杂,但实际上,我只是在每段内容周围绘制了块。



使用Flexbox,我们创建了两个突出显示为列的块。 相反,当使用网格时,我们为父元素配置整个网格,然后向子元素指示该网格上的位置。

要设置网格,我们可以执行以下操作:

 .card { display: grid; grid-template-columns: 1fr 3fr; } 

fr度量单位是网格所独有的,它指示可用空间的比例。 这种用法非常类似于在Flexbox中安装两列并确定其宽度分别为25%和75%。

将项目放置在网格上


也许由于多年以来我一直使用float来创建标记这一事实,现在元素仅位于所需位置的情况似乎没有什么魔力。

您可以为每个元素使用grid-rowgrid-column来将它们精确地放置在我们想要的位置,但是我使用Grid越多,我越爱上grid-template-areas属性并使用区域定义放置元素。

这种方法花费更多时间,但是值得,特别是当我们创建自适应设计时(我们将很快实现)。

首先,我们需要为.card元素定义grid-template-areas .card ,然后可以将所有子元素分配给这些区域:

 .card { ... display: grid; grid-template-columns: 1fr 3fr; grid-column-gap: 2em; grid-template-areas: "image name" "image position" "social description"; } .profile-name { grid-area: name; } .profile-position { grid-area: position; } .profile-info { grid-area: description; } .profile-img { grid-area: image; } .social-list { grid-area: social; } 

在下面的示例中,您可以看到所有这些操作:


就这么简单


我喜欢使用grid-template-areas的原因grid-template-areas是,如果其他人查看了代码,他们将立即了解正在发生的事情...

如果有人向您显示使用数字和span指定grid-rowgrid-column的代码,则计算和了解它们将在何处以及如何定位元素非常简单。 对于简单的布局或在某些地方使用跨度,我认为它们的使用是适当的, 但更令人愉悦的是,仅查看父元素的代码,立即了解整个布局将是什么样

使用网格时,更容易知道元素的实际大小。


在我们的第一个示例中,我们将其中一个flex元素的宽度设置为50%,实际上,该宽度不等于50%。 如果您了解发生这种情况的原因,那太好了,但有时仍然会很烦人。 这很容易解决,但是当使用网格时,它成为一个小得多的问题。

由于我们定义了整个布局,因此我们也精确指定了应该占用多少空间元素。

当然,我们可以使用minmax()函数和度量单位fr ,它们会激起一点水,因为它们使我们可以更灵活地定义大小(例如上面示例中使用的大小),但是即使那样我们仍然可以完全控制在灵活性方面,所有这些都由父级控制,而无需为父级设置某些属性,而为子级设置一些属性。

有限的变更


如果我们看一下Flexbox示例,那么不更改HTML标记就无法使其看起来像下面的布局:



我们只限于使用<div>将元素分组在一起的方式。 我们不得不使用这些<div>来使布局生效,但是现在它已成为我们的障碍。

由于我们的网格容器的子级位于同一级别,因此您可以做任何事情 。 另外,由于我们使用grid-template-areas配置了所有内容,因此进行这些更改非常容易。

 .card { /*   grid-template-areas: "image name" "image position" "social description"; */ /*   */ grid-template-areas: "image name" "image position" "image social" ". description"; } 

通过这种方式使用grid-template-areas ,您可以快速轻松地将社交网络的图标移动到我们希望看到它们的位置(最后一部分中的点表示一个空单元格)。

使用媒体查询时,使工作变得更轻松。


正如我多次提到的,使用grid-template-areas 。 我们只能使用父级的属性来完全控制布局:

 .card { /*     */ display: grid; grid-template-columns: 1fr 3fr; grid-column-gap: 2em; grid-template-areas: "name" "image" "social" "position" "description"; } .profile-name { grid-area: name;} .profile-position { grid-area: position; } .profile-info { grid-area: description; } .profile-img { grid-area: image; } .social-list { grid-area: social; } /*      */ @media (min-width: 600px) { .card { text-align: left; grid-template-columns: 1fr 3fr; grid-template-areas: "image name" "image position" "social description"; } .profile-name::after { margin-left: 0; } } 

下面的CodePen包含一个完整样式的示例。 您可以研究它,使用网格区域,看看完全重建布局有多么容易。


Flexbox仍然有自己的范围


我越来越多地使用Grid,但是我认为Flexbox仍然有自己的范围。 如果我的徽标和导航彼此相邻放置,那么很高兴有一种简单的方法来执行类似的操作,并且知道它们将是我想要的位置:

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

这同样适用于我们用于导航的<ul> ,只是为了使元素彼此跟随,或者,正如您在带有所检查卡片的示例中所看到的,它非常适合.social-list

对于不需要复杂布局的简单组件,这确实很好。 但是越来越多的时候,我注意到向Grid的发展,有时是因为对它们的明显需求,有时是因为我想使用minmax()函数或度量单位fr

但最后,我认为Grid最好的事情是能够大大简化我们的标记。

我们仍然被迫使用<div> ,但是由于有了Grid,我们可以越来越少地使用它们。

总结


无论Flexbox多么出色,它都不比Grid简单。 在某些情况下,它确实可以很好地工作,但是当使用更复杂的布局时,网格可以使我们拥有更多的控制权。 在更改媒体查询时,在使用响应式设计时,将增强此控件。

使用Flexbox时,最大的变化就是flex-direction 。 使用网格,我们可以快速简单地完全更改组件的设计。

Flexbox和Grid都具有更多功能。 每种都有自己的目的,但是如果您觉得自己不知道采用哪种方法,或者总体上想理解响应式设计,我最近在Scrimba宣布了一门课程,涉及响应式设计问题,称为响应式Web设计Bootcamp。

Source: https://habr.com/ru/post/zh-CN471396/


All Articles