1. 程式人生 > >CSS柵格系統與彈性盒模型:實踐比較

CSS柵格系統與彈性盒模型:實踐比較

不久以前,所有的HTML頁面佈局都是通過table、float以及其他CSS屬性完成的,但這些方法並不適合構建複雜的web頁面。

於是,W3C推出了flexbox(彈性盒模型)——一種專門用於構建健壯的響應式頁面的佈局模式。使用flexbox可以很容易地對齊頁面元素和內容,而它也是現在大多數web開發者首選的CSS系統。

現在,最佳HTML佈局系統的稱號又多了一個新的競爭者,它就是強大的CSS Grid,3月底,它就已經得到了Firefox 52和Chrome 57的原生支援,其他瀏覽器相信也會緊隨其後。

一個基本佈局測試

為了瞭解兩種系統的佈局方式,我們會分別用這兩種系統構建同一個頁面,一次使用flexbox(彈性盒模型),一次使用CSS Grid(柵格系統)。頁面如下:

靜態頁面佈局
(一個精簡的靜態頁面佈局)

這種設計非常基礎——包含一個居中容器,其中放置頁頭、主體部分、側邊欄和頁尾。為了完成這個佈局,我們需要解決這幾個問題:
1. 對齊佈局中的四個部分(頁頭、主體、側邊欄、頁尾)。
2. 響應式設計(在小螢幕上側邊欄置於主體下方)。
3. 對齊頁頭內容——導航置於左側,按鈕置於右側。

為了便於比較,我們一切從簡,先從第一個問題開始。

挑戰一:頁面部分定位

Flexbox解決方案

我們首先使用flexbox解決這個問題,為容器新增display:flex,並且垂直定位子元素,也即讓每個部分縱向排列。

.container {
    display
: flex
; flex-direction: column; }

現在我們來讓主體部分和側邊欄靠在一起,由於我們已經設定其父容器為縱向,所以我們需要新增一個包裝元素,來重新設定主體與側邊欄的定位方式。

<header></header>
<div class="main-and-sidebar-wrapper">
    <section class="main"></section>
    <aside class="sidebar"></aside>
</div>
<footer
>
</footer>

然後我們將包裝元素設定為flex容器(display:flex)並將定位方式設定為橫向(flex-direction:row)。

.main-and-sidebar-wrapper {
    display: flex;
    flex-direction: row;
}

最後一步是設定主體與側邊欄的尺寸,我們將其尺寸設定為3:1,使用flex很容易完成這個目標。

.main {
    flex: 3;
    margin-right: 60px;
}
.sidebar {
   flex: 1;
}

我們可以看到,flexbox完美地完成了這項工作,但是我們仍然需要新增大量的CSS屬性和一個額外的HTML元素。接下來讓我們看看CSS Grid是如何解決這個問題的。

CSS Grid解決方案

CSS Grid有多種使用方法,此處我們使用“柵格模板區域(grid-template-areas)”語法,因為它看起來最適合完成這個任務。
首先來定義四個柵格區域,每個對應頁面的一個部分。

<header></header>
<!-- 注意此處無包裝元素 -->
<section class="main"></section>
<aside class="sidebar"></aside>
<footer></footer>
header {
    grid-area: header;
}
.main {
    grid-area: main;
}
.sidebar {
    grid-area: sidebar;
}
footer {
    grid-area: footer;
}

然後設定網格並且分配每個區域的位置。下面的程式碼可能乍一看很複雜,但一旦你瞭解了柵格系統它就會變得極易掌握。

.container {
    display: grid;

    /*在網格中定義列的數量和大小。
      單位fr工作原理與flex類似:
      fr列元素將按照其值共享同一行中的可用空間。
      下面的程式碼表示有兩列,第一列是第二列的三倍。*/
    grid-template-columns: 3fr 1fr;

    /*分配前面定義的網格區域。
      第一行均為header。
      第二行由main和sidebar共享。
      第三行均為footer。*/
    grid-template-areas: 
        "header header"
        "main sidebar"
        "footer footer";

    /*每個網格間距60px*/
    grid-gap: 60px;
}

這樣就完成了要求,佈局將遵從上述結構,並且使用這種方式我們甚至不用處理內邊距和外邊距。

挑戰二:響應式設計

Flexbox解決方案

這一步與前一步緊密聯絡在一起,對於flexbox來說我們必須改變包裝元素的flex-direction並且調整邊距。

@media (max-width: 600px) {
    .main-and-sidebar-wrapper {
        flex-direction: column;
    }

    .main {
        margin-right: 0;
        margin-bottom: 60px;
    }
}

由於我們的示例很簡單,所以此處需要做的工作並不多,但在一個更復雜的佈局中,就會有許許多多的內容需要重定義了。

CSS Grid解決方案

由於我們已經定義好了grid-areas,所以我們只需要在媒體查詢中對網格進行重排序即可。

@media (max-width: 600px) {
    .container {
    /* 在移動裝置上重排序網格*/
        grid-template-areas: 
            "header header"
            "main main"
            "sidebar sidebar"
            "footer footer";
    }
}

或者,我們也可以重新定義整個佈局,如果你覺得這樣可以更簡潔些。

@media (max-width: 600px) {
    .container {
        /*  將頁面重新定義為單列布局 */
        grid-template-columns: 1fr;
        grid-template-areas: 
            "header"
            "main"
            "sidebar"
            "footer";
    }
}

挑戰三:對齊頁頭元件

Flexbox解決方案

我們的頁頭中包括一些導航連結和一個按鈕。我們希望將導航置左,按鈕置右。導航中的連結必須相鄰對齊。

<header>
    <nav>
        <li><a href="#"><h1>Logo</h1></a></li>
        <li><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
    </nav>
    <button>Button</button>
</header>

設定CSS樣式:

header {
    display: flex;
    /*平鋪頁頭內容*/
    justify-content: space-between;
}

現在導航列表和按鈕已經正確對齊了,剩下的任務就是使<nav>中的元素水平移動了,最簡單的方法是使用display:inline-block,但是為了完全使用flexbox來完成這個任務,我們使用下面這個解決方案:

header nav {
    display: flex;
    /*專案位於容器的基線上*/
    align-items: baseline;
}

僅有兩行程式碼,還不錯。接下來我們看看CSS Grid是如何解決的。

CSS Grid解決方案

為了分離導航和按鈕,我們將<header>設定為2列柵格,另外我們需要額外兩行CSS定位它們各自的邊界。

header{
    display: grid;
    grid-template-columns: 1fr 1fr;
}
header nav {
    justify-self: start;
}
header button {
    justify-self: end;
}

但此時<nav>中的嵌入式連結,尚未正確對齊,因為CSS Grid中沒有類似flexbox的baseline(基線)選項。所以我們必須再定義一個子網格。

header nav {
    display: grid;
    grid-template-columns: auto 1fr 1fr;
    align-items: end; 
}

很明顯CSS Grid在完成這項佈局中存在一些問題,但也是意料之中的事——畢竟它主要是用來對齊容器的,而不是容器中的內容,它並不適合做最後的潤色。

總結

如果你通讀了全文,結論就很顯然了——並不存在一個最好的佈局系統,flexbox和CSS Grid有各自擅長的領域,完全可以一起使用,而非一個能夠替代另一個。
對於沒時間通讀全文的讀者,可以看一看最後的總結:
1. CSS Grid更適用於頁面的整體架構,非常易於管理頁面佈局,甚至可以用於非常規、不對成設計中。
2. Flexbox擅長進行元素中內容的對齊,可以使用flex定位設計中的細節部分。
3. 使用CSS Grid進行2D佈局(行和列)。
4. Flexbox更適合一維空間(僅行或列)。
5. CSS Grid和flexbox不是替代關係,兩者完全可以搭配使用。