css3 實現(xiàn)瀑布流布局

瀑布流布局有一個專業(yè)的英文名稱Masonry Layouts。瀑布流布局已經(jīng)有好多年的歷史了政勃,我最早知道這個名詞的時候大約是在2012年唧龄,當(dāng)時Pinterest網(wǎng)站的布局就是使用的這種流式布局,簡言之像Pinterest網(wǎng)站這樣的布局就稱之為瀑布流布局奸远,也有人稱之為Pinterest 布局既棺。

瀑布流布局其核心是基于一個網(wǎng)格的布局,而且每行包含的項目列表高度是隨機的(隨著自己內(nèi)容動態(tài)變化高度)懒叛,同時每個項目列表呈堆棧形式排列丸冕,最為關(guān)鍵的是,堆棧之間彼此之間沒有多余的間距差存大薛窥。還是上張圖來看看我們說的瀑布流布局是什么樣子胖烛。

image

當(dāng)初要實現(xiàn)這樣的布局都是依賴于JavaScript來實現(xiàn),所以當(dāng)時出現(xiàn)過很多實現(xiàn)瀑布流布局的插件诅迷。比如Masonry佩番、Isotope等都是非常有名的插件。但使用純CSS來實現(xiàn)罢杉,當(dāng)時還是非常困難的趟畏,不管是使用float還是inline-block布局都無法很好的控制列表項目堆棧之間的間距。最終得到的效果就像下面這樣:

image

現(xiàn)在距離2012年已經(jīng)過去了五個年頭屑那,CSS的技術(shù)更新也是日新月異拱镐,在這幾年當(dāng)中出現(xiàn)了很多新的布局方法,比如多列布局multi-columns持际、Flexbox布局以及今年瀏覽器支持有Grid布局沃琅。早前在《CSS布局的未來》一文中有對這些布局做過闡述。既然CSS的布局有這么多的變化蜘欲,那么今天有沒有不借助任何JavaScript(純CSS方案)能否實現(xiàn)瀑布流布局益眉?答案是肯定的,接下來的內(nèi)容姥份,我們就使用不同的CSS布局方案來實現(xiàn)瀑布流布局郭脂。

Multi-columns

首先最早嘗試使用純CSS方法解決瀑布流布局的是CSS3 的Multi-columns。其最早只是用來用來實現(xiàn)文本多列排列(類似報紙雜志樣的文本排列)澈歉。但對于前端同學(xué)來說展鸡,他們都是非常具有創(chuàng)意和創(chuàng)新的,有人嘗試通過Multi-columns相關(guān)的屬性column-count埃难、column-gap配合break-inside來實現(xiàn)瀑布流布局
比如我們有一個類似這樣的HTML結(jié)構(gòu):

<div class="masonry"> 
    <div class="item"> 
      <div class="item__content"> </div>
    </div> 
    <div class="item"> 
        <div class="item__content"> </div>
    </div> 
    <!-- more items --> 
</div>

其中div.masonry是瀑布流的容器莹弊,其里面放置了n個列表div.item涤久。為了節(jié)約篇幅,上面代碼僅列了兩個忍弛。結(jié)構(gòu)有了响迂,現(xiàn)在來看CSS。在.masonry中設(shè)置column-countcolumn-gap细疚,前者用來設(shè)置列數(shù)蔗彤,后者設(shè)置列間距:

.masonry { column-count: 5; column-gap: 0; }

上面控制了列與列之間的效果,但這并不是最關(guān)鍵之處疯兼。當(dāng)初純CSS實現(xiàn)瀑布流布局中最關(guān)鍵的是堆棧之間的間距然遏,而并非列與列之間的控制(說句實話,列與列之間的控制float之類的就能很好的實現(xiàn))吧彪。找到實現(xiàn)痛楚啦鸣,那就好辦了±囱酰或許你會問有什么CSS方法可以解決這個。在CSS中有一個break-inside屬性香拉,這個屬性也是實現(xiàn)瀑布流布局最關(guān)鍵的屬性啦扬。

.item { break-inside: avoid; box-sizing: border-box; padding: 10px; }

其中break-inside:avoid為了控制文本塊分解成單獨的列,以免項目列表的內(nèi)容跨列凫碌,破壞整體的布局扑毡。當(dāng)然為了布局具有響應(yīng)式效果,可以借助媒體查詢屬性盛险,在不同的條件下使用column-count設(shè)置不同的列瞄摊,比如:

.masonry { 
    column-count: 1; // one column on mobile
} 
@media (min-width: 400px) { 
    .masonry { column-count: 2; // two columns on larger phones } 
} 
@media (min-width: 1200px) { 
    .masonry { column-count: 3; // three columns on...you get it } 
}
 <!-- etc. -->

比如下面的這個示例:點擊預(yù)覽

示例1.png

看到上面示例的效果,這個時候是不是有點成就感了苦掘,是不是覺得CSS更神奇了换帜?

Flexbox


Flexbox布局到今天已經(jīng)是使用非常廣泛的,也算是很成熟的一個特性鹤啡。那接下來我們就看Flexbox怎么實現(xiàn)瀑布流布局惯驼。如果你從未接觸過Flexbox相關(guān)的屬性,那建議你點擊這里閱讀递瑰。如果你覺得這里信息量過于太多祟牲,那強列建議你閱讀下面幾篇文章,閱讀完之后你對Flexbox相關(guān)屬性會有一個徹底的了解:

接下來回到我們今天的正題當(dāng)中抖部,使用Flexbox實現(xiàn)瀑布流布局有兩種方案说贝。

一個主要的列容器


結(jié)構(gòu)依舊和Multi-columns小節(jié)中展示的一樣。只是在.masonry容器中使用的CSS不一樣:

.masonry {
    display: flex;
    flex-flow: column wrap;
    width: 100%;
    height: 800px;
}

之前在.masonry中是通過column-count來控制列慎颗,這里采用flex-flow來控制列乡恕,并且允許它換行言询。這里關(guān)鍵是容器的高度,示例中顯式的設(shè)置了height屬性几颜,當(dāng)然除了設(shè)置px值倍试,還可以設(shè)置100vh,讓.masonry容器的高度和瀏覽器視窗高度一樣蛋哭。記住县习,這里height可以設(shè)置成任何高度值(采用任何的單位),但不能不顯式的設(shè)置谆趾,如果沒有顯式的設(shè)置躁愿,容器就無法包裹住項目列表。

使用Flexbox布局沪蓬,對于.item可以不再使用break-inside:avoid彤钟,但其它屬性可以是一樣。同樣的跷叉,響應(yīng)式設(shè)置逸雹,使用Flexbox實現(xiàn)響應(yīng)式布局比多列布局要來得容易,他天生就具備這方面的能力云挟,只不過我們這里需要對容器的高度做相關(guān)的處理梆砸。前面也提到過了,如果不給.masonry容器顯式設(shè)置高度是無法包裹項目列表的园欣,那么這里響應(yīng)式設(shè)計中就需要在不同的媒體查詢條件下設(shè)置不同的高度值:

.masonry {
    height: auto;
}

@media screen and (min-width: 400px) {
    .masonry {
        height: 1600px;
    }
}

@media screen and (min-width: 600px) {
    .masonry {
        height: 1300px;
    }
}

@media screen and (min-width: 800px) {
    .masonry {
        height: 1100px;
    }
}

@media screen and (min-width: 1100px) {
    .masonry {
        height: 800px;
    }
}

同樣來看一個示例效果:點擊預(yù)覽

示例2.png

這個解決方案有一個最致命的地方帖世,就是需要顯式的給.masonry設(shè)置height,特別對于響應(yīng)式設(shè)計來說這個更為不友好沸枯。而且當(dāng)我們的項目列表是動態(tài)生成日矫,而且內(nèi)容不好控制之時,這就更蛋疼了绑榴。那么有沒有更為友好的方案呢哪轿?

前面說到過Flexbox有兩種方案,那咱們先來看方案二翔怎,再來回答這個問題缔逛。

單獨的列容器

這個方案,我們需要對我們的HTML結(jié)構(gòu)做一個變更姓惑。變更后的HTML結(jié)構(gòu)看起來像這樣:

<div class="masonry">
    <div class="column">
        <div class="item">
        <div class="item__content">
        </div>
        </div>
        <!-- more items -->
    </div>
    <div class="column">
        <div class="item">
        <div class="item__content">
        </div>
        </div>
        <!-- more items -->
    </div>
    <div class="column">
        <div class="item">
        <div class="item__content">
        </div>
        </div>
        <!-- more items -->
    </div>
</div>

不難發(fā)現(xiàn)褐奴,在div.item外面包了一層div.column,這個div.column稱為列表項目的單獨容器于毙。在這個解決方案中敦冬,.masonry.column都通過display:flex屬性將其設(shè)置為Flex容器,不同的是.masonry設(shè)置為行(flex-direction:row)唯沮,而.column設(shè)置為列(flex-direction):

.masonry {
    display: flex;
    flex-direction: row;
}

.column {
    display: flex;
    flex-direction: column;
    width: calc(100%/3);
}

這里有一個需要注意脖旱,在.column咱們通過calc()方法來控制每個列的寬度堪遂,如果你希望是三列,那么可以設(shè)置width: calc(100% / 3);實際中根據(jù)自己的設(shè)計來設(shè)置width

.masonry {
    display: flex;
    flex-direction: row;
}

.column {
    display: flex;
    flex-direction: column;
    width: calc(100%/3);
}

這種方案對應(yīng)的響應(yīng)式設(shè)計萌庆,需要在不同的媒體查詢下修改width值溶褪,比如:

.masonry {
    display: flex;
    flex-direction: column;
}

@media only screen and (min-width: 500px) {
    .masonry {
        flex-direction: row;
    }
}

.column {
    display: flex;
    flex-flow: column wrap;
    width: 100%;
}

@media only screen and (min-width: 500px) {
    .column {
        width: calc(100%/5);
    }
}

效果如下:點擊預(yù)覽

示例3.png

從實戰(zhàn)結(jié)果已經(jīng)告訴你答案了。只不過在結(jié)構(gòu)上變得冗余一點践险。

Grid

Grid將是布局當(dāng)中的一把利劍猿妈,也可以說是神器,特別是今年得到了眾多瀏覽器的支持巍虫。記得去年在CSSConf分享后彭则,有同學(xué)問我Grid是否能實現(xiàn)瀑布流的布局。說實話占遥,雖然Grid對于布局而言是非常的強大俯抖,但要很好的實現(xiàn)瀑布流布局還是非常的蛋疼。@Rachel Andrew在她分享的文章中也特意提到過實現(xiàn)瀑布流的方案瓦胎。從文章中摘出有關(guān)于瀑布流布局的那部分內(nèi)容芬萍。

Grid制作瀑布流,對于結(jié)構(gòu)而言和Multi-columns示例中的一樣搔啊。只不過在.masonry使用display:grid來進行聲明:

.masonry {
    display: grid;
    grid-gap: 40px;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: minmax(50px, auto);
}

對于.item較為蛋疼担忧,需要分別通過grid-rowgrid-column來指定列表項目所在的區(qū)域,比如:

.masonry > div:nth-child(1) {
    grid-row: 1 / 4;
    grid-column: 1;
}

.masonry > div:nth-child(2) {
    grid-row: 1 / 3;
    grid-column: 2;
}
...

將效果Fork過來:點擊預(yù)覽

WX20181229-103956@2x.png

在Grid中有自動排列的算法的屬性:

  • 如果沒有明確指定網(wǎng)格項目位置坯癣,網(wǎng)格會按自動排列算法,將它最大化利用可用空間
  • 如果在當(dāng)前行沒有可用位置最欠,網(wǎng)格會自動搜索下一行示罗,這樣會造成一定的差距,浪費可用空間
  • 可以把grid-auto-flowrow值改變auto芝硬,可以切換搜索順序
  • grid-auto-flow還可以接受另一個關(guān)鍵詞蚜点。默認(rèn)情況下,其值是sparse拌阴,但我們可以將其顯式的設(shè)置為dense绍绘,讓網(wǎng)格項目試圖自動填補所有可用的空白空間

言外之意,Grid中自動排列的算法對于實現(xiàn)瀑布流布局有很大的幫助迟赃。不過對于堆棧(列表項目)高度不能友好的控制陪拘。

總結(jié)

這篇文章主要介紹了如何使用純CSS實現(xiàn)瀑布流的布局。文章簡單介紹了三種實現(xiàn)方案:Multi-columns纤壁、Flexbox和Grid左刽。從上面的示例或者實現(xiàn)手段而言,較我友好的是Flexbox的方案酌媒。當(dāng)然欠痴,隨著CSS Grid特性的完善迄靠,使用Grid實現(xiàn)瀑布流布局將會變得更為簡單和友好。那讓我們拭目以待喇辽。當(dāng)然如果你覺得這些方案都不太好掌挚,你可以依舊可以考慮JavaScript的解決方案。如果你有更好的解決方案菩咨,也希望能在下面的評論中與我們一起分享吠式。

著作權(quán)歸作者所有。
商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處旦委。
原文: https://www.w3cplus.com/css/pure-css-create-masonry-layout.html ? w3cplus.com

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奇徒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子缨硝,更是在濱河造成了極大的恐慌摩钙,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件查辩,死亡現(xiàn)場離奇詭異胖笛,居然都是意外死亡,警方通過查閱死者的電腦和手機宜岛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進店門长踊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人萍倡,你說我怎么就攤上這事身弊。” “怎么了列敲?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵阱佛,是天一觀的道長。 經(jīng)常有香客問我戴而,道長凑术,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上汇竭,老公的妹妹穿的比我還像新娘瘦真。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般命满。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绣版,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天胶台,我揣著相機與錄音歼疮,去河邊找鬼。 笑死诈唬,一個胖子當(dāng)著我的面吹牛韩脏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播铸磅,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼赡矢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了阅仔?” 一聲冷哼從身側(cè)響起吹散,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎八酒,沒想到半個月后空民,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡羞迷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年界轩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衔瓮。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡浊猾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出热鞍,到底是詐尸還是另有隱情葫慎,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布薇宠,位于F島的核電站偷办,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏昼接。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一悴晰、第九天 我趴在偏房一處隱蔽的房頂上張望慢睡。 院中可真熱鬧,春花似錦铡溪、人聲如沸漂辐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽髓涯。三九已至,卻和暖如春哈扮,著一層夾襖步出監(jiān)牢的瞬間纬纪,已是汗流浹背蚓再。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留包各,地道東北人摘仅。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像问畅,于是被迫代替她去往敵國和親娃属。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,654評論 2 354

推薦閱讀更多精彩內(nèi)容