图片的瀑布流排列布局,之前我做这种需求都是使用 js + absolute 的方案来实现,实现的方法比较复杂,性能肯定也是比不上纯 css 的实现的,刚好我最近看到了 css 的 columns 属性,看到它的第一眼我就知道,这小子在实现瀑布流方面肯定是有所作为的

关于 columns MDN

columns 是用来设置元素的列宽和列数的,它有两个属性:column-widthcolumn-count,分别用来设置列宽和列数,语法如下:

1
columns: <column-width> || <column-count>

可以设置列宽和列数,但需要注意的是 column-width 不支持负值,也不支持百分比值

一个简单的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>使用 columns 实现瀑布流展示</title>
<style>
.flow {
column-count: 4;
column-gap: 10px;
width: 800px;
margin: auto;
background-color: #e5e5e5;
padding: 10px;
line-height: 0;

}
img {
width: 100%;
object-fit: cover;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div class="flow"></div>
<script>
const flow = document.querySelector('.flow')
for (let i = 0; i < 10; i++) {
const height = Math.floor(Math.random() * 200 + 200)
const src = `https://picsum.photos/200/${height}`
const img = document.createElement('img')
img.src = src
flow.appendChild(img)
}
</script>
</body>
</html>

效果如下:

image-20231006221849449

这样就已经完成了一个简单的瀑布流

卡片文字的展示

上面我们是直接展示了图片,那么如果我们希望 div + text 的组合也能实现这样一个瀑布流的布局是不是也能这样做呢?

下面我们就动手试试看吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>使用 columns 实现瀑布流展示</title>
<style>
.flow {
column-count: 4;
column-gap: 10px;
width: 800px;
margin: auto;
background-color: #e5e5e5;
padding: 10px;
}
.flow > div {
background-color: #ffffff;
margin-bottom: 10px;
padding: 5px;
}
</style>
</head>
<body>
<div class="flow"></div>
<script>
const flow = document.querySelector('.flow')
for (let i = 0; i < 10; i++) {
const div = document.createElement('div')
const content = [`这是第${i}个div'`];
const length = Math.floor(Math.random() * 200);
content.length = length + 1;
content.fill('好', 1);
const text = document.createTextNode(content.join(''));
div.appendChild(text)
flow.appendChild(div)
}
</script>
</body>
</html>

效果如下:

image-20231006232411845

我们发现它并不像我们想象中那样展示,而是将 div 进行了截断

幸好我们还有一个属性可以设置他的中断方式,那就是在不想被中断的 div 中设置 break-inside: avoid 这样这个 div 就不会被从中间截断了,我们对上面的代码进行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>使用 columns 实现瀑布流展示</title>
<style>
.flow {
column-count: 4;
column-gap: 10px;
width: 800px;
margin: auto;
background-color: #e5e5e5;
padding: 10px;
}
.flow > div {
background-color: #ffffff;
margin-bottom: 10px;
padding: 5px;
break-inside: avoid;
}
</style>
</head>
<body>
<div class="flow"></div>
<script>
const flow = document.querySelector('.flow')
for (let i = 0; i < 10; i++) {
const div = document.createElement('div')
const content = [`这是第${i}个div'`];
const length = Math.floor(Math.random() * 200);
content.length = length + 1;
content.fill('好', 1);
const text = document.createTextNode(content.join(''));
div.appendChild(text)
flow.appendChild(div)
}
</script>
</body>
</html>

效果如下:

image-20231006233154076

现在,它看起来就很合理了,到此使用纯 css 实现的瀑布流布局就实现了