內(nèi)容布局(四):Grid布局

耽擱了好久一直沒寫 Grid 布局,主要是寫布局的文章太累人??。這期就朝花夕拾,寫寫 Grid layout 的入門教程。

Grid Basic

Grid layout 翻譯過來叫網(wǎng)格布局,我先介紹一下 Grid 里的幾個基本術(shù)語:

Grid Container

網(wǎng)格容器就是被設(shè)置為display: grid的元素,通俗來說就是所有網(wǎng)格的最外層:

.grid-container {
  display: grid;
}

Grid Items

網(wǎng)格項就是網(wǎng)格容器里的每一個子元素。如下所示,header、asidemainfooter就是grid-container的網(wǎng)格項。(p.s. 孫子元素不會受到祖先網(wǎng)格屬性的影響)

<div class="grid-container">
  <header></header>
  <aside></aside>
  <main>
      <!-- doesn’t effected!!! -->
      <div class="grandson"></div>
      <!-- doesn’t effected!!! -->
  </main>
  <footer></footer>
</div>
container & items

Grid Columns

既然是網(wǎng)格,自然有列和行的概念,我們先說“列”。網(wǎng)格容器添加grid-template-columns屬性便可激活列屬性:下方示例中,我們把網(wǎng)格項排成了兩列。實現(xiàn)上只需把兩列的長度(200pxauto)從左至右枚舉出來即可:

.grid-container {
  display: grid;
  grid-template-columns: 200px auto;
}
column

除了利用單位或 auto 來指定每一列的長度,我們也可以讓列按一定比例排布。下方示例中,實現(xiàn)了左右兩列 1:2 比例的布局——只需在grid-template-columns指定1fr2fr即可。

.grid-container {
  display: grid;
  grid-template-columns: 1fr 2fr;
}
Fractions

p.s. fr 是 franction 的縮寫

Grid Rows

同理,grid-template-rows會激活行屬性,也就是用來定義每一行的高度,屬性同樣可以是基本單位(px,rem,%),也可以是fr比例:

.grid-container {
  display: grid;
  grid-template-columns: 1fr 2fr;
  grid-template-rows: 100px 200px;
}
Rows

Grid Gaps

若想為這些排布的 items 添加間距(槽),可以使用grid-gap屬性。單獨定制橫軸或縱軸的間距,還有grid-column-gapgrid-row-gap這兩個屬性。

.grid-container {
  display: grid;
  grid-template-columns: 1fr 2fr;
  grid-template-rows: 100px 200px;

  grid-column-gap: 10px;
  grid-row-gap: 10px;
  /* or in simplified form */
  grid-gap: 10px;
}
Rows

Grid Cells & Gird Lines

grid-template-columnsgrid-template-rows排布后,橫軸和縱軸交匯,就形成如下所示的單元格(grid cell)和標(biāo)注為 1、2、3... 的網(wǎng)格線(grid line)。這里我提一下,cell 和 item 是不一樣的概念:cell 是網(wǎng)格的基本單元,而 item 是可以橫跨多個 cell 的 DOM 元素。

cell

Grid Layout

上文我們介紹了幾個網(wǎng)格布局的基本術(shù)語;若是到此為止,那也頂多是加強版的 table 布局罷了。而網(wǎng)格布局的真正特別之處是在 grid cell 基礎(chǔ)上的網(wǎng)格定位。

我們還是從傳統(tǒng)布局的弊端說起,下圖是一種很常見的頁面布局。

Flex Layout

這種布局實現(xiàn)上很直白:先把整體分成三行,再把中間那行分成兩列。HTML 便簽大體如下所示:

<body>
  <header class="row"></header>
  <div class="row">
    <aside class="column-aside"></aside>
    <main class="column-main"></main>
  </div>
  <footer class="row"></footer>
</body>

實現(xiàn)很簡單,就不寫 CSS 了;只是在語義標(biāo)簽層面上,header、footerasidemain 理應(yīng)是同級;但為了布局方便不得不把 asidemain 做成了孫子節(jié)點,有點怪怪的。不過整體也沒太大問題。如果再成換更復(fù)雜的布局呢,比如,回字形?

Hollow Square

用傳統(tǒng)布局技術(shù)(如 flex)實現(xiàn)回字形,代碼量會立馬暴漲。更糟糕的是,這種排版將犧牲掉所有語義標(biāo)簽——你的關(guān)注點只會在各種層層嵌套的 div 上了。

Grid Position

網(wǎng)格布局能幫到什么呢?我前文也提到過,Grid items 可以橫跨多個 Grid cells,就從這里入手。

我們再看看上面那個回字形布局,本質(zhì)上不就是個九宮格嘛?我們用 repeat 方法給網(wǎng)格容器寫一個 3×3 的 cell 九宮格:

.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
}

最后只要把網(wǎng)格項 header 覆蓋在第 1 和第 2 個 cell 上、aside 在 4 和 7 上、main 在 3 和 6、footer 在 8 和 9 上,即可完成布局。

Soduku

那網(wǎng)格布局怎么為網(wǎng)格項定位這些 cell 呢?用坐標(biāo)呀!從 (grid-column-start, grid-row-start)(grid-column-end, grid-row-end) 所在的矩形區(qū)域來定位網(wǎng)格項的排布。橫坐標(biāo)值就是 Y 軸(Column Grid Line)所顯示的數(shù)值,縱坐標(biāo)就是 X 軸(Row Grid Line)所顯示的數(shù)值,起始數(shù)值都是 1。

Position

上圖所示,header 位于 (1,1)(3,2) 這塊矩形區(qū)域內(nèi),我們?yōu)?header 添加如下 CSS 屬性;header 便會自動定位到左上角那塊粉紅色區(qū)域了。

header {
  grid-column-start: 1;
  grid-row-start:  1;
  grid-column-end: 3;
  grid-row-end: 2;
}

其他幾塊區(qū)域的布局我就不寫出來了,大家有興趣的話自己算一下坐標(biāo)即可。

Grid Areas

除上面這種二維坐標(biāo)定位的方式,CSS 網(wǎng)格布局還提供了一種更無腦的定位方式——grid-template-areas——可以為網(wǎng)格設(shè)置區(qū)域模版,比如上面的回字形布局模版就如下所示:

.grid-container {
  display: grid;
  grid-template-areas:
    "h h m"
    "a . m"
    "a f f";
}

這個模版我寫得很簡單,解釋一下:就是由九個字符及空格所示意的九宮格模版。以左上角 h h 為例,兩個相鄰的 h 組成了一個所謂的“命名網(wǎng)格區(qū)”,表示網(wǎng)格區(qū)名為 h 的網(wǎng)格項將會被排布在第 1、2 兩個 cell 上。am、f 分別是另外三個網(wǎng)格項的標(biāo)識符;中間的 . 是一個空白區(qū)域的占位符,我本人習(xí)慣用這個字符,大家盡可以挑選自己喜歡的占位符。

之后,我們再為 header、aside、main、footer 分別設(shè)置映射區(qū)域——grid-area,這四個網(wǎng)格項就自動排布到各自模版位上去了。

header { grid-area: h; }
aside { grid-area: a; }
main { grid-area: m; }
footer { grid-area: f; }

再回頭看一下網(wǎng)格布局的 HTML,語義標(biāo)簽不需要為布局做任何改變。這是較傳統(tǒng)布局的重大改進(jìn),HTML 結(jié)構(gòu)和 UI 終于實現(xiàn)了分離。

<body class="grid-container">
  <header></header>
  <aside></aside>
  <main></main>
  <footer></footer>
</body>

Grid Kiss

grid-template-areas 還需要為各個網(wǎng)格項命名模版區(qū)域,模版能不能自己幫我們映射到相應(yīng)的 html tag 或是 class 上去呢?這樣寫起來似乎更省事。

嗯,還真有人想到了這一點——一個叫 postcss-grid-kisspostcss 插件。Grid-kiss 為我們實現(xiàn)了一種很有趣的 CSS 布局方案:讓所有的布局變成一幅“簡筆畫”:

.grid-container {
  grid-kiss:
    "+-------------+  +-----+"
    "|   header    |  |     |"
    "+-------------+  |     |"
    "+-----+          |main |"
    "|     |          |     |"
    "|aside|          +-----+"
    "|     | +--------------+"
    "|     | |    footer    |"
    "+-----+ +--------------+"
    ;
}

它的實現(xiàn)就是把這副文本流圖轉(zhuǎn)化成 grid 語法樹。有一句廣告說的好,“Grid-kiss,布局從未如此簡單”

IE support

最后再說一下 IE,早在 E10 的時候它就已經(jīng)支持網(wǎng)格布局了——還是挺超前的。只可惜 IE 的 Grid 語法別樹一幟,未被大眾認(rèn)可;方法與現(xiàn)代 Grid 一比,更相形見絀了。那 IE 上要怎么使用網(wǎng)格布局呢?我們還是得依靠 PostCSS——CSS 里的 Babel,它有個叫 autoprefixer 的插件可以幫我們完成 Modern Grid 到 IE Grid 的轉(zhuǎn)換;這里(Autoprefixer online)還有一個在線的轉(zhuǎn)換網(wǎng)站,有興趣的朋友可以試一下。

若你已經(jīng)使用現(xiàn)代 JS 框架(如 Vue、React),它們的腳手架大多內(nèi)置了 postcss 和 autoprefixer,基本上就是無配置使用。上面的 grid-kiss,也只要給 postcss 配置加個插件,親測 IE11 可用。至于 IE 的 Grid 語法,就讓它隨風(fēng)消逝在歷史的長河之中吧。

小結(jié)

上次看了篇文章,提到 CSS Grid 已是一種很大眾化的前端技術(shù)。但我身邊的 team,只能說很少很少很少有人使用。我猜原因有多種:

  • 熟練掌握 CSS 的開發(fā)人員本身就很少,大家形成了一種“默契”——不要增加認(rèn)知復(fù)雜度
  • 技術(shù)革新太快,一開始想著“讓子彈飛一會兒”,但是之后就再也沒人提起了
  • 傳統(tǒng)認(rèn)知中后端重于前端,很多團(tuán)隊也無心推動前端升級

當(dāng)然,這些種種我們也應(yīng)理解,畢竟這只是一種布局技巧,在一個產(chǎn)品的范疇中占不了太多分量;甚至于技術(shù)本身,只要別太爛,也并不是決定產(chǎn)品成敗的關(guān)鍵。所以嘛,對于新技術(shù)也,能用則用,不能用也不要太過執(zhí)著;做人嘛,最重要的是開心。

相關(guān)

文章同步發(fā)布于an-Onion 的 Github。碼字不易,歡迎點贊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • CSS Grid(網(wǎng)格) 布局(又稱為 “Grid(網(wǎng)格)” ),是一個二維的基于網(wǎng)格的布局系統(tǒng)它的目標(biāo)是完全改變...
    諾CIUM閱讀 1,350評論 0 3
  • Grid 是CSS中最強大的布局系統(tǒng)。它是2-Dimensional System,這意味著它可以同時處理列和行....
    邢烽朔閱讀 2,713評論 0 5
  • 網(wǎng)格線(Grid Line) 構(gòu)成網(wǎng)格結(jié)構(gòu)的分界線。它們既可以是垂直的(“列網(wǎng)格線(column grid lin...
    晚溪呀閱讀 1,287評論 0 0
  • 1:基本布局 Grid 布局是二維的基于網(wǎng)格的布局系統(tǒng),它可以同時處理列和行(這是對比flex彈性盒模型布局而言)...
    前白閱讀 958評論 0 1
  • 簡介 CSS網(wǎng)格布局(又名“網(wǎng)格”)是一個二維的基于網(wǎng)格的布局系統(tǒng),其目的只在于完全改變我們設(shè)計基于網(wǎng)格的用戶界面...
    禮知白閱讀 719評論 0 0

友情鏈接更多精彩內(nèi)容