Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
布流布局出來好多年了,剛出來時,一般都采用js來實現,涌現了很多比較好的js插件,例如:masonry.js、gridify.js等等。這里就不再詳說如何使用了,網上都能找到。今天討論的是純CSS實現瀑布流布局。
這種布局方法非常簡單,就是將多個列表橫向排列,每個列表擁有的項都差不多。圖片寬度固定,高度自動撐起來。
html:
<div class="wrap"> <ul class="waterfall"> <li class="item"><img src="image/1.jpg"></li> <li class="item"><img src="image/3.jpg"></li> <li class="item"><img src="image/5.jpg"></li> <li class="item"><img src="image/7.jpg"></li> <li class="item"><img src="image/9.jpg"></li> </ul> <ul class="waterfall"> <li class="item"><img src="image/2.jpg"></li> <li class="item"><img src="image/4.jpg"></li> <li class="item"><img src="image/6.jpg"></li> <li class="item"><img src="image/8.jpg"></li> <li class="item"><img src="image/10.jpg"></li> </ul> </div>
css:
.wrap{ display:flex; justify-content: space-between; } .waterfall{ width:50%; } .waterfall .item img{ width:100%; }
注:
1、waterfall也可以浮動,wrap清除浮動,只要兩個列表在一行就行。
2、每一塊 item 都是從上往下排列的,并不能實現從左往右,解決辦法是:在獲取數據時,需要將數據按奇偶進行分類顯示(假設顯示兩列,多列同理)。您可以定義兩個數組:listEven和listOdd,分別來接受獲取的數據的偶數項和奇數項,然后分別進行渲染。這里用VUE來演示:
//假設res.data為ajax請求到的數據 res.data.map(function(item,index){ index%2===0 ? that.listEven.push(item) : that.listOdd.push(item); })
<div class="wrap"> <ul class="waterfall"> <li class="item" v-for="(item,index) in listEven" :key="'even'+index"><img :src="item"></li> </ul> <ul class="waterfall"> <li class="item" v-for="(item,index) in listOdd" :key="'odd'+index"><img :src="item"></li> </ul> </div>
3、這種布局方法,會有一個問題,如果item高度左右列相差很大,就會顯示有問題,如下圖,解決辦法給item一個max-height,超過圖片這個max-height就隱藏,此外,后臺在傳圖片時做裁切更好:
css 瀑布流
CSS3 column多列可以非常輕松的實現瀑布流效果,它會自動將列表項分配到根據設置的列數當中去,先看下它的常用屬性:
html
<ul class="waterfall"> <li class="item"><img src="1.jpg"></li> <li class="item"><img src="2.jpg"></li> <li class="item"><img src="3.jpg"></li> <li class="item"><img src="4.jpg"></li> <li class="item"><img src="5.jpg"></li> <li class="item"><img src="6.jpg"></li> <li class="item"><img src="7.jpg"></li> <li class="item"><img src="8.jpg"></li> <li class="item"><img src="9.jpg"></li> <li class="item"><img src="10.jpg"></li> </ul>
css
.waterfall{ column-count:2; } .waterfall .item{ break-inside: avoid; }
效果如下:
css3瀑布流布局
注:
1、每一塊 item 都是從上往下排列的,并不能實現從左往右,第一種方法采用了奇偶兩個數組解決了,這個不好解決,如果帶有上拉加載,不確定總個數,就更不好解決了。
2、item的上下間距盡量不要用margin,否則可能會出現下面這種情況,這是因為左列最后一個margin跑到右邊上面去了,改成padding即可,因為padding屬于item的內容,而break-inside: avoid則禁止item折斷:
css3瀑布流布局
CSS3的flex用法很多。大多數情況都是用來橫排,將塊狀容器顯示在一行,還有就是用來對其一行。但是,改變flex-direction就可以做到縱向排列。
html
<ul class="waterfall"> <li class="item"><img src="1.jpg"></li> <li class="item"><img src="2.jpg"></li> <li class="item"><img src="3.jpg"></li> <li class="item"><img src="4.jpg"></li> <li class="item"><img src="5.jpg"></li> <li class="item"><img src="6.jpg"></li> <li class="item"><img src="7.jpg"></li> <li class="item"><img src="8.jpg"></li> <li class="item"><img src="9.jpg"></li> <li class="item"><img src="10.jpg"></li> </ul>
css
.waterfall{ /*flex-box*/ display: flex; /*縱向排列*/ flex-direction: column; /*換列*/ flex-wrap: wrap; height: 100vh; } .waterfall .item{ width:50%; }
注:
1、flex-wrap: wrap 是為了讓item撐滿waterfall的時候換列(可以理解為換行)
2、這里waterfall的height一定要寫,否則,waterfall隨著內容變多,不斷撐高也不會換列。
3、waterfall的height要隨著item的數量變化而變化,否則,一列顯示不了就顯示兩列,兩列顯示不了就顯示三列,為了維持固定的列數,只能不斷升高waterfall的高度。
4、flex-direction: column和flex-wrap: wrap可以合并為flex-flow: column wrap;
5、與前面兩種方法一樣,這種方法仍然是不好解決從上往下排列而非從左往右排列的問題。
總結:純CSS實現瀑布流,總有這樣或那樣的問題,最終還是要通過js來控制。如果對排序沒有要求的話,第二種方法還是比較好用的。純css實現瀑布流,大家還有什么好的方法,歡迎留言評論。關注IT學堂,會有更多驚喜哦!
我自己是一名從事了多年開發的web前端老程序員,目前辭職在做自己的web前端私人定制課程,今年我花了一個月整理了一份最適合2020年學習的web前端學習干貨,各種框架都有整理,送給每一位前端小伙伴,想要獲取的可以關注我的頭條號并在后臺私信我:前端,即可免費獲取。
使用demo
div { -ms-transform: rotate(0); -webkit-transform: rotate(0); -moz-transform: rotate(0); -o-transform: rotate(0); transform: rotate(0);}
CSS前綴自動補全:autoprefixer
已知: margin:20px; border:10px; padding:10px; width:200px; height:50px;

標準盒模型:1\. 占用寬:margin*2+padding*2+border*2+width=20*2+10*2+10*2+200=2802\. 占用高:margin*2+padding*2+border*2+height=20*2+10*2+10*2+50=1303\. 盒子實際寬度:padding*2+border*2+width=10*2+10*2+200=2404\. 盒子實際高度padding*2+border*2+height=10*2+10*2+50=90

怪異盒模型:1\. 占用寬:margin*2+width=20*2+200=2402\. 占用高:margin*2+height=20*2+50=903\. 盒子實際寬度:width=2004\. 盒子實際高度height=50
IE8及更早版本不兼容問題解決方案:在HTML頁面聲明
BFC(塊狀格式化上下文,獨立的盒子,布局不受外部影響,但是如果同一個BFC中,同級塊狀元素的margin-top和margin-bottom會重疊)
只要元素滿足下面的任一條件,都會觸發BFC特征。
解決問題:
元素被當成行內元素排版時,元素直接的空白符會被瀏覽器處理,根據white-spack的處理方式(默認是normal,合并多余空白),Html代碼在回車換行時被轉成一個空白符,在字體不為0的情況下,空白符占據一定寬度,所以inline-block元素之間就出現了空隙。
復現<ul> <li>首頁</li> <li>登陸</li> <li>資源</li> <li>社區</li> <li>幫助</li></ul>

解決辦法:

優先級相同時會發生什么? 樣式被覆蓋
normalize.css是一個css reset的替代方案。
ul>li:nth-child(2n+1) { background-color: red; }ul>li:nth-child(2n) { background-color: yellow;}
ul>li:first-child { border-top: none; }
有夢想的人,眼睛會發光。
希望屏幕前的你,能夠關注我一波。接下來,我會分享前端各種干貨,以及編程中的趣事。
天這篇文章我們開始詳細講解JS的事件。之前我們已經講過許多事件,而我們今天要講的主要是事件對象。之前我們學習的onclick事件用于得知一個元素是否被點擊,但如果我們想知道一些更詳細的信息,例如點擊位置,點擊鍵是左鍵還是右鍵,就需要用到event對象。又例如我們希望檢測用戶鍵盤按的到底是左鍵還是右鍵來完成相應的功能,也需要用到event對象。
event對象的作用是幫助我們獲取一些事件的信息,例如鼠標位置,鍵盤按鍵。這里我們用一個小例子來說明event對象是怎么運作的。現在我們試圖實現一個效果:無論點擊頁面的什么地方,都可以彈窗。聰明的同學可能已經猜到,我們可以直接給body添加onclick事件來實現這一點:
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8" /> <title>無標題文檔</title> <script>window.onload=function (){ document.body.onclick=function () { alert('a'); };}; </script> </head> <body> </body> </html>
但實際上你會發現,無論怎么點擊頁面都無法進行彈窗,這是為什么呢?現在我們對這個頁面改造一下:
<html> <head> <meta charset="utf-8" /> <title>無標題文檔</title> <script>window.onload=function (){ document.body.onclick=function () { alert('a'); };};</script> </head> <body style="border:1px solid black;"> <input type="button"value="aaa"> </body> </html>
可以看到的是,在body內沒有內容的時候,body頁面是撐不起來的(至少在ie下是這樣的),我們在頁面中加入了一個button后,body的大小也隨著button略微增大。當然我們可以從樣式角度去解決這個問題,但是我們現在從程序的角度考慮的話,應該怎么去解決他呢?其實很簡單,我們不選擇給body添加onclick事件而是直接給document添加就可以了:
window.onload=function (){ document.onclick=function () { alert('a'); }; };
效果如下:
這里body也沒有被撐起來,但是document代表的是整個網頁,因此可以通過點擊頁面任何地方彈窗。這里我們通過一個例子來講講document到底是什么東西。
window.onload=function (){ alert(document.childNodes[0].tagName); };
效果如下:
這里本應該打印出document第一個子節點的標簽名,但返回結果為undefined。順便大家可以用IE7測試一下,其返回結果會為一個感嘆號。聰明的同學應該可以猜到,感嘆號其實就是DOCTYPE聲明中的第一個字符,DOCTYPE聲明本身也是作為一個節點存在的。
實際上我們可以這么理解:在一個頁面里,DOCTYPE和html存在同一個父級,也就是document(一個看不見的虛擬節點),他包括了整個網頁的內容和網頁聲明。我們提了這么多關于document的知識,為的就是告訴大家一點:如果想給整個頁面添加事件,那么使用document一定比使用html好,因為html頁面是有可能撐不開的。回到我們的事件對象來。我們通過event對象可以獲取事件的信息,例如可以退獲取點擊的坐標:
window.onload=function (){ document.onclick=function (ev) { //IE //alert(event.clientX+','+event.clientY); //FF //alert(ev.clientX+','+ev.clientY); var oEvent=ev||event; alert(oEvent.clientX+','+oEvent.clientY); }; };
在ie瀏覽器下,直接通過event.clientX和event.clientY就可以獲取點擊的坐標,而在火狐下,event對象是不兼容的,需要給事件讀入一個參數(參數本身就是事件對象,由系統讀入),用這個參數來調用clientX和clientY屬性獲取坐標。而“var oEvent=ev||event;”這種寫法,系統會自動獲取為真的一邊,這樣就可以通過一句話完美解決兼容性的問題了。
說完事件對象后我們來看看事件流?事件流說的簡單一點,其實就是事件跟水一樣從頭到尾流動的過程。我們來看一個關于事件流的最簡單的小例子:
<!DOCTYPE HTML> <html onclick="alert('html');"> <head> <meta charset="utf-8"> <title>無標題文檔</title> <style> div {padding:100px;} </style> </head> <body onclick="alert('body');"> <div style="background:#CCC;" onclick="alert(this.style.background);"> <div style="background:green;" onclick="alert(this.style.background);"> <div style="background:red;" onclick="alert(this.style.background);"> </div> </div> </div> </body> </html>
效果如下:
當我們點擊最里面的一個div時,它會連續彈出多個框,原因大家應該都明白。這里,就涉及到了事件冒泡的知識——在這個程序里,當我們點擊了最里面的div并執行事件后,還會將這個事件傳遞給父級繼續執行,依次類推,直到html和document。這就是所謂的事件冒泡——事件會隨著層級依次傳遞到底。
事件冒泡學完以后大家更多的疑問肯定是,我們能用它來做點什么,畢竟學了任何知識都是拿來用的,而不是看的。一個小小的結論是:在我們平時做東西的時候,真正主動去利用時間冒泡去做的事情非常少,甚至可以說,很多時候事件冒泡都會給我們帶來煩惱腦。為什么這么說呢,下面我們來看一個小例子,立刻就能明白了。
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>無標題文檔</title> <style> #div1 {width:400px; height:300px; background:#CCC; display:none;} </style> <script> window.onload=function () { var oBtn=document.getElementById('btn1'); var oDiv=document.getElementById('div1'); oBtn.onclick=function (ev) { var oEvent=ev||event; oDiv.style.display='block'; //alert('按鈕被點擊了'); oEvent.cancelBubble=true; }; document.onclick=function () { oDiv.style.display='none'; //alert('document被點擊了'); }; }; </script> </head> <body> <input id="btn1" type="button" value="顯示" /> <div id="div1"> </div> </body> </html>
我們試想一下,我們想要實現一個功能:點擊頁面任意地方,都可以讓已經顯示的div塊隱藏,根據我們前面所學的知識,最好的方法應該是給document添加事件。但如果我們直接這么做的話,就會存在下面這個問題:我們在點擊按鈕的時候,這個事件也會被傳遞到其根元素document上,也就是說,點擊了按鈕后,會觸發兩個事件,div依然會被隱藏。取消冒泡的方式也是通過事件對象,在event對象里有一個屬性叫cancelBubble,當我們將它設置為true的時候,就可以取消該元素的事件冒泡了。
下面我們來說一下鼠標事件,之前說過了,clientX,clinentY可以獲取鼠標的坐標。不過,我們僅僅說它是鼠標的坐標,而并沒有說它是鼠標的什么坐標。現在我們來看一下clientX,clinentY有一些小問題。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>無標題文檔</title> <style> #div1 {width:200px; height:200px; background:red; position:absolute;} </style> <script> document.onmousemove=function (ev) { var oEvent=ev||event; var oDiv=document.getElementById('div1'); oDiv.style.left=oEvent.clientX+'px'; oDiv.style.top=oEvent.clientY+'px'; };</script> </head> <body> <div id="div1"> </div> </body> </html>
效果如下:
我們讓div1坐標就等于鼠標的當前坐標,可以看到我們實現了一個div隨著鼠標移動的效果。但這個程序存在一個小小的隱患——例如,現在如果我們把body的高度設置為2000px,會發生什么呢?實際上,無論是clientX還是clientY,它們代表的實際含義都是可視區坐標,而div則是根據body來定位的,所以當可視區并不在頁面頂端時,必然會出現鼠標和div之間的錯位。這里,我們可以使用scrollTop來解決這個問題。
<html> <head> <meta charset="utf-8"> <title>無標題文檔</title> <style> #div1 {width:200px; height:200px; background:red; position:absolute;} </style> <script> document.onmousemove=function (ev){ var oEvent=ev||event; var oDiv=document.getElementById('div1'); var scrollTop=document.documentElement.scrollTop||document.body.scrollTop; oDiv.style.left=oEvent.clientX+'px'; oDiv.style.top=oEvent.clientY+scrollTop+'px'; }; </script> </head> <body style="height:2000px;"> <div id="div1"></div> </body> </html>
這樣,無論是否滾動頁面,都不會出現錯位的問題了(不過會出現div抖動的情況,我們以后會有方法解決)。一個小小的經驗是:但凡是你用到clientX,clientY的時候一定要加上scrollLeft或者scrollTop,否則很容易出問題。
現在我們來看一下其另一個例子(這里我們將scroll封裝成一個函數getPos。
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>無標題文檔</title> <style> div {width:10px; height:10px; background:red; position:absolute;} </style> <script> function getPos(ev){ var scrollTop=document.documentElement.scrollTop||document.body.scrollTop; var scrollLeft=document.documentElement.scrollLeft||document.body.scrollLeft; return {x: ev.clientX+scrollLeft, y: ev.clientY+scrollTop};}document.onmousemove=function (ev){ var aDiv=document.getElementsByTagName('div'); var oEvent=ev||event; var pos=getPos(oEvent); for(var i=aDiv.length-1;i>0;i--) { aDiv[i].style.left=aDiv[i-1].offsetLeft+'px'; aDiv[i].style.top=aDiv[i-1].offsetTop+'px'; } aDiv[0].style.left=pos.x+'px'; aDiv[0].style.top=pos.y+'px'; }; </script> </head> <body><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div> </body> </html>
效果如下:
這里制作出了一串div跟隨著鼠標走的特效。我們讓后一個div都跟著前一個div走,第一個div跟著鼠標走,就可以實現這種效果了。
說完鼠標事件之后,我們來看看鍵盤事件。通過keyCode,我們可以獲取用戶操作的是哪個按鍵。這里我們需要介紹兩個新事件:onkeydown和onkeyup,分別代表按下鍵盤按鍵和放開鍵盤按鍵的事件。
這里通過一個小例子來說明他們是怎么用的:
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>無標題文檔</title> <script> document.onkeydown=function (ev) { var oEvent=ev||event; alert(oEvent.keyCode); }; </script> </head> <body> </body> </html>
可以看到的是,我們輸入一個鍵盤按鍵后,頁面會彈出一個數字,實際上鍵盤幾乎每個按鍵都有對應的keyCode,因此keyCode可以很好地為我們檢測用戶按的是哪個鍵。現在我們來看一個通過keyCode用鍵盤控制div的移動的小例子:
<html> <head> <meta charset="utf-8"> <title>無標題文檔</title> <style> #div1 {width:100px; height:100px; background:#CCC; position:absolute;} </style> <script> document.onkeydown=function (ev) { var oEvent=ev||event; var oDiv=document.getElementById('div1'); if(oEvent.keyCode==37) { oDiv.style.left=oDiv.offsetLeft-10+'px'; } else if(oEvent.keyCode==39) { oDiv.style.left=oDiv.offsetLeft+10+'px'; } }; </script> </head> <body> <div id="div1"></div> </body> </html>
值得注意的一點是,如果我們按住一個方向鍵不動,可以看到div塊會先定住一會兒,然后才開始移動(實際上我們平時打字的時候也是這樣),這里給大家留一個懸念,大家可以自己思考一下如何解決這個問題。除了keyCode外,JS鍵盤事件還有幾個屬性:ctrlKey,altKey,shiftKey等。我們在論壇或微博經常可以看到ctrl+回車提交留言的功能,就是通過這些屬性完成的:
<!DOCTYPE HTML><html> <head> <meta charset="utf-8"> <title>無標題文檔</title> <script> window.onload=function () { var oTxt1=document.getElementById('txt1'); var oTxt2=document.getElementById('txt2'); oTxt1.onkeydown=function (ev) { var oEvent=ev||event; if(oEvent.keyCode==13 && oEvent.ctrlKey) { oTxt2.value+=oTxt1.value+'\n'; oTxt1.value=''; } }; }; </script> </head> <body> <input id="txt1" type="text" /><br> <textarea id="txt2" rows="10" cols="40"></textarea> </body> </html>
oEvent.keyCode==13 && oEvent.ctrlKey代表的就是在按回車的同時按住ctrl鍵——這樣,我們就完成了一個ctrl+回車提交的功能。從下節課我們會講一些事件更加復雜,更加高級一些的應用。
我是石川(Blue),如果你覺得我的公眾號還不錯,請多幫我推薦給你的朋友,多謝了。
作者簡介:前阿里巴巴高級技術經理,現開課吧技術學院院長。精通C/C++、Java、Python、前端開發等多種開發技術,曾參與淘寶網的早期建設和優化,擁有豐富的企業級系統開發經驗,對HTML5移動端互聯網技術及生態體系有深厚的造詣。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。