[譯] CSS Grid 之列寬自適應:`auto-fill` vs `auto-fit`

言歸發表於2018-02-20

CSS Grid 之列寬自適應:auto-fill vs auto-fit

除了顯式的指定列大小之外,CSS Grid 還有個非常強大的功能 —— 模式填充(repeat-to-fill)列然後對內容進行自動佈局。也就是說,開發者只需要指定列數,自適應方面的事情(視口尺寸小則顯示列數少,反之則多)交給瀏覽器來處理就行了,也不需要用媒體查詢。

上述功能完全可以用一條語句就能實現,這不禁讓我想起《哈利波特》裡,鄧布利多在霍拉斯家裡揮舞著他的巴拉拉小魔棒,然後“傢俱一件件跳回了原來的位置,裝飾品在半空中恢復了原形,羽毛重新鑽回軟墊裡,破損的圖書自動修復,整整齊齊地排列在書架上…”。

就是這麼神奇,而且還不用媒體查詢。這一切都歸功於 repeat() 方法和自動佈局的關鍵字。

其實這方面的技術文章很多,基本用法我就不在此贅述了,有興趣可以參考 Tim Wright 寫的 博文,個人極力推薦。

總之,repeat() 方法能根據你的需要分割出任意多個列。例如,如果你需要一個基於 12 列的網格系統,你可以這麼寫:

.grid {
   display: grid;

  /* 指定網格列數 */
  grid-template-columns: repeat(12, 1fr);
}
複製程式碼

1fr 表示讓瀏覽器將網格空間進行均分,每列佔其一分,這樣就建立了 12 個寬度不固定但是相等的列。而且不管視口寬度如何,都會保持 12 列不變。但是,估計你也想到了,如果視口過窄,內容必然會被擠扁。

所以,這裡有必要設定列的最小寬度來保證容器不至於太窄,這裡需要用到 minmax() 方法。

grid-template-columns: repeat( 12, minmax(250px, 1fr) );
複製程式碼

按照 grid 的脾性,這麼做肯定會導致當前行內容溢位,即便視口在最小列寬的限制條件下實在無法容納這些列,這些列也不會自動換行,因為之前告訴過瀏覽器必須有 12 列。

為了實現換行,可以用 auto-fitauto-fill

grid-template-columns: repeat( auto-fit, minmax(250px, 1fr) );
複製程式碼

這條語句讓瀏覽器自個兒去處理列寬和元素的換行,如果容器寬度不夠,元素會自動換行,也就不會導致溢位了。這裡仍舊用了 fr 單位,這樣的話,如果行內剩下的空間不足以容納另外一列時,已有的列能自動擴張佔滿一整行,不造成空間浪費。

乍一看名字,auto-fillauto-fit 似乎是完全相反的兩個東西,實際上它們的區別相當微妙。

非要說的話,用 auto-fit 的時候,當前行的末尾留了不少空白,但是什麼時候留白,為什麼會留白呢?

來讓我們一探究竟。

Fill 和 Fit 的區別到底在哪?

在最近一個 CSS 研討會上,我是這麼總結 auto-fillauto-fit 的區別的:

auto-fill 傾向於容納更多的列,所以如果在滿足寬度限制的前提下還有空間能容納新列,那麼它會暗中建立一些列來填充當前行。即使建立出來的列沒有任何內容,但實際上還是佔據了行的空間。

auto-fit 傾向於使用最少列數佔滿當前行空間,瀏覽器先是和 auto-fill 一樣,暗中建立一些列來填充多出來的行空間,然後坍縮(collapse)這些列以便騰出空間讓其餘列擴張。

乍看起來還是挺懵逼的,稍後我會做一個視覺化圖來展示這些行為,這樣更容易理解一點。Firefox 有專門的 Grid 分析工具能幫助顯示元素和列的尺寸、位置(譯者注:用開發者工具拾取容器元素,在樣式側邊欄中的 display: grid 中的 grid 左側有個網格圖示,點一下就能顯式網格線條了)。

這裡 的 demo 為例。

還是用 repeat() 方法來定義列,設定其最小寬度為 100px,最大為 1fr,這樣,如果存在額外空間,每一列分到的空間大小都相等。這裡讓列數自行計算,換行和自適應都交給瀏覽器處理。

第一個例子使用 auto-fill 關鍵字,第二個則是 auto-fit

.grid-container--fill {
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
}

.grid-container--fit {
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
複製程式碼

在特定的情況下,auto-fillauto-fit 的效果是一樣的。

[譯] CSS Grid 之列寬自適應:`auto-fill` vs `auto-fit`

雖然看起來一樣,但骨子裡還是不同的。看起來一樣只是因為視口的寬度造成了這種巧合.

使它們產生不同的結果的關鍵點在於 grid-template-columns 中列數和列寬的設定,例子不同,產生的結果也會不同。

當視口的寬度大到能夠容納額外的列到當前行時,差別就會體現出來了。這時,瀏覽器會採用兩種方式來處理這種情況,怎麼處理取決於是否還有內容需要放到多出的列裡面。

所以,如果當前行還能再放得下一列,瀏覽器的行為如下:

  1. “我這還有空間再放一列,還有沒放進來的內容嗎(如:grid item)?如果有,OK,我再在當前行新增一列,如果視口太小,空間不夠了,我換一行再加”。
  2. 如果沒有多的內容:“是讓這新的一列尸位素餐呢,還是讓其坍縮讓其餘的列進行擴張來佔據它的空間呢?”

auto-fillauto-fit 的出現解答了最後一個問題:在沒有多的內容的情況下,是坍縮還是任其佔位? 這是問題,同時也是選擇,最終取決於你的內容,以及你想該內容在響應式設計下如何表現。

下面來詳細解釋。為了形象、生動的表現出 auto-fillauto-fit 的區別,請按我的步驟做,觀察螢幕上的變化。現在,我正在調整視口的大小,留出足夠的橫向空間,讓其能容納更多的列到當前行。牢記一點,例子中的兩行有完全相同的內容、相同的列數,唯一的區別是第一行用的是 auto-fill,第二行用的是 auto-fit

這下應該清楚了吧,如果還是不明白,那我們繼續:

auto-fill 的做法:“來‘列’啊,給我把這行全佔了,列越多越好,我不介意有些個列完全是透明的 —— 看不到不代表不存在嘛。有空間就加列,有無內容無所謂,反正空間我是佔了(也就是說會用內容/grid item 來填充)。"

如上所述,auto-fill 儘可能容納多的列,即使有些列是空的,auto-fit 則稍顯不同。 auto-fit 的做法和 auto-fill 一樣,隨著視口寬度增大而增加列數,區別在於新增加的列都坍縮了(包括間隔 gap 在內)。用 Firefox 的 Grid 工具來視覺化這個過程再合適不過了,當視口的寬度增加時,新的列也被新增進來,grid 的線條也會增加,肉眼就能觀察得到全過程。

auto-fit 的做法:“先用已有的列進行填充,然後盡情擴張直到佔滿一整行空間。空白列不允許佔據多出的空間,這些空間要好好利用,應該讓已經填進去的列(內容/grid item)擴張自己來填充這些空間。”

有必要記住的一點是,在以上兩種情況中,多出來的列(無論最後是否坍縮)都不是隱式的列(implicit columns) —— 這在官方文件裡有特殊的含義。這裡新增的,或者說建立的列都在顯式 grid(explicit grid)裡面,和直接指明劃分出 12 列的 grid 是一樣的。所以,使用列數索引時, -1 會指向 grid 的末端,如果是隱式建立的,情況就不是這樣了。 給 Rachel Andrew 加雞腿,感謝他給出的這個小貼士。

總結

只有行的寬度大到能夠容納額外的列時,auto-fillauto-fit 這兩者的區別才會體現出來。

auto-fit 時,內容區會自動拉伸以便佔滿一整行;另一方面,使用 auto-fill 的時候,瀏覽器對待空列和那些有實質內容的列一樣,一視同仁,允許其佔用行空間 —— 即使這些空列並無實質性內容,它們也還是會分得行空間的一杯羹,所以也能間接的影響那些有內容的列的大小,或者說寬度。

你更傾向於哪種行為取決於你的需求,說實在的,我也在想到底有哪些情況,auto-fill 會比 auto-fit 更適用一點。如果你恰好周圍有這樣的使用場景,希望能在評論區不吝賜教。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章