CSS也能实现瀑布流布局?
前言
生活中很多软件都会使用到瀑布流,比如说淘宝的商品浏览页面,还有一些图片浏览页面,都会有瀑布流的应用场景。要做出好看的瀑布流,通常是使用js做响应式瀑布流,但是我们也可以通过一些强大的css属性,来完成瀑布流布局。这里我总结几个css属性帮我们制作瀑布流布局。
瀑布流
瀑布流布局,其视觉展示是一种参差不齐的多栏布局,不同数据块会无限附加在一栏中的上一个数据块的尾部,达到可无限加载数据的效果
多列布局(Multi-column)
Multi-column有下面一些属性:
1.columns:设置列数和每列的宽度
2.column-width:设置每列的宽度。
3.column-count:设置列数
4.column-gap:设置列与列之间的间隙
5.column-rule:设置列与列之间的分割线
6.column-span:设置元素是否跨所有列
7.column-fill:设置所有列的高度统一
...
利用 Multi-column 中几个属性就可以完成瀑布流布局:(这里我们利用vue来实现数据响应)
其中 column-count: 5;
将设置为5个列,column-gap: 20px;
将设置列与列之间的间距为20px,这样我们就很简单的实现了瀑布流布局。我还在每个数据块放置了文本,那么我在每个数据块设置了break-inside:avoid;
属性,用于使每个数据块内容不会中断。因为使用这种方法实现的瀑布流,遵循先从上到下,再从左到右排布,这样如果左边列的最后一个数据块的文本过多,就可能出现在其右一列的头部。
以下是完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<title>Document</title>
<style>
.box{
padding: 10px;
column-count: 5;
column-gap: 20px;
}
.item{
border: 1px solid #999;
margin-bottom: 10px;
break-inside:avoid;
}
.item img{
width: 100%;
}
</style>
</head>
<body>
<div id="app">
<div class="box">
<div class="item" v-for="item in list" :key="item.id">
<img :src="item.img" alt="">
<span class="title">{{item.content}}</span>
</div>
</div>
</div>
<script>
const {createApp} = Vue
createApp({
data(){
return {
list:[
{
id: 0,
content: '出或属及然立物区际团干林品号界织声政自青',
img: 'https://picsum.photos/200/335?random=58'
},
{
id: 1,
content: '规社需别至打她南气提现身记指今化油百积体',
img: 'https://picsum.photos/200/349?random=761'
},
{
id: 2,
content: '许题状世声程管么物社社同圆了而备公所料青',
img: 'https://picsum.photos/200/442?random=71'
},
{
id: 3,
content: '然立物区际团干林品号界织声政自青参从运统',
img: 'https://picsum.photos/200/322?random=312'
},
{
id: 4,
content: '团干林品号界织声政自青参从运统类半口识高',
img: 'https://picsum.photos/200/399?random=460'
},
{
id: 5,
content: '例导向王活中叫社就江工外以气图专律北多建',
img: 'https://picsum.photos/200/446?random=898'
},
{
id: 6,
content: '六思断名过增思复许石查再生斯法派带改叫向',
img: 'https://picsum.photos/200/495?random=460'
},
{
id: 7,
content: '可定开京出或属及然立物区际团干林品号界织',
img: 'https://picsum.photos/200/451?random=389'
},
{
id: 8,
content: '定开京出或属及然立物区际团干林品号界织声',
img: 'https://picsum.photos/200/374?random=216'
},
{
id: 9,
content: '提现身记指今化油百积体量但国参根书为影从',
img: 'https://picsum.photos/200/339?random=426'
},
{
id: 10,
content: '问任写主速情及极需和始亲点酸七建红放周养',
img: 'https://picsum.photos/200/400?random=22'
},
{
id: 11,
content: '参从运统类半口识高多选石空改流通工来万北',
img: 'https://picsum.photos/200/468?random=373'
},
{
id: 12,
content: '习七准导离每见里可求产着影却响百产际片院',
img: 'https://picsu m.photos/200/442?random=903'
},
{
id: 13,
content: '划子要步百图引美须成展党复任场走许就素受',
img: 'https://picsum.photos/200/416?random=874'
},
{
id: 14,
content: '上是题快而被己老制米制往例导向王活中叫社',
img: 'https://picsum.photos/200/421?random=219'
},
{
id: 15,
content: '开京出或属及然立物区际团干林品号界织声政',
img: 'https://picsum.photos/200/427?random=909'
}
]
}
}
}).mount('#app')
</script>
</body>
</html>
网格布局-grid
网格布局实现瀑布流也只需要使用其中几个属性:
1. grid-auto-rows:设置行高(auto; 即自适应行数)
2. grid-template-rows:设置每行的高度或比例(1fr 1fr 1fr;即三行且高度1:1:1)
3. grid-template-columns:设置列数
5. grid-row-start:设置开始的行数(auto;自适应开始的行数)
6. grid-row-end:结束行数(span 2; 即跨两行)
网格布局实现瀑布流需要先设置列数grid-template-columns: 1fr 1fr 1fr 1fr;
即四列均分,再设置网格布局的行高为一个较小的高度grid-auto-rows: 1px;
,但是不能高于图片最小高度,还需要设置每个容器的开始行grid-row-start: auto;
即自适应,最后用js来配合计算每张图片占有的网格行数,再设置每个图片容器的尾部(结束)行数,即跨多少行。(由于这里的图片数据都是用ChatGPT生成,所以是随机的,获取宽高也是从生成的图片链接截取)
注:这种方法不便于自适应的瀑布流,加载完成后,拖动改变窗口宽高但图片容器宽高未变,导致重叠或留白
源代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<title>Document</title>
<style>
.box{
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-auto-rows: 1px;
column-gap: 5px;
}
.item{
grid-row-start: auto;
}
.item img{
width: 100%;
}
</style>
</head>
<body>
<div id="app">
<div class="box">
<div class="item" v-for="item in list" :key="item.id">
<img :src="item.img" alt="">
</div>
</div>
</div>
<script>
const {createApp} = Vue
createApp({
data(){
return {
list:[
{
id: 0,
content: '出或属及然立物区际团干林品号界织声政自青',
img: 'https://picsum.photos/200/335?random=58'
},
{
id: 1,
content: '规社需别至打她南气提现身记指今化油百积体',
img: 'https://picsum.photos/200/349?random=761'
},
{
id: 2,
content: '许题状世声程管么物社社同圆了而备公所料青',
img: 'https://picsum.photos/200/442?random=71'
},
{
id: 3,
content: '然立物区际团干林品号界织声政自青参从运统',
img: 'https://picsum.photos/200/322?random=312'
},
{
id: 4,
content: '团干林品号界织声政自青参从运统类半口识高',
img: 'https://picsum.photos/200/399?random=460'
},
{
id: 5,
content: '例导向王活中叫社就江工外以气图专律北多建',
img: 'https://picsum.photos/200/446?random=898'
},
{
id: 6,
content: '六思断名过增思复许石查再生斯法派带改叫向',
img: 'https://picsum.photos/200/495?random=460'
},
{
id: 7,
content: '可定开京出或属及然立物区际团干林品号界织',
img: 'https://picsum.photos/200/451?random=389'
},
{
id: 8,
content: '定开京出或属及然立物区际团干林品号界织声',
img: 'https://picsum.photos/200/374?random=216'
},
{
id: 9,
content: '提现身记指今化油百积体量但国参根书为影从',
img: 'https://picsum.photos/200/339?random=426'
},
{
id: 10,
content: '问任写主速情及极需和始亲点酸七建红放周养',
img: 'https://picsum.photos/200/400?random=22'
},
{
id: 11,
content: '参从运统类半口识高多选石空改流通工来万北',
img: 'https://picsum.photos/200/468?random=373'
},
{
id: 12,
content: '习七准导离每见里可求产着影却响百产际片院',
img: 'https://picsum.photos/200/442?random=903'
},
{
id: 13,
content: '划子要步百图引美须成展党复任场走许就素受',
img: 'https://picsum.photos/200/416?random=874'
},
{
id: 14,
content: '上是题快而被己老制米制往例导向王活中叫社',
img: 'https://picsum.photos/200/421?random=219'
},
{
id: 15,
content: '开京出或属及然立物区际团干林品号界织声政',
img: 'https://picsum.photos/200/427?random=909'
}
]
}
},
mounted(){//生命周期函数
let items = document.getElementsByClassName('item')
Array.from(items).forEach(item => {//遍历每个图片容器
let img = item.getElementsByTagName('img')[0]
let newImg = new Image()//img是特例,只要被js创建就会被浏览器加载
newImg.src = img.src
//获取生成的图片的宽高
height = img.src.slice(img.src.lastIndexOf('/') + 1, img.src.lastIndexOf('?'))
width = img.src.slice(img.src.lastIndexOf('/') - 3 ,img.src.lastIndexOf('/'))
//根据窗口宽度计算缩放之后的图片高度,以便计算跨多少行
newImg.height = height * (item.clientWidth / width)
// console.log(newImg.height);
newImg.onload = function(){
//设置item占据网格的几行
item.style.gridRowEnd = `span ${newImg.height}`
}
})
}
}).mount('#app')
</script>
</body>
</html>
弹性布局
弹性布局实现瀑布流就是利用纵向弹性,使每列的每个容器接在上一个图片容器之后,瀑布流需要几栏就要设置几个div包裹,还要将数据分成相应的组数,方法比较low,一般不使用,优点就是可以设置flex: 1 ;
让每列宽度自适应,达到响应式效果。
源代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<title>Document</title>
<style>
.box{
display: flex;
flex-wrap: wrap;
}
.clomun{
flex: 1 ;
display: flex;
flex-direction: column;
}
</style>
</head>
<body>
<div id="app">
<div class="box">
<div class="clomun">
<img :src="item.img" v-for="item in list1" alt="">
</div>
<div class="clomun">
<img :src="item.img" v-for="item in list2" alt="">
</div>
<div class="clomun">
<img :src="item.img" v-for="item in list3" alt="">
</div>
</div>
</div>
<script>
const {createApp} = Vue
createApp({
data(){
return {
list1:[],
list2:[],
list3:[],
list:[
{
id: 0,
content: '出或属及然立物区际团干林品号界织声政自青',
img: 'https://picsum.photos/200/335?random=58'
},
{
id: 1,
content: '规社需别至打她南气提现身记指今化油百积体',
img: 'https://picsum.photos/200/349?random=761'
},
{
id: 2,
content: '许题状世声程管么物社社同圆了而备公所料青',
img: 'https://picsum.photos/200/442?random=71'
},
{
id: 3,
content: '然立物区际团干林品号界织声政自青参从运统',
img: 'https://picsum.photos/200/322?random=312'
},
{
id: 4,
content: '团干林品号界织声政自青参从运统类半口识高',
img: 'https://picsum.photos/200/399?random=460'
},
{
id: 5,
content: '例导向王活中叫社就江工外以气图专律北多建',
img: 'https://picsum.photos/200/446?random=898'
},
{
id: 6,
content: '六思断名过增思复许石查再生斯法派带改叫向',
img: 'https://picsum.photos/200/495?random=460'
},
{
id: 7,
content: '可定开京出或属及然立物区际团干林品号界织',
img: 'https://picsum.photos/200/451?random=389'
},
{
id: 8,
content: '定开京出或属及然立物区际团干林品号界织声',
img: 'https://picsum.photos/200/374?random=216'
},
{
id: 9,
content: '提现身记指今化油百积体量但国参根书为影从',
img: 'https://picsum.photos/200/339?random=426'
},
{
id: 10,
content: '问任写主速情及极需和始亲点酸七建红放周养',
img: 'https://picsum.photos/200/400?random=22'
},
{
id: 11,
content: '参从运统类半口识高多选石空改流通工来万北',
img: 'https://picsum.photos/200/468?random=373'
},
{
id: 12,
content: '习七准导离每见里可求产着影却响百产际片院',
img: 'https://picsum.photos/200/442?random=903'
},
{
id: 13,
content: '划子要步百图引美须成展党复任场走许就素受',
img: 'https://picsum.photos/200/416?random=874'
},
{
id: 14,
content: '上是题快而被己老制米制往例导向王活中叫社',
img: 'https://picsum.photos/200/421?random=219'
},
{
id: 15,
content: '开京出或属及然立物区际团干林品号界织声政',
img: 'https://picsum.photos/200/427?random=909'
},
{
id: 16,
content: '题快而被己老制米制往例导向王活中叫社就江',
img: 'https://picsum.photos/200/490?random=87'
},
{
id: 17,
content: '复许石查再生斯法派带改叫向派更织证果克长',
img: 'https://picsum.photos/200/481?random=643'
},
{
id: 18,
content: '产张声很那响备育然际看离面市用大平张律般',
img: 'https://picsum.photos/200/375?random=612'
},
{
id: 19,
content: '石空改流通工来万北林向小府万就八往得白证',
img: 'https://picsum.photos/200/431?random=16'
},
{
id: 20,
content: '备公所料青反要看万采如指组更产张声很那响',
img: 'https://picsum.photos/200/449?random=444'
},
{
id: 21,
content: '图专律北多建战器解然才料只根维光者率把律',
img: 'https://picsum.photos/200/311?random=625'
},
{
id: 22,
content: '石南至构严九题可定开京出或属及然立物区际',
img: 'https://picsum.photos/200/324?random=523'
},
{
id: 23,
content: '很那响备育然际看离面市用大平张律般那意县',
img: 'https://picsum.photos/200/341?random=443'
},
{
id: 24,
content: '图引美须成展党复任场走许就素受事多观界立',
img: 'https://picsum.photos/200/477?random=799'
},
{
id: 25,
content: '际看离面市用大平张律般那意县对门并议省取',
img: 'https://picsum.photos/200/459?random=62'
},
{
id: 26,
content: '社同圆了而备公所料青反要看万采如指组更产',
img: 'https://picsum.photos/200/361?random=105'
},
{
id: 27,
content: '知片具加其许题状世声程管么物社社同圆了而',
img: 'https://picsum.photos/200/321?random=569'
},
{
id: 28,
content: '南至构严九题可定开京出或属及然立物区际团',
img: 'https://picsum.photos/200/431?random=788'
},
{
id: 29,
content: '往得白证易习七准导离每见里可求产着影却响',
img: 'https://picsum.photos/200/328?random=462'
},
{
id: 30,
content: '京出或属及然立物区际团干林品号界织声政自',
img: 'https://picsum.photos/200/391?random=918'
},
{
id: 31,
content: '照酸但明片种设音规地白声那火半省上是题快',
img: 'https://picsum.photos/200/426?random=989'
},
{
id: 32,
content: '件型各离性格术五织做圆界位为经员间阶知片',
img: 'https://picsum.photos/200/430?random=505'
},
{
id: 33,
content: '件型各离性格术五织做圆界位为经员间阶知片',
img: 'https://picsum.photos/200/317?random=542'
},
{
id: 34,
content: '界位为经员间阶知片具加其许题状世声程管么',
img: 'https://picsum.photos/200/471?random=355'
},
{
id: 35,
content: '属及然立物区际团干林品号界织声政自青参从',
img: 'https://picsum.photos/200/432?random=552'
},
{
id: 36,
content: '感近度产数直华名车书细先值山不口问任写主',
img: 'https://picsum.photos/200/395?random=497'
},
{
id: 37,
content: '际团干林品号界织声政自青参从运统类半口识',
img: 'https://picsum.photos/200/327?random=773'
},
{
id: 38,
content: '界真离气建各划音感近度产数直华名车书细先',
img: 'https://picsum.photos/200/331?random=640'
},
{
id: 39,
content: '改流通工来万北林向小府万就八往得白证易习',
img: 'https://picsum.photos/200/348?random=187'
},
{
id: 40,
content: '叫向派更织证果克长商统八规社需别至打她南',
img: 'https://picsum.photos/200/484?random=777'
},
{
id: 41,
content: '八规社需别至打她南气提现身记指今化油百积',
img: 'https://picsum.photos/200/355?random=535'
},
{
id: 42,
content: '通工来万北林向小府万就八往得白证易习七准',
img: 'https://picsum.photos/200/400?random=173'
},
{
id: 43,
content: '离性格术五织做圆界位为经员间阶知片具加其',
img: 'https://picsum.photos/200/306?random=741'
},
{
id: 44,
content: '圆界位为经员间阶知片具加其许题状世声程管',
img: 'https://picsum.photos/200/302?random=605'
},
{
id: 45,
content: '种设音规地白声那火半省上是题快而被己老制',
img: 'https://picsum.photos/200/312?random=120'
},
{
id: 46,
content: '题状世声程管么物社社同圆了而备公所料青反',
img: 'https://picsum.photos/200/484?random=768'
},
{
id: 47,
content: '八规社需别至打她南气提现身记指今化油百积',
img: 'https://picsum.photos/200/459?random=661'
},
{
id: 48,
content: '用大平张律般那意县对门并议省取空万酸至名',
img: 'https://picsum.photos/200/303?random=329'
},
{
id: 49,
content: '高多选石空改流通工来万北林向小府万就八往',
img: 'https://picsum.photos/200/463?random=885'
}
]
}
},
mounted(){
let num = ~~(this.list.length / 3)//计算列的数据数量,便于下面分配
this.list1 = this.list.slice(0,num)
this.list2 = this.list.slice(num,num*2)
this.list3 = this.list.slice(num*2,this.list.length)
}
}).mount('#app')
</script>
</body>
</html>
实现瀑布流布局的主要手段是使用JS,因为用CSS一般难以实现我们想要的瀑布流效果(数据块分布,响应式等等),这里只是应该知道CSS也能完成瀑布流布局,一般使用第一种方法来实现,但是网格布局很强大,基本能实现我们想要的各种布局效果。
转载自:https://juejin.cn/post/7254020450161770557