天天看點

震驚!很多人都不知道 CSS Grid 架構早就有了!

震驚!很多人都不知道 CSS Grid 架構早就有了!

寫作本文起源于知乎的一個問題:【CSS Grid 布局那麼好,為什麼至今沒有人開發出基于 Grid 布局的前端架構呢?】

這篇文章拖沓了兩個月,是因為真的不知道從哪裡說好。這個問題的所有回答幾乎都沒有切中問題的本質,而且對 CSS Grid 也有很深的誤解。另外這個問題的描述可能不太恰當,因為基于 CSS Grid 的架構已經有了。感興趣的朋友可以了解一下 Flex-Layout,它是一個基于指令布局的神器。大家不要被項目名誤導,雖然叫 <code>flex-layout</code>,其實有 <code>flex</code> 和 <code>grid</code> 兩種指令。

我覺得這個問題更恰當的描述應該是【為什麼沒有基于 Grid 布局的純 CSS 前端架構呢】,基于 Float 和 Flex 的 CSS 布局架構多如牛毛,但是一直沒看到基于 CSS Grid 的實作。我在寫 Snack 的時候也曾考慮過在 v3 版本中整合 CSS Grid,但是後來發現有些不現實,下文詳述。據說 Bootstrap 也曾打算在 v5 版本整合 CSS Grid,但是目前來看依然沿用了 Flex 布局。我個人覺得基于指令實作的 <code>flex-layout</code> 應該是整合 CSS Grid 的最佳方式。

本文打算從相反的角度聊一聊,假如要實作一個基于 CSS Grid 的布局架構,我們會遇到哪些問題呢?

先說一下相容性,很多人總覺得 CSS Grid 的相容性不行。其實不然,下圖的統計資料能夠看出大部分浏覽器對 CSS Grid 的支援還是不錯的,要知道 Flex 在 IE10 上面可以使用的屬性也非常有限。據統計目前 CSS Grid 使用率和 Flex 已經基本持平了。是以相容性并不能回答開篇提出的問題。

震驚!很多人都不知道 CSS Grid 架構早就有了!
震驚!很多人都不知道 CSS Grid 架構早就有了!

CSS 布局主要有四種,上古時期用的是 table,這個就不說了,我們隻讨論新世紀常用的 Float、Flex、Grid。這三種布局方式就是遞進的關系,逐漸加強了 CSS 布局的便利性。CSS 布局的最佳實踐當屬 Bootstrap,其中 Float 和 Flex 布局方案都已經被 Bootstrap 實作,唯獨 Grid 方案遲遲不見蹤影。

CSS 布局架構的關鍵在于如何設計栅格,我們先看看在 Bootstrap 中是怎麼進行布局的。

用過 Bootstrap 的人對以上結構一定不陌生。在 Bootstrap v4 中,由于 Flex 布局功能的增強,<code>row</code> 也可以搭配 <code>utility</code> 使用。

<code>row</code> 和 <code>col</code> 的組合幾乎已經成為栅格布局的共識和标準。接下來我們就用這種設計方式手撕一個 Grid 栅格看看效果。

其實手撕一個 CSS 布局栅格并不難,關鍵是要熟悉預處理器的循環功能。下面我們分别用 Float、Flex 及 Grid 實作一個簡化版的栅格布局并對比一下它們之間的差異。

Float 是過去實作流體布局的唯一方式,難點在于處理父元素的塌陷,這算是一個老生常談的問題了,本文不再贅述。以下是一個簡易版的 Float 栅格:

See the Pen

float-columns by Zongbin (@nzbin)

on CodePen.

這種栅格簡單實用,堪稱經典。但是 Float 布局的局限性很大,如果栅格的高度不相同(比如将第一個栅格的高度加高),布局就會出現錯位。

Flex 的誕生幾乎解決了 Float 栅格的所有痛點,比如上面提到的錯位問題。以下是一個簡易版的 Flex 栅格:

flex-columns by Zongbin (@nzbin)

其實在一維布局中,Flex 已經足夠好用,至少在流體布局中沒發現特别需要改進的地方,是以我們是否還有必要引入二維布局方案?

重點來了!重點來了!重點來了!

Grid 是比 Flex 更進階的布局技術,是以單純替換 Flex 實作一套栅格布局系統完全沒有問題。以下是一個極其簡易的 Grid 栅格,幾乎和 Flex 栅格的效果沒有差別。

grid-columns by Zongbin (@nzbin)

Grid 除了能實作 Flex 的布局之外,還可以在縱向空間對每一行進行調整(比如設定 <code>grid-template-rows: 1fr 2fr</code>)。另外,Grid 設定其它列數的栅格也比較容易,比如設定 10 列栅格,隻需要設定 <code>grid-template-columns: repeat(10, 1fr)</code> 即可;如果是 Flex,則需要重新計算栅格的寬度。

上面示例中展示的 CSS Grid 的功能隻是冰山一角。作為一個二維布局技術,它的屬性寫法非常繁雜,比如另外一個強大的功能 <code>grid-template-areas</code> MDN Demos。這種屬性定義方式很難使用類名的疊加組合實作對應的功能。

如果隻是簡單地将 Flex 栅格替換成 Grid 栅格,我個人感覺意義不大,一個基于 CSS Grid 全新的栅格系統應該盡可能的發揮它所有的優勢。這或許就是 CSS Grid 栅格系統遲遲沒有出現的原因吧。我不知道文章寫到這裡是否清楚的表達了我的觀點,或者說能否解答大家對于開篇問題的疑惑。接下來再看看 <code>flex-layout</code> 中的 Grid。

因為 <code>flex-layout</code> 是基于指令的實作,是以不像類名疊加的方式那樣有很大的局限性,幾乎可以發揮 CSS Grid 的全部優勢。以下就是 <code>grid-template-areas</code> 的定義方法。

<code>flex-layout</code> 無論是設計思路還是實作方式都讓我頂禮膜拜,它與傳統的 Bootstrap 形式的栅格有着本質差別。本文的重點不是介紹 <code>flex-layout</code>,如果大家感興趣,還是看官網介紹吧 Flex-Layout。

醞釀了兩個月的文章,感覺還是沒有把自己的觀點表達清楚。回到問題本身,【為什麼沒有基于 Grid 布局的純 CSS 前端架構呢】,個人覺得最主要的還是傳統寫法無法發揮 CSS Grid 的全部優勢,至少用以往的組合類方式是無法做到的。CSS Grid 屬性的特殊性也決定了不可能也不應該隻是單純的疊加組合類名。

感謝您的閱讀,如果您對我的文章感興趣,可以關注我的部落格,我是叙帝利,下篇文章再見!

開發低代碼平台的必備拖拽庫 https://github.com/ng-dnd/ng-dnd

基于 Angular Material 的中背景管理架構 https://github.com/ng-matero/ng-matero

Angular Material Extensions 擴充元件庫 https://github.com/ng-matero/extensions

仿 Windows 照片檢視器插件 https://github.com/nzbin/photoviewer

仿 Windows 照片檢視器插件 jQuery 版 https://github.com/nzbin/magnify

完美替代 jQuery 的子產品化 DOM 庫 https://github.com/nzbin/domq

簡化類名的輕量級 CSS 架構 https://github.com/nzbin/snack

與任意 UI 架構搭配使用的通用輔助類 https://github.com/nzbin/snack-helper

單元素純 CSS 加載動畫 https://github.com/nzbin/three-dots

有趣的 jQuery 卡片抽獎插件 https://github.com/nzbin/CardShow

懸疑科幻電影推薦 https://github.com/nzbin/movie-gallery

鍛煉記憶力的小程式 https://github.com/nzbin/memory-stake