Flex 與 Grid 相比就像功能鍵盤和觸摸屏。觸摸屏的控制力相比功能鍵盤來講就像是降維打擊,由於功能鍵盤只能上下左右控制(x、y 軸),而觸摸屏打破了佈局障礙,直接從(z 軸)觸達,這樣 不管 UI 內部佈局再複雜,均可以經過 touch 直接定位。css
Flex 是一維佈局方式,咱們須要不斷嵌套 Div 才能造成複雜結構,而一旦佈局產生了變化,原有嵌套結構若是不能 「兼容變化」 到新結構,代碼就須要重構。而 Grid 就像觸摸屏同樣,能夠二維佈局,即使佈局方式作了翻天覆地的調整,也僅需少許修改就能適配。html
這就是此次精讀 用 css grid 從新思考佈局 的緣由,理解這個革命性佈局技術給佈局,甚至代碼邏輯組織帶來的變化。前端
做者首先拋出了 Flex 的問題,實際上是 block
float
flex
這三種佈局模式的通病:css3
minmax
之類的 API,因此定製型不足。舉個例子,上圖的結構用 Flex 描述多是這樣的:git
<div class="card"> <div class="profile-sidebar"> <img src="https://i.pravatar.cc/125?image=3" alt="" class="profile-img" /> <ul class="social-list"> <li> <a href="#" class="social-link" ><i class="fab fa-dribbble-square"></i ></a> </li> <li> <a href="#" class="social-link" ><i class="fab fa-facebook-square"></i ></a> </li> <li> <a href="#" class="social-link" ><i class="fab fa-twitter-square"></i ></a> </li> </ul> </div> <div class="profile-body"> <h2 class="profile-name">Ramsey Harper</h2> <p class="profile-position">Graphic Designer</p> <p class="profile-info"> Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere a tempore, dignissimos odit accusantium repellat quidem, sit molestias dolorum placeat quas debitis ipsum esse rerum? </p> </div> </div>
利用 HTML 嵌套結構,咱們將圖形縱向分紅兩大塊,而後在每塊內部繼續嵌套劃分佈局,這是最經典的佈局行爲了。github
樣式文件裏,咱們須要對每層佈局進行描述,同時支持多分辨率彈性佈局,包括頂層 card
容器在內的一些樣式須要作必定調整:微信
.card { width: 80%; margin: 0 auto; display: flex; flex-direction: column; max-width: 600px; background: #005e9b; flex-basis: 250px; color: white; padding: 2em; text-align: center; } .profile-info { font-weight: 300; opacity: 0.7; } .profile-sidebar { margin-right: 2em; text-align: center; } .profile-name { letter-spacing: 1px; font-size: 2rem; margin: 0.75em 0 0; line-height: 1; } .profile-name::after { content: ""; display: block; width: 2em; height: 1px; background: #5bcbf0; margin: 0.5em auto 0.65em; opacity: 0.25; } .profile-position { text-transform: uppercase; font-size: 0.875rem; letter-spacing: 3px; margin: 0 0 2em; line-height: 1; color: #5bcbf0; } .profile-img { max-width: 100%; border-radius: 50%; border: 2px solid white; } .social-list { list-style: none; justify-content: space-evenly; display: flex; min-width: 125px; max-width: 175px; margin: 0 auto; padding: 0; } .social-link { color: #5bcbf0; opacity: 0.5; } .social-link:hover, .social-link:focus { opacity: 1; } .bio { padding: 2em; display: flex; flex-direction: column; justify-content: center; } @media (min-width: 450px) { .bio { text-align: left; max-width: 350px; } } .bio-title { color: #0090d1; font-size: 1.25rem; letter-spacing: 1px; text-transform: uppercase; line-height: 1; margin: 0; } .bio-body { color: #555; } .profile { display: flex; align-items: flex-start; } @media (min-width: 450px) { .card { flex-direction: row; text-align: left; } .profile-name::after { margin-left: 0; } }
讓咱們看看 Grid 是怎麼作的吧!Grid 有許多 API,咱們重點看 grid-template-areas
這個屬性,利用它,咱們能夠不關心模塊的 HTML 結構,直接平鋪方式描述:ide
<div class="card"> <img src="https://i.pravatar.cc/125?image=3" alt="" class="profile-img" /> <ul class="social-list"> <li> <a href="#" class="social-link"><i class="fab fa-dribbble-square"></i></a> </li> <li> <a href="#" class="social-link"><i class="fab fa-facebook-square"></i></a> </li> <li> <a href="#" class="social-link"><i class="fab fa-twitter-square"></i></a> </li> </ul> <h2 class="profile-name">Ramsey Harper</h2> <p class="profile-position">Graphic Designer</p> <p class="profile-info"> Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere a tempore, dignissimos odit accusantium repellat quidem, sit molestias dolorum placeat quas debitis ipsum esse rerum? </p> </div>
能夠看到,使用 Grid 能夠將 UI 結構與 HTML 結構分離,HTML 結構僅描述包含關係,咱們只需在樣式文件中描述具體 UI 結構。模塊化
樣式文件只截取 Grid 相關部分:佈局
.card { width: 80%; margin: 0 auto; display: flex; flex-direction: column; max-width: 600px; background: #005e9b; flex-basis: 250px; color: white; padding: 2em; text-align: left; display: grid; grid-template-columns: 1fr 3fr; grid-column-gap: 2em; grid-template-areas: "image name" "image position" "social description"; } .profile-name { grid-area: name; } .profile-position { grid-area: position; } .profile-info { grid-area: description; } .profile-img { grid-area: image; } .social-list { grid-area: social; }
能夠看到,grid-template-areas
是進一步抽象的語法,將頁面結構經過直觀的文本描述,不管是理解仍是修改都更爲輕鬆。
這種描述方式適配不一樣分辨率下也具備優點,只要重組 grid-template-areas
便可:
@media (min-width: 600px) { .card { text-align: left; grid-template-columns: 1fr 3fr; grid-template-areas: "image name" "image position" "social description"; } }
歸根結底,Grid 經過二維結構描述,將子元素佈局控制收到了父級,使佈局描述更加直觀。
最後做者也提到,Flex 依然有使用場景,即簡單的一維結構,或者 space-between
等 Flex 獨有語法的狀況。所以推薦總體、複雜的二維佈局採用 Grid,一維的簡單佈局採用 Flex。
Grid 的佈局思路給了我不少啓發,HTML 結構與 UI 結構的分離有助於減小 DIV 的層級結構,使代碼看上去更清晰。
也許有人會疑惑,Grid 無非將 HTML 佈局部分功能挪到了 CSS,總體複雜度應該不變。其實,從 grid-template-areas
這個 API 能夠看到,Grid 不只僅將佈局功能抽到 CSS 中,更是將佈局描述進行了一層抽象,使代碼更易維護。
爲何 Grid 能夠對佈局進行抽象?由於 Grid 將二維結構都掌握在手中,獲得了更大的佈局能力,才能進一步將結構化語法抽象爲字符串的描述。
抽象的好處是不言而喻的,你以爲一堆嵌套的 DIV 與下面的代碼,哪一個更易讀呢?
.card { grid-template-areas: "image name" "image position" "social description"; }
這就是抽象的好處,通常來講,代碼抽象程度越高就越易讀,越易維護。
再看一個 Chrome Grid 插件,將 Grid 可視化顯示出來,並能夠以 UI 方式進行調整:
UI 是對文本的再抽象,同時能夠規避一些不可能存在的語法,好比:
.card { grid-template-areas: "image name" "image position" "social image"; }
佈局只能以凸多邊形方式拓展,不可能分離,也不可能忽然插入一個其餘模塊而變成凹多邊形。所以 UI 能夠將這個錯誤規避,並簡化爲橫豎多條線的方式對 UI 進行劃分,顯然這種描述方式效率更高。
不得不說,Grid 以及圖形化插件的探索,是佈局領域的一大進步,是不斷抽象的嘗試,要解決的問題只有一個:如何提供一種更直觀的描述 UI 的方式。
Grid 將佈局方式提升了一個維度,會直接影響到 JS 模塊化方式。
尤爲是以 JSX 組織代碼的狀況下,一個模塊等於 UI + JS,經過嵌套方式的佈局會讓咱們更傾向於站在 UI 視角劃分模塊。
好比對於上圖模塊,若是用 Flex 方式佈局,咱們可能會首先建立模塊 X 做爲左側容器,子元素是 A 和 B,建立模塊 Y 做爲右側容器,子元素是 C 以及新容器 Z,Z 容器的子元素是 D 和 E。
若是你的第一印象是這麼組織代碼,不得不認可模塊化會受到佈局方式的影響。雖然許多時候這樣劃分是正確的,但當這 5 個模塊各自沒有關聯時,咱們建立的容器 X、Y、Z 就失去了複用性,在新的組合場景咱們又要從新組合一遍。
可是在 Grid 語法中,咱們不須要 X、Y、Z,只須要用 css grid generator 按照上圖的方式拖拖拽拽便可自動生成以下佈局代碼:
.parent { display: grid; grid-template-columns: 3fr repeat(2, 1fr); grid-template-rows: repeat(5, 1fr); grid-column-gap: 0px; grid-row-gap: 0px; } .div1 { grid-area: 1 / 1 / 3 / 2; } .div2 { grid-area: 3 / 1 / 6 / 2; } .div3 { grid-area: 1 / 2 / 2 / 4; } .div4 { grid-area: 2 / 2 / 6 / 3; } .div5 { grid-area: 2 / 3 / 6 / 4; }
其實 grid-template-columns
grid-template-rows
組合起來使用比 grid-template-areas
更強大,可是純代碼方式描述沒有 grid-template-areas
直觀,但是配合一些可視化系統就很是直觀了:
將 A ~ E 這 5 個模塊佈局抽出來後,它們之間的關係就打平了,咱們能夠徹底從邏輯視角審視如何作模塊化了。
CSS Grid 本質上是一種二維佈局的語法,相比 Block、Flex 等一維佈局方案,多了一個維度能夠同時從行與列角度定義佈局,所以派生出 grid-template-areas
等語法,總體上更內聚更直觀,抽象度也更高了。
理解了這些也就理解了佈局將來的發展方向,讓佈局與 Dom 分離 一直是前端的一個夢想,開發 UI 部分時,只需關心頁面由哪些模塊組成,去實現這些模塊就好了,而不須要關心模塊之間應該如何組合。在描述組合時,能夠經過可視化或比較抽象的字符串描述佈局的結構,並對應到寫好的模塊上,這樣的代碼維護性遠高於用 DIV 描述結構的方案。
討論地址是: 精讀《用 css grid 從新思考佈局》 · Issue #211 · dt-fe/weekly
若是你想參與討論,請 點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。
關注 前端精讀微信公衆號
<img width=200 src="https://img.alicdn.com/tfs/TB...;>
版權聲明:自由轉載-非商用-非衍生-保持署名( 創意共享 3.0 許可證)