Web 开发,尤其是您可以使用 CSS 进行的开发,已经变得越来越复杂。借助 CSS Grid 的附加功能,现在可以实现看起来像手动布局的布局。让我们解决一个如何做这样的事情的实际例子。
在这篇文章中,我想谈谈 CSS 网格的惊人可能性,以及它如何允许更接近印刷设计的复杂布局。我们将要讨论的设计实际上是我为客户所做的设计(稍微修改为演示案例)。它将涵盖 CSS 网格的两个主要用例:
有一个静态网格,我们在其中为每个元素定义指定的起点和终点;
使用 CSS 网格模板区域可以轻松地重新排序简单的 HTML 布局,而无需更新 HTML。
作为奖励,我们还将涉及object-fit和aspect-ratio,它们也会派上用场。
![](https://i-blog.csdnimg.cn/blog_migrate/de935d76ad2ceab45d743a067731a085.png)
(大预览)
在这里您可以看到我们将要实现的设计:左侧是桌面版,右侧是移动版的裁剪版(假设移动视图继续第 3 和 4 节)。这里发生了很多事情,没有什么真正适合整齐的行和列。图像布置在不均匀的网格上,有时甚至重叠,我们有一些窄文本和一个编号元素,可兼作设计元素。
跳转后更多!继续往下看↓
参加关于前端和 UX的Smashing Workshop,其中包括实用知识、现场会议、视频录制和友好的问答。关于设计系统、用户体验、网络性能和 CSS/JS。与 Brad Frost、Christine Vallaure 和许多其他人一起。
手工图像布局 #
让我们先看看每个彩色组件内的图像网格元素。虽然我们有四个彩色组件,但只有两个变体会重复。为了便于比较,我将桌面版一分为二,并将两半并排放置——这样更容易比较。如您所见,第一个和第三个相同,第二个和第四个相同。如果我们只比较第一个和第二个变体,它们会有所不同,但基本构建块非常相似(全尺寸背景颜色、大图像块、带有数字的列和一些文本)。因此,我们可以认为它是同一个组件,只是有两个选择。
![](https://i-blog.csdnimg.cn/blog_migrate/46365071bb7b7a711f20f4e04c8b3ce8.png)
(大预览)
在过去,我们不得不在 Photoshop 中制作图像网格,然后将其作为一个图像添加到页面中。显然,我们仍然可以这样做,但该解决方案对于响应式网站来说从来都不是特别好,并且使用图片元素也可以,但是如果我们想更改图片,我们将不得不在 Photoshop 中进行多次布局并重做所有操作。每次为这个元素添加不同的图片时,我们都需要这样做。
但如果没有其他选择,我们就不会出现在本文的这一部分!一段时间以来,使用 CSS grid已经很安全了,只需要几行 CSS 就可以很巧妙地解决这个布局。
CSS Grid 允许我们在父元素上定义正式的网格定义——列和行,并为子元素指定它们在网格中的位置。我们还获得了 flex 提供的相同的证明和对齐功能。这消除了很多包装divs 的需要,也使 CSS 更苗条。
需要注意的一件事:因此,您的图形布局可能与 HTML 中的文档结构不同。
不过,屏幕阅读器仍将依赖 HTML 结构,因此请将最重要的信息放在首位,并尽量让所有内容保持合理的顺序。
现在让我们来看看我们的图像。我们至少需要什么?图像和图像本身的容器。你知道吗?使用 CSS Grid,这实际上就足够了——告别五层包裹div!
<divclass="grid image-grid-3-m4"><imgclass="image-0 "src=""/><imgclass="image-1 "src=""/><imgclass="image-2 "src=""/><imgclass="image-3 "src=""/></div>
复制
关于标记的更多信息。为了使样式更容易,我为每个图像添加了一个索引(因为我们想重复使用它们,它必须是一个类,而不是 ID)和周围的两个类,我们将使用它们来定义基本div样式:一个网格实用程序类和第二个用于识别变体的类。对于桌面视图中左侧三个图像和右侧第四个图像的变体,我花了一些时间思考如何最好地解决第四个图像的问题:我们是否将它与其他图像一起添加到容器中并尝试移动它到另一边,还是我们将它移动到移动设备上,等等。最后,我决定在图像容器中添加第四张图像,但通过 CSS 将其隐藏在桌面上,并有一个单独的div在具有相同图像的第二个位置,以便在桌面版本中显示。使用display:none还将从屏幕阅读器中隐藏该版本。
现在我们已经有了基本的 HTML 和我们的图像,是时候关注 CSS 了。如果您完全不熟悉 CSS 网格,那么这篇很有帮助的文章将介绍完整的语法并对其进行详细解释。不幸的是,我无法在本文中描述完整的语法。
首先,我们需要定义我们的网格。因为我有一个设计要处理,所以我使用了一种工具,它允许我在图像顶部放置线条,在图像的每个边缘放置一条线,并查看它们之间的像素尺寸。如果设计师已经使用了正式的网格并告诉我这件事,那就太好了,但不幸的是,事实并非如此,所以我使用比例尺寸作为我应该在网格中使用的近似值。基本上,我问自己每个数字的最小公倍数是多少——有一些回旋余地——并使用了它。(欢迎来到数学课。)我的目标是让所有网格列和行的大小相同,同时在列数或行数上灵活。
![](https://i-blog.csdnimg.cn/blog_migrate/c1a06b3a69b602e9ec6e24d423525391.png)
(大预览)
通过这种方法,我确定我想要在移动设备上有 14 列和 7 行加上一些统一的间隙。这使我能够近似布局中的分布,同时保持纵横比接近他们的设想。基于此,我们得到以下 CSS:
.grid{display: grid;}.image-grid-3-m4{grid-template-rows:repeat(7, 1fr);grid-template-columns:repeat(14, 1fr);gap: 0.5rem;}
复制
有了这四行 CSS,我们就有了一个可以填充的网格。如果继续,您会注意到图像现在在第一行中每个填充一个网格单元格。这是浏览器使用的自动布局机制,根据您想要执行的操作,它非常适合在几秒钟内定义一个均匀布局的设计。
请参阅Pfenya为网格 [forked] 编写的Pen Basic CSS 。
但很明显,我们想要花哨的东西,所以我们甚至没有布局。为了实现这一点,我们需要更多的 CSS 规则:grid-column准确地说grid-row。这些允许我们指定一个元素应该如何在网格中定位自己。再加上我可靠的线条和歪曲的数学,我可以放置每张图片。例如,第一张图片从左上角开始,所以我们从网格列的第 1 行和第 1 行开始,它将跨越 14 列和 4 行中的 6 列。除了告诉元素要跨越多少个单元格之外,您还可以指定结束值。就个人而言,我更喜欢跨度,因为它更容易跟踪和阅读。
.image-0{grid-column: 1 / span 6;grid-row: 1 / span 4;}
复制
除了有关图像放置位置的信息之外,还有另外三个规则在此处完成了很多非常繁重的工作:
img{object-fit:cover;height: 100%;width: 100%;}
复制
有了这些,我们告诉浏览器让图像始终跨越它们的整个容器,容器的大小由网格决定。然后我们使用object-fit来确保所有空间都被隐藏溢出的图像占用(如果您想了解更多信息object-fit,这里有一本很棒的入门书)。显然,这意味着部分图像将不会显示——在决定为此使用的图像时需要牢记这一点——尤其是当它们的纵横比不完全匹配时。
说到宽高比,右上角的图像看起来确实是正方形的。如果我们可以告诉它是方形的,不管图像本身的大小如何,这不是很整洁吗?我们现在实际上可以做到这一点。有一个名为 的 CSS 属性就是aspect-ratio这样做的,在这种情况下,它允许我们告诉图像它应该是方形的(众所周知,这是时髦的)。(不过,向后兼容性是一个问题,尤其是在 iOS 上。因此在某些用例中,您可能希望使用 polyfill。)但该aspect-ratio属性在将来会非常有用,您可以阅读更多详细信息它在 Stephanie Eckles 的这篇文章中。
所有这些都准备就绪后,我们现在可以先看看所有四张图片的外观:
参见Pfenya的Pen Untitled [forked]。
对于桌面版,我们真正想要做的就是移动图像开始和结束的位置。为此,我们需要一个重新定义网格和定位的媒体查询。我再次计算了我需要的行和列以及每个元素的位置,并将每个元素的信息添加到我的 CSS 中。
参见Pfenya的Pen Untitled [forked]。
现在我们有一个图像网格,它可以根据视口改变其布局,一旦我们将它放入一个具有灵活宽度的元素中,图像就会相应地更新它们的显示尺寸。
这里最难的事情是理解语法并掌握显式定位元素。但是一旦你这样做了,就会打开一个充满可能性的世界。显然,这不是你总能做的事情,尤其是当你有可重用的组件时,但对于特定的用例,它可以添加一些特殊的东西或解决一个困难的案例。
借助在线商店、视频和日程安排工具,无论您有什么想法,您都可以使用 Squarespace 销售任何东西。
在主要组件中移动块 #
现在我们已经完成了图像中最困难的部分,是时候看看组件本身了。再一次,我们将继续使用 CSS Grid,而这一次我们将使用grid-template-areas. 就个人而言,我非常喜欢这个功能,因为它为我们在桌面和移动设备之间的主要结构布局提供了极大的灵活性,而无需添加大量封装div或重复信息。这个组件是一个很好的展示,让我们开始吧。
如果我们再次转向设计,只有少数元素。我们有几张图片,在较大的视口中可以分为两部分:白框中的数字和所有文本元素。
![](https://i-blog.csdnimg.cn/blog_migrate/d31b8a4a07aa5ebdc2ffb47d0a339116.png)
(大预览)
最小的 HTML 是多少?同样,我们不需要很多额外的东西;一个环境div,然后每个部分一个是我们所需要的:
<divclass="container"><divclass="images"></div><divclass="numbering"></div><divclass="text"></div><divclass="single-image"></div></div>
复制
屡获殊荣的 JavaScript 组件库,具有所有必备功能 - 分页、排序、过滤、分组等等!
对于我们的示例,所有区域都有一个类名,用于标识它们稍后将保存的内容。但是,如果我们查看移动布局,数字位于图像之上!CSS 网格的妙处在于您可以对元素进行分层。我们已经将其用于上面的图像。如您所见,其中两个重叠,我们也可以对整个区域进行重叠。分层将由我们的老朋友 z-index 控制。与往常一样的规则:较高的 z-index 获胜并排在前面。
考虑到这一点,让我们创建两个区域:一个位于顶部,图像填充该区域,数字作为顶层,其中大部分透明以显示图像,第二个区域位于下方用于文本。我们可以使用之前使用的网格列和行语法,但在这种情况下,我们可以使用grid-template-areas. 有了这个,您可以为网格的各个部分添加名称,然后为每个元素决定它应该出现在哪个网格区域。特别是对于页面或组件框架,这是一种更容易和更快的工作方式,并且能够阅读它再次晚于使用所有非描述性数字。
我认为通过示例会更容易理解。
.container{display: grid;grid-template-columns: 1fr;grid-template-rows:repeat(2, 1fr);gap: 1.2rem;grid-auto-flow: row;grid-template-areas:"numerology""text";}.images{grid-area: numerology;}.numbering{grid-area: numerology;}.text{grid-area: text;}.single-image{display:none}
复制
我们再次将容器定义为网格,向其中添加两行,然后使用“grid-template-areas”为这些行命名。其语法对于 CSS 来说非常不寻常,但它为您提供了布局的迷你视图:是第一行和第二行Numerology中的单元格名称。Text
这些行现在有了名称,我们可以轻松地定位我们的元素。图像和数字容器都进入第一行,文本将进入第二行。因此,在上面的示例中,我们将 添加到我们在 HTML 中grid-area应用的类的 CSS 。div通过这几行,我们已经定义了布局。
为了实现数字的叠加效果,白框将在其容器中并获得固定的宽度和高度。然后我们可以使用flex它在容器中居中。
但是,您可能会问,我们如何从这个到桌面版本?实际上很容易!对于网站的整体设计,我们已经在桌面上为所有元素使用了一个 14 列的网格。如果我们用一些网格标记覆盖设计,我们会看到一切都应该采用的大致宽度。
![](https://i-blog.csdnimg.cn/blog_migrate/5057308179b256dc1faddf4a7205edac.png)
(大预览)
显然,我们在移动视图中命名的区域对于这个版本不会真正帮助我们,但我们可以简单地在桌面视图的媒体查询中更新它们,并定义不同的区域名称:
.container{display: grid;grid-template-columns:repeat(14,minmax(0, 1fr));grid-template-rows:repeat(2, 1fr);gap: 1.2rem;grid-auto-flow: row;grid-template-areas:"images images images images images . numbering numbering numbering single-image single-image single-image single-image single-image""images images images images images . text text text single-image single-image single-image single-image single-image";}.images{grid-area: images;}.numbering{grid-area: numbering;}.text{grid-area: text;}.single-image{grid-area: single-image;}
复制
让我第一个说,是的,这确实不是一个很好的定义方式,但不幸的是,语法template-areas不像列定义那样包含 repeat 关键字。
但是花点时间仔细看看。您可以看到,我们将前五列定义为属于images两行中的名称,然后我们有一个句点,这意味着这里没有任何内容,然后我们在第一numbering行中有三列,在text第二行中有三列,最后是 5 列single-image。就个人而言,我喜欢使用在线生成器,它允许我直观地定义这些区域并复制所需的 CSS。
现在,仅用不到 20 行代码,我们就完全改变了布局,而根本没有触及非常简单的 HTML 结构!但是 2 和 4 的替代版本呢?它们只使用了稍微不同的布局,那么为什么不为容器添加一些类.version-a并.version-b在grid-template-areas桌面上定义这些类呢?就这么简单。请看以下内容:
.version-1{grid-template-areas:"images images images images images . numbering numbering numbering single-image single-image single-image single-image single-image""images images images images images . text text text single-image single-image single-image single-image single-image";}.version-1 .single-image{grid-area: single-image;display:block;}.version-2{grid-template-areas:". numbering numbering numbering . . images images images images images images images images"". text text text . . images images images images images images images images";}
复制
老实说,对我来说,这仍然很疯狂。在最长的时间里,像这样的布局完全无法实现或制作起来非常复杂,并且在版本 1 和版本 2 之间共享 HTML 几乎是不可能的,至少对于完整的 HTML 来说是这样。现在我们可以挥动魔杖并更新它应该出现的位置。非常令人兴奋的东西。
这对我有很大帮助的另一个实际示例是为电子商务网站上的产品详细信息页面定义区域。能够将元素移动到它们在不同上下文中有意义的位置是令人惊奇的,但这也意味着您需要稍微调整您的思维模型以适应 HTML 和 CSS 的连接方式。而这甚至仅仅是个开始。有了容器查询和层,地平线上的许多东西将在未来开辟更多的可能性,我完全为此而来!
![](https://i-blog.csdnimg.cn/blog_migrate/c551ec0bc4333c29607b786efb18ba04.png)