博客地址:https://ainyi.com/60css
經過 Multi-columns 相關的屬性 column-count
、column-gap
配合 break-inside
來實現瀑布流佈局。html
設置這樣的 html 結構:git
1 <div class="masonry"> 2 <div class="item"> 3 <div class="item_content content-lar"> 1 4 </div> 5 </div> 6 <div class="item"> 7 <div class="item_content content-sma"> 2 8 </div> 9 </div> 10 <div class="item"> 11 <div class="item_content content-mid"> 3 12 </div> 13 </div> 14 <div class="item"> 15 <div class="item_content content-sma"> 4 16 </div> 17 </div> 18 <div class="item"> 19 <div class="item_content content-mid"> 5 20 </div> 21 </div> 22 <div class="item"> 23 <div class="item_content content-lar"> 6 24 </div> 25 </div> 26 <div class="item"> 27 <div class="item_content content-sma"> 7 28 </div> 29 </div> 30 <div class="item"> 31 <div class="item_content content-lar"> 8 32 </div> 33 </div> 34 <div class="item"> 35 <div class="item_content content-lar"> 9 36 </div> 37 </div> 38 <div class="item"> 39 <div class="item_content content-sma"> 10 40 </div> 41 </div> 42 <div class="item"> 43 <div class="item_content content-mid"> 11 44 </div> 45 </div> 46 <div class="item"> 47 <div class="item_content content-mid"> 12 48 </div> 49 </div> 50 <!-- more items --> 51 </div>
.masonry 是瀑布流容器,裏面放置了列表 item,在 .masonry
中設置 column-count(列數)
和 column-gap(
列間距)github
item 中設置 break-inside:avoid,這是
爲了控制文本塊分解成單獨的列,以避免項目列表的內容跨列,破壞總體的佈局。web
在 css 中設置包裹 masonry 和 item 的屬性樣式:數組
1 .masonry { 2 -moz-column-count:3; /* Firefox */ 3 -webkit-column-count:3; /* Safari 和 Chrome */ 4 column-count:3; 5 -moz-column-gap: 2em; 6 -webkit-column-gap: 2em; 7 column-gap: 2em; 8 width: 80%; 9 margin:2em auto; 10 } 11 .item { 12 padding: 2em; 13 margin-bottom: 2em; 14 -moz-page-break-inside: avoid; 15 -webkit-column-break-inside: avoid; 16 break-inside: avoid; 17 background: #f60; 18 }
固然爲了佈局具備響應式效果,能夠藉助媒體查詢屬性,在不一樣屏幕大小的條件下設置瀑布流容器 masonry 的 column-count 來自適應改變列數
:瀏覽器
1 @media screen and (max-width: 800px) { 2 .masonry { 3 column-count: 2; // two columns on larger phones 4 } 5 } 6 @media screen and (max-width: 500px) { 7 .masonry { 8 column-count: 1; // two columns on larger phones 9 } 10 }
那麼所產生的效果是:ide
也是根據屏幕大小自適應改變列數佈局
html 的結構依舊和上面的 Multi-columns 展現的同樣。只是在 .masonry
容器中使用的 CSS 不同:flex
在 .masonry
中是經過採用 flex-flow
來控制列,而且容許它換行。
這裏關鍵是容器的高度,我這裏要顯式的設置 height
屬性,固然除了設置 px
值,還能夠設置100vh
,讓 .masonry
容器的高度和瀏覽器視窗高度同樣。
記住,這裏height
能夠設置成任何高度值(採用任何的單位),但不能不顯式的設置,若是沒有顯式的設置,容器就沒法包裹住項目列表。
1 .masonry { 2 height: 800px; 3 display: flex; 4 flex-flow: column wrap; 5 width: 80%; 6 margin:2em auto; 7 }
對於 .item,
能夠再也不使用 break-inside:avoid
,但其它屬性能夠是同樣。
一樣的,響應式設置,使用 Flexbox 實現響應式佈局比多列布局 Multi-columns 要來得容易,他天生就具有這方面的能力,只不過咱們這裏須要對容器的高度作相關的處理。
前面也提到過了,若是不給 .masonry
容器顯式設置高度是沒法包裹項目列表的,那麼這裏響應式設計中就須要在不一樣的媒體查詢條件下設置不一樣的高度值:
1 @media screen and (max-width: 1100px) { 2 .masonry { 3 height: 800px; 4 } 5 } 6 @media screen and (max-width: 800px) { 7 .masonry { 8 height: 1100px; 9 } 10 } 11 @media screen and (max-width: 600px) { 12 .masonry { 13 height: 1300px; 14 } 15 } 16 @media screen and (max-width: 460px) { 17 .masonry { 18 height: 1600px; 19 } 20 }
那麼所產生的效果是:
也是根據屏幕大小自適應改變列數。
看到這裏,咱們能夠發現,使用純 css 寫瀑布流,每一塊 item 都是從上往下排列,不能作到從左往右排列:
這樣子如果動態加載圖片的瀑布流,體驗就會很很差
咱們想要的是這樣:
這樣作只能經過 js 來寫瀑布流
html 結構與上面相似,這裏我用圖片來作示例:
1 <div class="masonry"> 2 <div class="item"> 3 <img class="lazy" src="images/1.jpg" alt="" /> 4 </div> 5 <div class="item"> 6 <img class="lazy" src="images/2.jpg" alt="" /> 7 </div> 8 <div class="item"> 9 <img class="lazy" src="images/3.jpg" alt="" /> 10 </div> 11 <div class="item"> 12 <img class="lazy" src="images/4.jpg" alt="" /> 13 </div> 14 <div class="item"> 15 <img class="lazy" src="images/5.jpg" alt="" /> 16 </div> 17 <div class="item"> 18 <img class="lazy" src="images/6.jpg" alt="" /> 19 </div> 20 <div class="item"> 21 <img class="lazy" src="images/7.jpg" alt="" /> 22 </div> 23 <div class="item"> 24 <img class="lazy" src="images/8.jpg" alt="" /> 25 </div> 26 <div class="item"> 27 <img class="lazy" src="images/9.jpg" alt="" /> 28 </div> 29 <div class="item"> 30 <img class="lazy" src="images/10.jpg" alt="" /> 31 </div> 32 <div class="item"> 33 <img class="lazy" src="images/11.jpg" alt="" /> 34 </div> 35 <div class="item"> 36 <img class="lazy" src="images/12.jpg" alt="" /> 37 </div> 38 <div class="item"> 39 <img class="lazy" src="images/13.jpg" alt="" /> 40 </div> 41 <div class="item"> 42 <img class="lazy" src="images/14.jpg" alt="" /> 43 </div> 44 <div class="item"> 45 <img class="lazy" src="images/15.jpg" alt="" /> 46 </div> 47 <div class="item"> 48 <img class="lazy" src="images/16.jpg" alt="" /> 49 </div> 50 <div class="item"> 51 <img class="lazy" src="images/17.jpg" alt="" /> 52 </div> 53 <div class="item"> 54 <img class="lazy" src="images/18.jpg" alt="" /> 55 </div> 56 <div class="item"> 57 <img class="lazy" src="images/19.jpg" alt="" /> 58 </div> 59 <div class="item"> 60 <img class="lazy" src="images/20.jpg" alt="" /> 61 </div> 62 <div class="item"> 63 <img class="lazy" src="images/21.jpg" alt="" /> 64 </div> 65 <div class="item"> 66 <img class="lazy" src="images/22.jpg" alt="" /> 67 </div> 68 <div class="item"> 69 <img class="lazy" src="images/23.jpg" alt="" /> 70 </div> 71 <div class="item"> 72 <img class="lazy" src="images/24.jpg" alt="" /> 73 </div> 74 </div>
css 內容:
1 .masonry { 2 width: 100%; 3 margin-top: 50px; 4 position:relative; 5 } 6 .item { 7 z-index: 10; 8 transition: 0.25s; 9 overflow: hidden; 10 position: absolute; 11 } 12 .item img{ 13 width: 100%; 14 height:100%; 15 transition: 0.25s; 16 } 17 .item:hover img{ 18 z-index: 100; 19 transition: 0.25s; 20 overflow: hidden; 21 animation: bounceIn 0.25s ease-in 2 alternate; 22 } 23 @keyframes bounceIn{ 24 100% { 25 transform: scale(1.07); 26 } 27 }
js 瀑布流實現方式:
css 的絕對定位方式:根據每張圖片的位置設置 top 和 left 值:
1 //瀑布流效果 2 //這裏有一個坑(已經修復): 3 //由於是動態加載遠程圖片,在未加載徹底沒法獲取圖片寬高 4 //未加載徹底就沒法設定每個item(包裹圖片)的top。 5 6 //item的top值:第一行:top爲0 7 // 其餘行:必須算出圖片寬度在item寬度的縮小比例,與獲取的圖片高度相乘,從而得到item的高度 8 // 就能夠設置每張圖片在瀑布流中每塊item的top值(每一行中最小的item高度,數組查找) 9 //item的left值:第一行:按照每塊item的寬度值*塊數 10 // 其餘行:與自身上面一塊的left值相等 11 function waterFall() { 12 // 1- 肯定圖片的寬度 - 滾動條寬度 13 var pageWidth = getClient().width-8; 14 var columns = 3; //3列 15 var itemWidth = parseInt(pageWidth/columns); //獲得item的寬度 16 $(".item").width(itemWidth); //設置到item的寬度 17 18 var arr = []; 19 20 $(".masonry .item").each(function(i){ 21 var height = $(this).find("img").height(); 22 var width = $(this).find("img").width(); 23 var bi = itemWidth/width; //獲取縮小的比值 24 var boxheight = parseInt(height*bi); //圖片的高度*比值 = item的高度 25 26 if (i < columns) { 27 // 2- 肯定第一行 28 $(this).css({ 29 top:0, 30 left:(itemWidth) * i 31 }); 32 arr.push(boxheight); 33 34 } else { 35 // 其餘行 36 // 3- 找到數組中最小高度 和 它的索引 37 var minHeight = arr[0]; 38 var index = 0; 39 for (var j = 0; j < arr.length; j++) { 40 if (minHeight > arr[j]) { 41 minHeight = arr[j]; 42 index = j; 43 } 44 } 45 // 4- 設置下一行的第一個盒子位置 46 // top值就是最小列的高度 47 $(this).css({ 48 top:arr[index], 49 left:$(".masonry .item").eq(index).css("left") 50 }); 51 52 // 5- 修改最小列的高度 53 // 最小列的高度 = 當前本身的高度 + 拼接過來的高度 54 arr[index] = arr[index] + boxheight; 55 } 56 }); 57 } 58 59 60 //clientWidth 處理兼容性 61 function getClient() { 62 return { 63 width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, 64 height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 65 } 66 } 67 68 69 70 // 頁面尺寸改變時實時觸發 71 window.onresize = function() { 72 //從新定義瀑布流 73 waterFall(); 74 }; 75 76 77 78 //初始化 79 window.onload = function(){ 80 81 //實現瀑布流 82 waterFall(); 83 84 }
效果圖是:
這實現了橫向排列的瀑布流效果
博客地址:https://ainyi.com/60
GitHub:https://github.com/Krryxa