纯 CSS 砌体布局

新手上路,请多包涵

我需要实施砌体布局。但是,出于多种原因,我不想使用 JavaScript 来完成它。

由多列不同高度的矩形组成的网格。

参数:

  • 所有元素具有相同的宽度
  • 元素具有服务器端无法计算的高度(图像加上不同数量的文本)
  • 如果必须的话,我可以接受固定数量的列

有一个适用于现代浏览器的简单解决方案, column-count 属性。

该解决方案的问题在于元素按列排序:

从最左上方的方框开始,它们的编号从 1 到 4 一直向下,下一列中最上方的方框是 5,依此类推。

虽然我需要按行对元素进行排序,但至少大致如下:

从最左边的盒子开始,它们的编号从 1 到 6 一直横跨,但是因为盒子 5 是最短的,所以它下面的盒子是 7,因为它看起来比最左边的下一个盒子高一排。

我尝试过但无效的方法:

现在我 可以 更改服务器端渲染并重新排序项目,将项目数除以列数,但这很复杂,容易出错(基于浏览器决定将项目列表拆分为列的方式),所以我想尽可能避免它。

是否有一些 flexbox 魔法使这成为可能?

原文由 Pekka 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 413
1 个回答

2021 更新

CSS 网格布局级别 3 包括一个 masonry 特性。

代码将如下所示:

 grid-template-rows: masonry
grid-template-columns: masonry

截至 2021 年 3 月,它仅在 Firefox 中可用(激活标志后)。

结束更新;原回答如下


弹性盒

Flexbox 不可能实现动态砌体布局,至少不能以干净高效的方式实现。

Flexbox 是一个一维布局系统。这意味着它可以沿水平或垂直线对齐项目。弹性项目仅限于其行或列。

真正的网格系统是二维的,这意味着它可以沿水平和垂直线对齐项目。内容项目可以同时跨越行和列,这是弹性项目无法做到的。

这就是为什么 flexbox 构建网格的能力有限。这也是 W3C 开发了另一种 CSS3 技术 Grid Layout 的原因。


row wrap

在带有 flex-flow: row wrap 的弹性容器中,弹性项目必须换行到新 _行_。

这意味着 _弹性项目不能换行在同一行中的另一个项目之下_。

请注意上面的 div #3 如何包裹在 div #1 之下,创建一个新行。它不能包裹在 div #2 之下。

结果,当项目不是行中最高的时候,空白仍然存在,造成难看的间隙。


column wrap

如果切换到 flex-flow: column wrap ,则更容易实现类似网格的布局。然而,列向容器有四个潜在的问题:

  1. 弹性项目垂直流动,而不是水平流动(就像你在这种情况下需要的那样)。
  2. 容器水平扩展,而不是垂直扩展(类似于 Pinterest 布局)。
  3. 它要求容器具有固定的高度,以便物品知道在哪里包装。
  4. 在撰写本文时,它在所有主要浏览器中都存在缺陷,其中 容器不会扩展以容纳额外的列

因此,列方向容器在这种情况下不是一个选项,在许多其他情况下也是如此。


项目尺寸未定义的 CSS 网格

如果可以预先确定内容项的各种高度, 网格布局将是您问题的完美解决方案。所有其他要求都在 Grid 的能力范围内。

必须知道网格项目的宽度和高度,以便缩小与周围项目的差距。

因此,Grid 是构建水平流动的砖石布局的最佳 CSS,但在这种情况下达不到要求。

事实上,在能够自动缩小差距的 CSS 技术出现之前,CSS 通常没有解决方案。像这样的事情可能需要重排文档,所以我不确定它会有多大用处或效率。

你需要一个脚本。

JavaScript 解决方案倾向于使用绝对定位,它从文档流中删除内容项,以便重新排列它们而没有间隙。这里有两个例子:

Masonry 是一个 JavaScript 网格布局库。它的工作原理是根据可用的垂直空间将元素放置在最佳位置,有点像泥瓦匠在墙上安装石头。

来源:http: //masonry.desandro.com/

[Pinterest] 确实是一个很酷的网站,但我觉得有趣的是这些看板是如何布局的……所以本教程的目的是自己重新创建这种响应式块效果……

来源: https ://benholland.me/javascript/2012/02/20/how-to-build-a-site-that-works-like-pinterest.html


定义了项目尺寸的 CSS 网格

对于内容项的宽度和高度已知的布局,这里是纯 CSS 中的水平流动砌体布局:

 grid-container {
  display: grid;                                                /* 1 */
  grid-auto-rows: 50px;                                         /* 2 */
  grid-gap: 10px;                                               /* 3 */
  grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));   /* 4 */
}

[short] {
  grid-row: span 1;                                             /* 5 */
  background-color: green;
}

[tall] {
  grid-row: span 2;
  background-color: crimson;
}

[taller] {
  grid-row: span 3;
  background-color: blue;
}

[tallest] {
  grid-row: span 4;
  background-color: gray;
}

grid-item {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3em;
  font-weight: bold;
  color: white;
}
 <grid-container>
  <grid-item short>01</grid-item>
  <grid-item short>02</grid-item>
  <grid-item tall>03</grid-item>
  <grid-item tall>04</grid-item>
  <grid-item short>05</grid-item>
  <grid-item taller>06</grid-item>
  <grid-item short>07</grid-item>
  <grid-item tallest>08</grid-item>
  <grid-item tall>09</grid-item>
  <grid-item short>10</grid-item>
  <grid-item tallest>etc.</grid-item>
  <grid-item tall></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item tallest></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item tallest></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
</grid-container>

jsFiddle 演示


怎么运行的

  1. 建立块级网格容器。inline-grid 是另一个选项)
  2. grid-auto-rows 属性设置自动生成的行的高度。在这个网格中,每一行都是 50px 高。
  3. grid-gap 属性是 grid-column-gapgrid-row-gap 的简写。此规则在网格项 之间 设置 10px 的间距。 (它不适用于项目和容器之间的区域。)
  4. grid-template-columns 属性设置明确定义的列的宽度。

repeat 表示法定义了重复列(或行)的模式。

auto-fill 函数告诉网格在不溢出容器的情况下排列尽可能多的列(或行)。 (这可以创建与 flex 布局的 flex-wrap: wrap 类似的行为。)

minmax() 函数设置每列(或行)的最小和最大大小范围。在上面的代码中,每列的宽度最小为容器的 30%,最大为可用空间的宽度。

fr 单元 表示网格容器中可用空间的一部分。它相当于 flexbox 的 flex-grow 属性。

  1. 使用 grid-rowspan 我们告诉网格项它们应该跨越多少行。

CSS 网格的浏览器支持

  • Chrome - 截至 2017 年 3 月 8 日的全面支持(版本 57)
  • Firefox - 截至 2017 年 3 月 6 日的全面支持(版本 52)
  • Safari - 截至 2017 年 3 月 26 日的全面支持(版本 10.1)
  • Edge - 截至 2017 年 10 月 16 日的全面支持(第 16 版)
  • IE11 - 不支持当前规范;支持过时版本

这是完整的图片: http ://caniuse.com/#search=grid


Firefox 中的炫酷网格覆盖功能

在 Firefox 开发工具中,当您检查网格容器时,CSS 声明中有一个微小的网格图标。单击它会在页面上显示网格的轮廓。

此处有更多详细信息: https ://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts

原文由 Michael Benjamin 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏