使用 Flexbox 实现自适应照片布局

Avatar of Tim Van Damme
Tim Van Damme

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

让我们来看一下一种超轻量级的方法,用于为一组任意大小的照片创建水平砌体效果。将任何一组照片放入其中,它们将无缝地排列在一起,没有任何间隙。

该解决方案不仅轻量级,而且非常简单。我们将使用一个无序图像列表和仅 17 行 CSS 代码,其中flexboxobject-fit 是主要的实现者。

为什么?

我有两个爱好:用照片记录我的生活,以及想出有趣的方法来组合 CSS 属性,包括旧的和新的。

几周前,我参加了XOXO 并拍摄了大量照片,最终缩减到了一套不错的 39 张照片。由于想要拥有我的内容,在过去的几年里,我一直考虑建立一个简单的照片博客,但从未能够实现我心目中的布局:一个简单的砌体布局,照片在尊重其纵横比的同时填充行(想想 iOS 上的 Photos.app、Google Photos、Flickr……)。

我做了一些研究,看看是否有任何轻量级、无 JavaScript 的选项,但找不到任何适合我需求的选项。在遇到一些航班延误后,我开始尝试一些代码,限制自己尽可能地保持简单(因为这是我乐趣的定义)。

基本标记

由于我基本上是在创建一个图像列表,所以我选择了无序列表

<ul>
  <li>
    <img>
  </li>
  <!-- ... -->
  <li>
    <img>
  </li>
</ul>

向 Flexbox 致敬

然后出现了一连串的灵光乍现时刻

  • Flexbox 非常适合通过根据单元格内容确定单元格宽度来填充行。
  • 这意味着所有图片(横向或纵向)都需要具有相同的高度。
  • 我可以使用object-fit: cover; 来确保图片填充单元格。

理论上,这听起来像是一个可靠的计划,并且让我得到了一个我大约 90% 满意结果。

ul {
  display: flex;
  flex-wrap: wrap;
}

li {
  height: 40vh;
  flex-grow: 1;
}

img {
  max-height: 100%;
  min-width: 100%;
  object-fit: cover;
  vertical-align: bottom;
}

注意:40vh 似乎是桌面浏览器最佳的初始方法,它以合理的大小显示两行完整的图片,并暗示下方还有更多。这也允许每行显示更多图片,从而显著改善纵横比。

最后一行拉伸

我遇到的唯一问题是 Flexbox 非常希望填充所有行,并且它对最后一行图片的纵横比做了一些愚蠢的事情。这可能是我对这个布局最不喜欢的一点,但我不得不将一个空的<li> 元素添加到列表的末尾。

<ul>
  <li>
    <img>
  </li>
  <!-- ... -->
  <li>
    <img>
  </li>
  <li></li>
</ul>

结合这段 CSS 代码

li:last-child {
  flex-grow: 10;
}

注意:此处使用“10”没有科学依据。在我的所有测试中,这提供了最佳结果。

演示

查看 CodePen 上 Tim Van Damme (@maxvoltar) 编写的作品
自适应照片布局

CodePen 上。

视口优化

在处理不同的视口方向时,需要牢记一些注意事项。

纵向

如果您的视口高度大于宽度,则此方法会限制每行的图片数量,从而弄乱其纵横比。要解决此问题,您可以使用此简单的媒体查询使图片行变矮

@media (max-aspect-ratio: 1/1) {
  li {
    height: 30vh;
  }
}

短屏幕

为了帮助横向的小型设备,增加图片的高度有助于尽可能地看到它们

@media (max-height: 480px) {
  li {
    height: 80vh;
  }
}

较小的屏幕 + 纵向

大多数手机的宽度不足以允许 Flexbox 正确执行其工作,而不会使图片缩小,因此在这里我选择不尝试每行显示多张图片。但是,仍然值得在此处设置最大高度,这样您至少可以了解列表中下一张图片的提示。

@media (max-aspect-ratio: 1/1) and (max-width: 480px) {
  ul {
    flex-direction: row;
  }

  li {
    height: auto;
    width: 100%;
  }

  img {
    width: 100%;
    max-height: 75vh;
    min-width: 0;
  }
}

就是这样!

这种方法没有完全尊重图片的纵横比(但很接近),并且偶尔会导致一些奇怪的结果,但我绝对喜欢它的简洁性和灵活性。想要让您的画廊水平滚动而不是垂直滚动?只需进行一些调整即可实现。画廊中有 1000 张图片还是只有一张?它们看起来都会很好。对纵横比不确定?Flexbox 是您的最佳选择。如果您还没有,请再次查看演示,并告诉我您的想法!

额外内容

根据这些照片的大小,这样的页面可能会很快增长到几兆字节。在我的博客中,我添加了loading="lazy" 来解决这个问题。在图片上设置了该属性后,它只会在您滚动时接近它们时加载。目前仅在 Chrome 中受支持,但您可以自己实现更受支持的技术。