tiodot / tiodot.github.io

总结归纳--做的东西不是每一件都留到现在 但是能通过实践,收获了如何构建一套系统,一套工具的方法论
https://xchb.work
8 stars 0 forks source link

瀑布流布局之multi-columns实现 #24

Open tiodot opened 7 years ago

tiodot commented 7 years ago

最近开发手机端相关项目,访问页面时需要在PC上先把链接生成二维码,然后手机端扫码。经常需要访问不同页面,于是不停的复制链接,然后生成二维码,甚是麻烦,于是做了一个简易版的在线二维码转换页面,每次生成之后都可以选择保存到本地(所有保存都基于localStorage实现)。在展示历史记录时,发现各条历史有可能长度不一,对应的卡片高度也就不一致,很适合使用瀑布流布局实现。

瀑布流布局

首先看一个瀑布流的示例:

machi 2017-07-29 00-12-04

瀑布流可以简单的理解为是一个多栏布局,每一栏包含的元素块高度不一致,尽管如此,总体看起来各栏高度基本一致。最为主要的是每一个元素块左右或者上下间距都是一样的,从而有效的节约了页面空间。

现有实现方案

瀑布流的特性也带来了其实现上的难点:

  1. 栏数如何自适应,例如小屏2栏,大屏4栏
  2. 每一栏怎么布局,也就是新增元素块时应该加到那一栏?

如果借助于js,这些都不是问题,像热门的实现瀑布流布局js库masonry。其主要思想就是绝对定位,线上masonry示例,在数据加载过程中,首先获取数据对应元素块的高度,然后获取此时高度最小的某一列,从而计算出元素块的位置(left、top的值),最后插入到页面中。

当然也可使用纯CSS实现

  1. 使用Flex布局
  2. 使用multi-columns
  3. 使用grid布局

使用multi-columns实现

类似于flex布局,multi-columns其实也是也是一种布局方式。flex,grid布局都是通过元素的display属性来声明,而multi-columns布局则当元素的column-width或者column-count属性不是auto时触发。

body { column-width: 200px;  column-gap: 0;}

表示body是multi-columns布局,其每一列宽度至少为200px,至于有多少列取决于body元素的宽度。这里至少的意思是加入body宽度为799px, 而此时分为4列又少1px,所以只能分为3列,然后每一列会宽度为799 / 3 = 266.33px。

body { column-count: 2 }

而这种表示body元素有两列,每一列的宽度取决于可用的宽度。 如果同时设置column-widthcolumn-count

body { 
  column-width: 200px; 
  column-count: 3;
  column-gap: 0;
}

表示最多可以为3列,然后每列的宽度至少为200px。 也可以使用columns,该属性是column-widthcolumn-count的简便写法,以上示例的简便写法为:

body { 
  columns: 3 200px;  // 或者columns: 200px 3; 位置不影响
  column-gap: 0;
}

还有其他的一些属性:

  1. column-gap: 列与列之间的空隔
  2. column-rule: 形似border,位于column-gap的中间,不占用位置,类似于position:absolute。
  3. break-before, break-after, break-inside: 表示每列元素分割位置
  4. column-span:类似于表格的span,表示某一个元素占用列数,默认是1。 具体可以参考CSS Multi-column Layout Module

于是要实现一个瀑布流布局就可以很简单了:

// html结构
<body>
  <div>a</div>
  <div>b</div>
  <div>c</div>
  <div>a</div>
  <div>b</div>
</body>
// css结构
body {
  column-gap: 20px;
  column-rule: 1px solid red;
  columns: 200px; 
  padding: 0;
  margin: 0;
}

div {
  background: green;
  text-align: center;
  margin-bottom: 10px;
}

效果预览:

machi 2017-07-31 21-06-07

其他

很是好奇multi-columns的实现原理,是如何实现保证各列高度基本一致?

参考

  1. 在线二维码转换页面
  2. 纯CSS实现瀑布流布局
  3. CSS Multi-column Layout Module
youngwind commented 7 years ago

我不知道 multi-columns 的实现原理,但是之前我看过这篇文章,里面就提到,要想做到“各列的高度差最小”,可以考虑使用动态规划,具体的我也没有实现过。