使用純 CSS 實現 500px 照片列表布局

使用純 CSS 實現 500px 照片列表布局

文章很長,因為介紹了如何一步一步進化到最后接近完美的效果的,不想讀的同學可以直接跳到最后一個大標題之后看代碼、demo 及原理就好,或者也可以直接看下面這個鏈接的源代碼。不過還是建議順序讀下去,因為后面的原理需要前面的內容做為鋪墊,主要是在處理邊角問題上。

先看下效果,要不然各位可能沒動力讀下去了,實在是有點長,可以試著 resize 或者 zoom 一下看看動態效果:Cats

PS:文中的一些 demo 為了方便展示源代碼用了 jsbin,但 jsbin 偶爾抽風會顯示不出效果,試著在源代碼編輯框里不改變代碼意思的情況下編輯一下(比如在最后打一下回車)應該就可以了,或者查看一下你瀏覽器的翻墻設置,因為里面引入了 Google CDN 上的文件,有可能是因為 js 加載不成功導致的。

PS2:Demo 中用到的所有圖片都來自http://500px.com網站,圖片版權歸原作者所有。圖片地址末尾的數字即為其在http://500px.com上的 id,如果你喜歡某張圖片,可以通過https://500px.com/photo/[id]/ 這個地址訪問到圖片原始頁面。

好了,正文開始。

開始之前,先對比一下三種比較常見的圖片布局的差異

花瓣

此種布局為比較常見的等寬布局,所有圖片的寬度是一樣的

由于圖片是等比拉伸(等比拉伸的意思是圖片的寬和高變化相同的比例,也就是圖片展示的寬高比與原始寬高比一致),而每張圖片的寬度又是一樣的,所以圖片的高度就必然不一樣了

這種布局的缺點是,由于每張圖片展示的高度的不一致,圖片不是按一般的閱讀順序展示的,因為可能連續的多張圖片頂部的高度不一樣,而人眼又習慣于水平掃描,所以用戶就有可能漏看某些照片

圖片瀑布的底部一般是對不齊的

雖然底部很難完全對齊,但使用 JS 對圖片順序進行重排能夠讓底部盡量對齊,所以此種布局在 reflow 的時候(比如resize,zoom)必然要有 JS 的參與

Google Photos,500px,圖蟲等,以 Google Photos 為代表的即不等寬也不等高的圖片布局有如下特點:

圖片也沒有被非等比拉伸

每行的圖片在水平方向上也占滿了屏幕,沒有多余的空白

因為以上兩個條件,所以每行的圖片高度必然會不一樣,否則無法做到圖片在水平方向上占滿屏幕

圖片是按順序展示的,比較符合人眼閱讀順序,Google Photos 因為照片有拍攝時間這個屬性,必須滿足這個條件

底部是對齊的

Google Photos 的布局中,當某幾個日期的照片太少時,多個日期的照片會合并展示在同一行,當然這不是本文討論的重點

Instagram

正方形圖片布局,就不多說了~

以上介紹的前兩種布局都有一個共同點,那就是圖片沒有經過非等比拉伸,也就是說圖片里的內容沒有變形,也沒有被裁剪,只是放大或者縮小,這是目前圖片類應用在展示圖片上的一個趨勢,應該說,很少有專做圖片的網站會把照片非等比拉伸顯示(變形拉伸真的給人一種殺馬特的感覺…),最次的展示方式也就是把圖片裁剪成正方形后展示在一個正方形的區域里,類似于正方形容器的 background-size: cover; 的效果。

另外,在花瓣的布局中,比較寬的圖片展示區域會比較小;而在第二種布局中,則是比較高的圖片展示區域會比較小。

但是,在第一種布局中,因為寬度是定死了的,所以高寬比小到一定程度的圖片,顯示區域會非常小。而在第二種布局中,因為不同行的高度是不一樣的,如果比較高的圖片出現在比較高的行,還是有可能展示的稍大些的。

總體來說,以 Google Photos 為代表的圖片布局,在顯示效果上更優。關于如何使用 JS 來完成 Google Photos / 500px 布局的算法,這里就不討論了,讀者可以自己思考一下~

思考完成后可以看看這個頁面對這個布局的動態演示,打開頁面,等圖片全部加載完成后點擊頁面頂部的 layout 按鈕。

Demo 演示了如下的布局方式:先按照相同的高度把圖片排列起來,然后按行對每行的圖片進行等比放大,放大到當前行的所有圖片正好跟容器兩邊對齊,布局完成。

OK,下面根據上面的分析稍微總結一下評判圖片布局優劣的一些標準:

是否能盡量按原始列表中的順序輸出

能否按人眼的掃描順序輸出,即行高相同

圖片能否按照原始比例展示,或者盡量按原始比例展示

每張圖片的展示面積能否盡量接近,實際上在想完全展示照片的布局中,這一條是很難達成的

圖片不被非等比拉伸,內容不變形,內容展示完全

第一次看到類似 Google Photos 照片列表的布局已經不記得是在哪里了,當時只是覺得這種布局肯定需要 JS 參與,因為每行圖片高度相同的情況下不可能那么恰到好處的在容器兩端對齊,且所有圖片之間的間距大小也一樣(如果間距大小不一樣但兩端對齊,可以使用 inline 的圖片加上 text-justify 來實現,在圖片較小的時候(比如搜索引擎的圖片結果)也不失為一種選擇)。然而通過觀察,發現每行的高度并不相同,就確認了必然需要 JS 參與才能完成那樣的布局。

然而當越來越多的開始網站使用這樣的布局時,做為一個熱衷于能用 CSS 實現就不用 JS 的前端工程師,我就在考慮,能否僅用 CSS 實現這樣的布局呢?尤其是不要在 resize 時重新計算布局。

在經過一些嘗試后,我發現可在一定程度上用純 CSS 實現類似的布局。這里說的一定程度上僅使用 CSS 實現布局,我的意思是:布局一但渲染完成,布局后序的 resize,zoom 都可以在沒有 JS 參與的情況下保持穩定,也就是說,首次的渲染甚至可以通過服務器完成,整個過程可以沒有 JS 參與,所以說成是用純 CSS 實現也不過分。

實現過程

下面就來介紹一下我是如何只通過 CSS 一步一步實現的這個布局的:

一開始,我們將圖片設置為相同的高度:

img{height:200px;}

這樣并不能讓圖片在水平方向上占滿窗口,于是我想到了 flex-grow 這個屬性,讓 img 元素在水平方向變大占滿容器,整個布局也變成了 flex 的了:

div{display:flex;flex-wrap:wrap;}img{height:200px;flex-grow:1;}

把 flex container 的 flex-wrap 設置為 wrap,這樣一行放不下時會自動折行,每行的圖片因為 grow 的關系會在水平方向上占滿屏幕,效果看上去已經很接近我們想要的了,但每張圖片都會有不同程度的非等比拉伸,圖片的內容會變形,這個好辦,可以用 object-fit: cover; 來解決,但這么一來圖片又會被裁剪一部分。

最終demo

注意圖片都被裁剪了,尤其第一張。

不過上述的 DOM 結構顯然是沒辦法在實際中使用的:

不支持 object-fit 的瀏覽器下圖片會變形,因為圖片沒有容器,所以也沒辦法用 background-size: cover; 來解決這個問題

用了 object-fit 的瀏覽器下,圖片會被裁剪一部分,這兩條前面已經說過

沒辦法跟圖片一起展示一些相關的信息,因為 img 是裸標簽

另外就是在真實的網絡環境中,圖片的加載都是比較緩慢的,如果指望用圖片自己的尺寸來把布局撐開,用戶肯定會看到非常多的閃爍,demo 里的閃爍應該也已經非常明顯了

所以我們上面的這個布局事實上是沒辦法用于任何生產環境的。

為 img 標簽增加父元素

接下來我們把 DOM 結構改成下面這樣的:

我們為圖片增加了一個容器。依然把圖片設置為定高,如此一來,每個 div 將被圖片撐大,這時如果我們給 div 設置一個 flex-grow: 1; ,每個 div 將平分每行剩余的空間,div 會變寬,于是圖片寬度并沒有占滿 div。

如果我們將 img 的 width 設置為 100% 的話,在 IE 和 Firefox 下,div 已經 grow 的空間將不會重新分配(我覺得這是個很有意思的現象,圖片先把 div 撐大,div grow 之后又把圖片拉大),但在 Chrome 下,為 img 設置了 width: 100%; 之后,grow 的空間將被重新分配(我并沒有深究具體是如何重新分配的),重新分配后的結果是每個容器的寬度更加接近,這并不是我們想要的。

試了幾種樣式組合后,我發現把 img 標簽的 min-width 和 max-width 都設置為 100% 的話,在 Chrome 下的顯示效果就跟 IE 和 Firefox 一樣了。最后我們將 img 的 object-fit 屬性設置為 cover,圖片就被等比拉伸并占滿容器了,不過與前一種布局一樣,每行的高度是一樣的,另外圖片只顯示了一部分,上下兩邊都被裁剪掉了一些。

上面布局完整的demo

看起來跟前一個布局沒什么兩樣,但是現在我們可以在容器內部加上一些額外的標簽來顯示圖片信息了。

在這種布局下,如果圖片高度設置的比較小,布局已經沒有什么大礙,因為圖片越小就意味著每行的圖片越多而且剩余的空間越小并且剩余空間被更多的圖片瓜分,那每個容器的寬高比就越接近圖片的真實寬高比,多數圖片都能顯示出其主要部分。

棘手的最后一行

唯一的問題是最后一行,當最后一行圖片太少的時候,比如只有一張,因為 grow 的關系,它將占滿一整行,而高度又只有我們設置的 200px,這時圖片被展示出來的部分可能是非常少的,更不用說如果圖片本身上比較高,而展示區域又比較寬的情況了。

針對這種情況,我們可以讓列表最后的幾張圖片不 grow,這樣就不至于出現太大的變形,我們可以算出每行的平均圖片數量,然后用下面的 CSS 阻止“最后一行”的圖片 grow:

div:nth-last-child(5),div:nth-last-child(4),div:nth-last-child(3),div:nth-last-child(2),div:nth-last-child(1){flex-grow:0;}

然后配合 media query,在屏幕不同寬度時,讓“最后一行”的元素個數在窗口寬度變化時也動態變化:

@media(max-width:1000px)and(min-width:900px){div:nth-last-child(5),div:nth-last-child(4),div:nth-last-child(3),div:nth-last-child(2),div:nth-last-child(1){flex-grow:0;}}@media(max-width:1100px)and(min-width:1000px){div:nth-last-child(7),div:nth-last-child(6),div:nth-last-child(5),div:nth-last-child(4),div:nth-last-child(3),div:nth-last-child(2),div:nth-last-child(1){flex-grow:0;}}

上面的代碼寫起來是相當麻煩的,因為每個屏幕寬度范圍內又要寫多個 nth-last-child 選擇器,雖然我們可以用預處理器來循環迭代出這些代碼,但最終生成出來的代碼還是有不少重復。

有沒有辦法只指定最后多少個元素就行了,而不是寫若干個 nth-last-child 選擇器呢?其實辦法也是有的,想必大家應該還記得 CSS 的 ~ 操作符吧,a ~ b 將選擇在 a 后面且跟 a 同輩的所有匹配 b 的元素,于是我們可以這么寫:

div:nth-last-child(8),div:nth-last-child(8) ~ div {? flex-grow: 0;}

先選中倒數第 8 個元素,然后選中倒數第 8 個元素后面的所有同輩結點,這樣,就選中了最后的 8 個元素,進一步,我們可以直接將選擇器改寫為 div:nth-last-child(9) ~ div,就可以只用一個選擇器選擇最后的 8 個元素了。

上面的幾種選擇尾部若干元素的不同選擇器,實際上效果是不太一樣的:

div:nth-last-child(1),...,div:nth-last-child(n) 的選擇方法能保證倒數的 n 張圖片一定被選中,即使元素總個數不到 n

div:nth-last-child(n), div:nth-last-child(n) ~ div 只能保證當 div 元素至少有 n 個時才能選中最后的 n 個元素,因為如果 :nth-last-child(n) 不存在,這個選擇器就無效了

div:nth-last-child(n+1) ~ div 則需要保證 div 元素至少有 n+1 個時才能選中最后的 n 個元素,原理同上

選擇最后若干張圖片這種方式還是不夠完美,因為你無法確定你選擇的 flex item 一定在最后一行,萬一最后一行只有一張圖片呢,這時倒數第二行的前幾張圖片就會 grow 的很厲害(因為倒數第二行的后面 n-1 張都不 grow),或者最后兩行圖片的數量都沒有這么多,那倒數第二行就沒有元素 grow 了,就占不滿這一行了,布局就會錯亂。

那么有沒有辦法只讓最后一行的元素不 grow 呢?一開始我也了很多方法,甚至在想有沒有一個 :last-line 偽類什么的(因為有個 :first-line),始終沒有找到能讓最后一行不 grow 的方法,然而最后竟然在搜索一個其它話題時找到了辦法:

那就是在最后一個元素的后面再加一個元素,讓其 flex-grow 為一個非常大的值比如說 999999999,這樣最后一行的剩余空間就基本全被這一個元素的 grow 占掉了,其它元素相當于沒有 grow,更進一步,我們可以用偽元素來做這件事(不過 IE 瀏覽器的偽元素是不支持 Flexbox 屬性的,所以還是得用一個真實的元素做 placeholder):

section::after{content:'';flex-grow:999999999;}

到這里,我們基本解決這個布局遇到的所有問題。

Demo,resize 或者 zoom 然后觀察最后一行的圖片。

現在這種布局下最后一行的圖片其實總是顯示完全且沒有拉伸和變形的。

但還有最后一個問題,同前一種布局一樣,如果你在線上去加載使用這種方式布局的網頁,你會發現頁面閃動非常厲害,因為圖片在下載之前是不知道寬高的,我們并不能指望圖片加載完成后讓它把容器撐大,用戶會被閃瞎眼。其實真正被閃瞎的可能是我們自己,畢竟開發時要刷新一萬零八百遍。

所以,我們必須預先渲染出圖片的展示區域(實際上幾乎所有圖片類網站都是這么做的),所以這里還是要小用一些 js,這些工作也可以在服務器端做,或者是用任何一個模板引擎(下面的代碼使用了 angular 的模板語法)。

這個布局一旦吐出來,后續對頁面所有的動作(resize,zoom)都不會使布局錯亂,同時也不需要 JS 參與,符合前文所說的用純 CSS 實現:

section{padding:2px;display:flex;flex-wrap:wrap;&::after{//處理最后一行content:'';flex-grow:999999999;}}div{margin:2px;position:relative;height:200px;flex-grow:1;background-color:violet;img{max-width:100%;min-width:100%;height:200px;object-fit:cover;vertical-align:bottom;}}// 下一行的**表達式**是計算當圖片以 200 的高度等比拉伸展示時寬度的值

我們給圖片的父容器設置與圖片比例相同的初始大小,然后為它設置 flex-grow: 1; 等待它 grow,最終的效果將與上面種布局是一樣的,但可以看到圖片在加載過程中布局是沒有抖動的:

到這里,我們總算實現了圖片的非等寬布局。Demo,注意 HTML 模板里計算寬度的表達式。

那么這個布局的展示效果究竟如何呢?

實際上我專門寫了代碼計算每張圖片被展示出來的比例到底有多少:在圖片高度為 150px 左右時,約有三分之一的圖片展示比例在 99% 以上。最差的圖片展示比例一般在 70% 左右浮動,平均每張圖片展示比例在 90% 以上。圖片越矮/屏幕越大,展示效果會越好;圖片越高/屏幕越小,展示效果就越差。

因為這種方案最后也被我拋棄了,所以就不放計算展示比例的 demo 了。

看到這里,你應該是覺得被坑了,因為這并沒有實現標題中說的 Google Photos / 500px 照片列表的布局

因為每行的高度是一樣的,就必然導致大部分圖片沒有完全展示,跟 Google Photos / 500px 那些高大上的布局根本就不一樣!

其實正文從現在才正式開始,下面介紹的方式也是我在實現了上面的布局后很久才想出來的,前面的內容只是介紹一些解決邊角問題用的。

可以看到,前面的實現方式并沒有讓每張圖片的內容全部都顯示出來,因為每行的高度是一樣的,而想要實現 500px 的布局,每行圖片的高度很多時候是不一樣的。

一開始我覺得,CSS 也就只能實現到這種程度了吧,直到我遇到了另一個需求:

我想用一個正方形的容器展示內容,并且希望無論瀏覽器窗口多寬,這些正方形的容器大小在一個范圍內并且總是能鋪滿窗口的水平寬度而不留多余的空間(除了元素之間的空白),乍一看這個需求可能需要 JS 參與:讀出當前瀏覽器窗口的寬度,然后計算正方形容器的 size,然后渲染。

可以看這個demo,試著拉動一下窗口寬度然后看效果。

拉動過程中可以看到,正方形的容器會實時變大,大到一定程度后又變小讓每行多出一個正方形容器。 如果只看這一個 demo,可能各位不一定能一下子想到如何實現的,但如果只有一個正方形容器,它的邊長總是瀏覽器寬度的一半,想必很多人都知道的,長寬比固定的容器要怎么實現吧?

我們知道(事實上很多人都不確定,所以這可以做為一個面試題),margin 和 padding 的值如果取為百分比的話,這個百分比是相對于父元素的寬度的,也就是說,如果我給一個 block 元素設置 padding-bottom(當然,也完全可以是 padding-top,甚至可以兩個一起用)為 100% 的話,元素本身高度指定為 0,那么這個元素將始終是一個正方形(因為它的高度總是跟父元素的寬度一樣,而寬度 100% 也跟父元素的寬度一樣),并且會隨著容器寬度的變化而變化,想要改變正方形的大小,只需要改變父容器的寬度就可以了:

看這個demo,拉動窗口可以看到色塊會變大,但始終保持正方形。當然,如果參照物是瀏覽器窗口,那么在現代瀏覽器中,這個效果可以用 vw / vh 實現;但如果參照物不是瀏覽器窗口,就只能用垂直 padding 來實現了。

于是我就想到,如果不給 flex item 的元素設置高度,而是讓其被一個子元素撐開,并且這個子元素的寬度是100%,padding-bottom 也是 100%,那么 flex item 以及這個用來撐大父元素的子元素就會同時保持為正方形了,于是就實現了上面的那種正方形陣列布局。

但僅僅這樣還不夠,最后一行又會出問題,如果最后一行的元素個數跟前面的行不一樣的話,它們雖然會保持正方形,但是因為 grow 的關系,會比較大,那如何保證最后一行的元素也跟前面的行大小相同呢,這時使用一個元素并設置很大的 flex-grow 讓其占滿最后一行剩余空間的做法已經不可行了,因為我們需要讓最后一行的元素恰到好處的跟前面行的元素 grow 時多出一樣的空間。

其實解決方案也很簡單,把最后一行不當最后一行就行了!此話怎講呢?

在最后添加多個占位符,保證可見的最后一個元素永遠處于視覺上的最后一行,而讓占位符占據真正的最后一行,然后把這些占位符的高度設置為 0 。具體添加多少個占位符呢?顯然是一行最多能顯示多少個元素,就添加多少個了,比如前面的 demo 就添加了 8 個占位符,你可以在源代碼里面看一下。另外為了更好的語義,其實可以用其它的標簽當做占位符,這樣就不用寫出上面那種晦澀的選擇器了。

這樣一來,始終能占滿水平寬度的正方形陣列布局也實現了。

本來我以為,到這里就結束了,即使用上最先進的 Flexbox 布局,CSS 也無法實現圖片不裁減不拉伸且對齊的完美布局。

- FAKE EOF -

4 月 2 號的早上我醒來的時候,突然想到,既然可以讓一個容器始終保持正方形,那豈不是也可以讓這個容器始終保持任何比例?顯然是可以的,只要我們把用于撐大父元素的那個元素的 padding-bottom 設置為一個我們想要的值就可以了!這樣一來,說不定可以實現圖片布局中,所有圖片都完全展示且占滿水平寬度的布局(也就是 Google Photos / 500px 的布局)!

當然,前面提到過,由于圖片加載緩慢,圖片布局方案往往都會提前知道圖片的寬高來進行容器的預渲染,然后圖片加載完成后直接放進去。

所以這里我們仍然需要用 JS 或者服務器來計算一下圖片的寬高比例,然后設置到 padding-bottom 上面去,以保證容器的寬高比始終是其內部圖片的寬高比。

我們先讓所有圖片以 200px 的高度展示,寫出如下模板代碼:

這個公式計算了圖片高度為 200 時的寬度的值上面這個公式讓此元素及其父元素的比例與圖片原始比例相同,因為是垂直方向的 padding,所以是高度除以寬度,又因為是百分比,所以除以 100

在上面布局中,因為 flex-wrap 的關系,每一行不夠放的時候后面的內容就會折行,并且留出一些空白,每個容器的寬高比都是跟未來放入其內部的圖片的寬高比是一樣的,為了便于展示,我將圖片大小設置為容器大小的四分之一,應該明顯可以看出圖片的右下角處于容器的中心位置。

Demo

下一步,我們只需要讓所有的容器元素都 grow 就可以了,那么是把所有的元素的 flex-grow 設置為 1 嗎?

實際上如果設置了并看了效果,我們會發現并不是,因為我們希望每行元素在 grow 的時候,保持原有比例且高度相同。

Demo

可以看到如果給所有的 flex item 設置 flex-grow: 1; 的話,容器跟圖片的比例并不一致(雖然比較接近),這里我將圖片寬度設置了為容器的寬度以便觀察。

通過一些簡單的計算我們會發現,在每行的圖片中,每張圖片在水平方向上占用的寬度正好是其寬度在這一行所有圖片寬度之和中所占的比例

在前面不 grow 的情況下,每張圖片的容器的寬度已經是按比例分配了,而想要實現前一行描述的分配方式,每行的剩余空間,我們希望它仍然按照目前容器寬度所占的比例來分配,于是,每個容器的 grow 的值,正好就是它的寬度,只不過不要 px 這個單位。

最終的代碼如下:

flex,wrap? //實際上因為 flex-grow 是按比例分配,所以第二個公式里的 *200 可以不要,這要我們就只需要改前一個 200 了?



這樣一來,容器會占滿當前行,并且保持與未來內部所放入的圖片相同的寬高比:

Demo,可以看到,每張圖片都被完整展示出來了:

至于最后一行怎么處理,前面已經介紹過了,用一個 flex-grow 極大的元素占滿剩余空間就可以了。

這種布局在渲染完成后,你可以放心的 resize 和 zoom,布局都不會錯亂,而且沒有 JS 的參與。

到這里,我們終于實現了類似 Google Photos / 500px 網站的圖片布局。

總結一下這個方案的原理

padding(以及 margin)為百分比時是以容器的寬度為參照的

使用 flex-grow 來按圖片寬度所占的比例分配水平空間

使用寬高比固定的子元素撐大帶有指定比例 flex-grow 的 flex item 以實現不同行高度不一樣并保持寬高比

這種布局的優點:

不需要特殊的算法去計算每張圖片渲染之后的寬高等信息

不需要在 resize,room 時重新計算布局

CSS 的方案容易跟任何框架集成

最后說一下這種方案的一些缺點:

很明顯,我們只能指定每行圖片的最低高度,然后等著它 grow,并沒有辦法指定每行高度的上限是多少。雖然我們可以設置一下容器的 max-height,這樣一來被 max-height 影響的那些容器里面的圖片就展示不完全了。實際上只要圖片的比例都在一個正常的范圍,是不會出現某一行的高度過高的

在遇到比例超出某個范圍的圖片時可以只用我們允許的最大比例展示這張圖片,比如說遇到了一張 1:5 的圖片,我們只以 1:3 的區域來展示它。或者也可以調整一下圖片的順序,但這就需要 JS 參與了。500px 的這個搜索結果頁面貌似就是這么做的,試著把窗口寬度調小,會發現第一張后面的圖片展示不完全,因為如果展示完全的話,單張圖片就占用了太大的屏幕面積,所以它限定了高度。

另外,最后一行的圖片如果幾乎要占滿那一行時,因為占位符的存在,并不會占滿,會顯得不太理想(讀者可以調整窗口寬度觀察上面的完整 demo)。這種情況如果是使用 JS 計算的話,是可以避免的:在發現最后一行幾乎要占滿時,直接讓其占滿最后一行。其實這個情況在后來我也想到了解決方案,即還是在最后放上占位符,各位可以查看文章最開始的 demo 中的源代碼就知道了,如果不理解,可以留言討論。

我們在提到評價圖片布局優劣的標準時候說到,每張圖片展示區域越接近,評分應該也越高。理論上如果使用 JS 來計算布局,可以在算法上做如下優化:如果一行中比較高的圖片比較多,那么這一行就少放些圖片,留出更多的空間用來放大圖片,這樣就能讓高圖和寬圖顯示面積更接近一些了。而用 CSS 的方案如果不改變圖片順序就沒法做這種優化了。不過如果不改變圖片順序,即使算法做了這些優化,出現在高圖比較多的行里的寬圖,展示面積會更大,會出現一種比例失調的情況,也不夠完美。

關于降級

由于 IE 9 都是不支持 Flexbox 的,所以這個方案必然需要優雅降級。在不支持的瀏覽器上,讓圖片都以正方形展示應該也不會太差,然后用 float 或者 inline-block 來折行,這里就不細說了。

最后,本文其實只實現了 500px 的圖片的布局(即所有圖片在一個容器里),實際上并沒有實現 Google Photos 的布局,Google Photos 的布局比 500px 的還要復雜很多,仔細觀察就會發現,其是按日期排列并且不同日期在同一行顯示的時候也可以兩邊對齊,這種布局后來我也有了純 CSS 的解決方案。如果各位意猶未盡,可以在文后留言,我會將實現方案再整理一篇文章出來~

本文到此結束,謝謝圍觀!文中如有紕漏之處,還請各位大神留言指正~

最后的最后,廣告時間:

本人決定創業開辦前端培訓班,地點杭州,9月20左右開課,費用優惠包住宿,詳情請點擊我的專欄文章:大喵教育前端培訓 - 介紹,如果有朋友想學,歡迎介紹。如果沒有也希望你能進去點個贊讓更多人看到~寫文章不易,創業更不易~先行謝過了!

我叫謝然,貓奴,網名充電大喵,曾先后就職于省重點高中、阿里巴巴、小米。2016 年 9 月離開小米創建了自己的前端培訓品牌“大喵教育前端培訓”,第一期班于 2016 年 9 月 22 日順利開班,目前課程一切順利;第二期班將于 2017 年 3 月中旬開課,地點杭州下沙。大喵教育前端培訓勵志辦靠譜的前端培訓,重視基礎,開設算法、數據結構、計算機網絡等相關課程,并且部分課程使用英文授課,我的目標就是利用自己的專業技術在五個月的時間內踏踏實實的把該教的內容教給學員,不坑爹,不造假。如果你有興趣了解,請點擊:大喵教育前端培訓 - 介紹

「真誠贊賞,手留余香」

2人贊賞了4

CSS 布局500pxGoogle 相冊

383

收藏

分享

編輯

文章被以下專欄收錄

前端雜貨鋪

關注前端,不浮躁,不迂腐,踏踏實實。

進入專欄

前端外刊評論

關注前端前沿技術,探尋業界深邃思想 qianduan.guru

進入專欄

49 條評論

寫下你的評論...

沈振宇

我是圖蟲的創始人,有興趣可以知乎私信聊一下

1 年前

查看對話

謝然(作者)回復沈振宇

搬知乎來半個月,終于有了第一條評論,沒想到竟然是…我私信你…

6贊

1 年前

木亦

css魔法。。。

1 年前

Zimmer

馬克一下

1 年前

Zimmer

馬克一下

1 年前

孫飛

寫的真好!,希望出下一篇文章

1 年前

查看對話

謝然(作者)回復孫飛

會的~

1 年前

辛時雨

純 CSS 我們怎么能不滋瓷

2贊

1 年前

learnshare

Instangram -> Instagram :)

1 年前

張曉樣

辛苦

1 年前

12345下一頁

推薦閱讀

阿斯塔納:世博會開幕,就在這座草原上崛起的超現實主義之城

我們在日出之時抵達阿斯塔納,初升的太陽照耀在一望無際的大平原上,視野中的天際線浮現出一…查看全文

Luna Li

1 個月前

編輯精選發表于兩個瘋子的亞歐見聞

撤銷企業登記等行政許可,是糾正違法行為,不屬行政處罰!

撤銷企業登記等行政許可,是糾正違法行為,不屬行政處罰! 黃璞琳 (歡迎點擊訂閱“璞琳說…查看全文

黃璞琳

1 個月前

編輯精選發表于璞琳說法

汽車品牌相愛相殺,多年前他們都是一家人,今天我們聊保時捷和戴姆勒

克萊斯勒的創始人曾經是別克品牌的總經理;戴姆勒創世人的兒子保羅戴姆勒曾經是奧迪(Horch…查看全文

王洪浩

13 天前

編輯精選

探路二次元|在荊棘坎坷中成長的中國配音演員

本文由 @ 微博動漫 授權轉載。序 近幾年,隨著國產動畫關注度的提高,諸如“《狐妖小紅娘》…查看全文

下水道撈魚小分隊

1 個月前

編輯精選發表于隊長的撈魚筆記

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 13,800評論 1 92
  • H5移動端知識點總結 閱讀目錄 移動開發基本知識點 calc基本用法 box-sizing的理解及使用 理解dis...
    Mx勇閱讀 4,625評論 0 26
  • 移動開發基本知識點 一.使用rem作為單位 html { font-size: 100px; } @media(m...
    橫沖直撞666閱讀 3,514評論 0 6
  • CSS 3中彈性盒布局的最新版概述 在CSS 3中,CSS Flexible Box模塊為一個非常重要的模塊,該模...
    吾名無雙閱讀 1,248評論 0 5
  • 前言 溫馨提示:本文較長,圖片較多,本來是想寫一篇 CSS 布局方式的,但是奈何 CSS 布局方式種類太多并且實現...
    sunshine小小倩閱讀 3,173評論 0 59