【譯】Css Grid VS Flexbox: 實踐比較

如意同學發表於2019-03-07

【譯】Css Grid VS Flexbox: 實踐比較

原文:CSS Grid VS Flexbox: A Practical Comparison 作者:Danny Markov

在不久前,所有 HTML 頁面的佈局都是通過tablefloat和其他 CSS 屬性來完成的,但其實這些屬性並不適合設計複雜的網頁。

緊接著,出現了flexbox ——一種專門為建立強大的響應式頁面而設計的佈局模式。 使得元素和內容的正確對齊變得很容易,現在是大多數網頁開發者首選的 CSS 系統。

現在我們有了一個“構建 html 佈局最佳系統獎盃”的新競爭者——這就是強大的CSS Grid,到本月底,它將在 Firefox 52和  Chrome 57中釋出,其他瀏覽器(希望如此)也會很快跟進。

基本佈局測試

為了瞭解使用每個系統構建佈局是什麼感覺,我們對同一個 HTML 頁面構建了兩次 -- 一次是使用 flexbox,另一次是使用CSS Grid。 您可以從原文文章頂部附近的下載按鈕下載這兩個專案,或者在這個線上演示中檢視它們:

剝離式靜態頁面佈局

這個設計非常簡單——它由一個居中的容器組成,其中包含一個頭部、主要部分、側邊欄和一個頁尾。 下面是我們必須解決的主要"挑戰",同時儘可能保持 CSS 和 HTML 的乾淨:

  1. 佈局四個主要部分
  2. 響應式佈局(在螢幕較小的情況下側邊欄位於主要內容的下方)
  3. 將標題導航的內容對齊到左側,按鈕對齊到右側

正如你所看到的,為了便於比較,我們把一切都寫的儘可能簡單。 讓我們從第一個問題開始。

挑戰1: 定位頁面部分

Flexbox 方案

我們從 flexbox 方案開始。 我們將 display: flex新增到容器並將其子容器垂直定向。 這會讓所有模組一個接一個地往下放。

.container {
    display: flex;
    flex-direction: column;
}
複製程式碼

現在我們需要讓主要部分和側邊欄挨著放。 由於 flex 容器通常是單向的,因此我們需要新增一個wrapper元素。

<div class="main-and-sidebar-wrapper">
    <section class="main"></section>
    <aside class="sidebar"></aside>
</div>
<footer></footer>
複製程式碼

然後我們設定包裹層(wrapper)的display為:flex 並且flex-direction設定為相反的方向。

.main-and-sidebar-wrapper {
    display: flex;
    flex-direction: row;
}
複製程式碼

最後一步是設定主要部分和邊欄的大小。 我們希望主要內容是側邊欄大小的三倍,這對 flex 或百分比來說並不困難。

.main {
    flex: 3;
    margin-right: 60px;
}
.sidebar {
   flex: 1;
}
複製程式碼

你可以看到 flexbox 已經做得很好了,但我們仍然需要相當多的 CSS 屬性 + 一個額外的 HTML 元素。 讓我們看看 CSS 網格是如何工作的。

CSS Grid 方案

使用 CSS Grid有幾種不同的方法,我們將使用grid-template-areas,對於當下我們要完成的工作來說,它似乎是最適合的。

首先,我們將定義四個grid-area,每個網格區域一個:

<!-- Notice there isn't a wrapper this time -->
<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;
}
複製程式碼

然後我們可以建立我們的grid,並分配每個區域的位置。

下面的程式碼一開始可能看起來相當複雜,但是一旦瞭解了網格系統,就很容易理解了。

.container {
    display: grid;

    /*  Define the size and number of columns in our grid. 
    The fr unit works similar to flex:
    fr columns will share the free space in the row in proportion to their value.
    We will have 2 columns - the first will be 3x the size of the second.  */
    grid-template-columns: 3fr 1fr;

    /*  Assign the grid areas we did earlier to specific places on the grid. 
        First row is all header.
        Second row is shared between main and sidebar.
        Last row is all footer.  */
    grid-template-areas: 
        "header header"
        "main sidebar"
        "footer footer";

    /*  The gutters between each grid cell will be 60 pixels. */
    grid-gap: 60px;
}
複製程式碼

就是這樣! 佈局現在遵循開頭所說的結構,現在甚至不需要處理任何邊緣或填充。

挑戰2: 讓頁面響應迅速

Flexbox 方案

此步驟的執行與前一個步驟緊密相連。 對於 flexbox 解決方案,我們將不得不改變wrapper的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 {
    /*  Realign the grid areas for a mobile layout. */
        grid-template-areas: 
            "header header"
            "main main"
            "sidebar sidebar"
            "footer footer";
    }
}
複製程式碼

或者,如果覺得有必要的話,我們可以從頭開始重新定義整個佈局

@media (max-width: 600px) {
    .container {
        /*  Redefine the grid into a single column layout. */
        grid-template-columns: 1fr;
        grid-template-areas: 
            "header"
            "main"
            "sidebar"
            "footer";
    }
}
複製程式碼

挑戰3: 對齊元件頭部

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>
複製程式碼

在一篇舊文章The Easiest Way To Make Responsive Headers中,我們已經使用flexbox做了一個類似的佈局,這個技巧非常簡單:

header {
    display: flex;
    justify-content: space-between;
}
複製程式碼

現在導航列表和按鈕正確對齊。 剩下的就是讓<nav> 中的項水平居中。 在這裡使用 display: inline-block 是最簡單的,但是既然我們要使用完全 flexbox,那麼讓我們應用一個flexbox-only解決方案:

header nav {
    display: flex;
    align-items: baseline;
}
複製程式碼

只有兩行! 一點也不差。 接下來讓我們看看 CSS Grid是如何處理它的。

CSS Grid 方案

為了分割導航和按鈕,我們必須設定header為display: grid ,並設定一個2列的網格。 另外還需要兩行額外的 CSS 來定位它們在各自的邊界上。

header{
    display: grid;
    grid-template-columns: 1fr 1fr;
}
header nav {
    justify-self: start;
}
header button {
    justify-self: end;
}
複製程式碼

至於導航中的內聯連結--其實我們使用css grid是無法非常精準實現的。 以下是我們的最佳嘗試:

css-grid-header.png

這些連結是內聯的,但是它們不能正確對齊,因為沒有像 flexbox 的 align-items 那樣的baseline選項。 我們還必須定義另一個子網格。

header nav {
    display: grid;
    grid-template-columns: auto 1fr 1fr;
    align-items: end; 
}
複製程式碼

很明顯,CSS grid在佈局的這一部分遇到了困難,但這並不奇怪——它的重點是調整容器,而不是容器內的內容。

總結

如果你已經讀完了整篇文章,這個結論對你來說並不意外。 事實上是,沒有一個最優的解決方案--flexboxCSS Grid擅長的東西不同,決定了使用場景不同,它們應該一起被使用,而不是作為競爭對手。

對於那些直接跳到文章結論的人(不用擔心,我也經常這樣做)),這裡有一個全文比較結論的摘要:

  • CSS grids對於構建更大的圖片非常有用。 它們使管理頁面佈局變得非常容易,甚至可以處理更多非傳統和不對稱的設計
  • Flexbox 非常擅長對齊元素內容,它可以用來定位設計中較小的細節
  • 使用 CSS grids進行2D 佈局(行和列)
  • Flexbox只在一個維度時(行或列)工作得更好
  • 沒有理由只使用CSS grids或只使用 flexbox。 我們應該同時學習它們,並使用它們

相關文章