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 描述結構的方案。
若是你想參與討論,請 點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。
關注 前端精讀微信公衆號
版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享 3.0 許可證)