1. 程式人生 > >使用 CSS Grid 實現表單佈局的優勢

使用 CSS Grid 實現表單佈局的優勢

表單佈局和設計一直是網頁設計和開發中令人頭疼的一部分。 嘗試過寫 <select> 標籤的樣式,或者在所有瀏覽器中都居中一個 label 的人感觸肯定更深。

原文連結:https://www.sitepoint.com/css-grid-web-form-layout/

在2016年,我寫了一篇文章標題為 "Make Forms Fun with Flexbox",文中指出瞭如何使用 Flexbox 佈局解決多種表格佈局的困難。為了展示 HTML 標籤順序的一致性,label 總是跟隨在一個關聯域標籤之後:

<div>
  <input
id="name" name="name" type="text" />
<label for="name">name</label> </div> <div> <select id="experience" name="experience"><!-- options --></select> <label for="experience">experience</label> </div> <div> <input id="html" name
="html" type="checkbox" />
<label for="html">HTML</label> </div>

然後,Flexbox 可以這樣用:

  • 如果需要重新定位 label 順序,比如,將文字輸入(input)、選擇框(select) 或者 textarea 移動到 label 的左邊
  • 垂直對齊 labelfiled

還可以使用相鄰的同級選擇器來根據它們的欄位的狀態來新增樣式,例如,當選中複選框時,將粗體應用到 label 上:

input:checked + label {
  font-weight
: bold; }

使用 Flexbox 來設計表單的缺點

可是在表單佈局中使用 Flexbox 有很多問題。 Flexbox 建立一個一維佈局,一項需要折行後跟著一項, Field/label 必須放置在帶有 display: flex; 的父級容器元素中,這樣才能保證每一行都換行。

必須要給 label 一個固定的寬度,例如 10em。 因為如果一個label 內文字超長,文字可能會溢位,使得重置元素寬度或者擠出旁邊的表單元素,無法與其他行的元素對齊。

最後,表單通常會在網格中設計。 我們為何不試試主流瀏覽器支援的 CSS Grid 佈局呢?

相容方式

大多數 CSS Grid 文章都介紹了這些概念,而且也為舊版本的瀏覽器提供了優雅降級。 當佈局有很多裝飾性佈局的時候,這種方法是很理想的——例如,定位頁面內容、頁首、頁尾和選單。就算是少量的舊瀏覽器內展示為線性佈局,頁面也依然是可用的。

表單佈局從功能上來說,會相對重要,因為使用者如果在錯誤的框中輸入資訊會導致資訊錯誤。所以本教程採用的是一種漸進增強的方法:

  • 浮動佈局適用於所有的瀏覽器,包括 IE8 + (不支援 Flexbox)。
  • 在所有現代瀏覽器中使用 CSS Grid 來實現表單佈局

下面的例子因為樣式很少,所以直接寫在了 HTML 元素上。 這種方式 BEM 不推薦,但也能保持程式碼可讀,整潔。

我們先寫一些表單的基礎結構。

HTML

一個經典的 HTML 表單結構應該儘量保持簡潔,沒有必要用 <div> 包裹每一個鍵值對。

<form action="get">
  <fieldset>
    <legend>Your web development skillset</legend>

    <div class="formgrid">

      <input id="name" name="name" type="text" />
      <label for="name">name</label>

      <select id="experience" name="experience">
        <option value="1">1 year or less</option>
        <option value="2">2 years</option>
        <option value="3">3 - 4 years</option>
        <option value="5">5 years or more</option>
      </select>
      <label for="experience">experience</label>

      <input id="html" name="html" type="checkbox" />
      <label for="html">HTML</label>

      <input id="css" name="css" type="checkbox" />
      <label for="css">CSS</label>

      <input id="javascript" name="javascript" type="checkbox" />
      <label for="javascript">JavaScript</label>

      <textarea id="skills" name="skills" rows="5" cols="20"></textarea>
      <label for="skills">other skills</label>

      <button type="submit">SUBMIT</button>

    </div>

  </fieldset>
</form>

唯一的附加元素是 <div class="formgrid">fieldset 元素瀏覽器是無法設定 display: grid 或者 display: flex的, 所以需要一個外部容器 div 包裹。

表單佈局浮動佈局

在設定初始字型和顏色樣式之後,需要分配浮動佈局:

  • 70% 寬度向右浮動
  • 30% 寬設定給 label,向左浮動
/* fallback 30%/70% float layout */
input, output, textarea, select, button {
  clear: both;
  float: right;
  width: 70%;
}

label {
  float: left;
  width: 30%;
  text-align: right;
  padding: 0.25em 1em 0 0;
}

複選框和單選按鈕放置在 label 前,然後向左浮動。 它們的內部寬度可以自適應(width:auto) ,但要設定左邊距 30% 進行對齊:

button, input[type="checkbox"], input[type="radio"] {
  width: auto;
  float: left;
  margin: 0.5em 0.5em 0 30%;
}

input[type="checkbox"] + label, input[type="radio"] + label {
  width: auto;
  text-align: left;
}

這種方式的表單佈局適用於所有瀏覽器,包括 IE8 +

https://codepen.io/SitePoint/pen/bxVaKK

一個不認真的開發人員會認為這樣就完事兒了,但是這個表單其實還有幾個小問題:

  • 填充和邊距調整是很不穩定的,在不同瀏覽器中可能表現不一致
  • 如果需要更長的標籤文字或不同大小的字型,那麼 CSS 間距就會需要調整
  • 在小螢幕尺寸下,label 會溢位

開始使用網格

Grid 模組為了能夠建立一個有行和列的佈局,新增了 18 個新的 CSS 屬性。
模組增加了18個新的 CSS 屬性,以便建立一個有行和列的佈局。 網格內的元素可以放置在任何行/列,也可以佔多行或者多列,重疊其他元素,設定水平或垂直居中。 聽起來和 Flexbox 很相似,但是:

Flexbox 是一維的。 元素是一個挨著一個出現的,很有可能不會包裹在一個新的"行"中。 常用的案例是選單或者圖片庫

網格是二維的,同時擁有行和列。 如果一個元素對它的單元來說太大,行或列還會相應地變大。佈局頁面或者表單,網格真是再適合不過了。

CSS 網格相比基於表格的佈局, 會更靈活,需要更少的標籤。 相比其他的 CSS 屬性,網格會更加複雜一些,學起來會稍難一點,但是不需要每個屬性和值都記住,可以先了解最基本的網格在元素上的使用:

.container {
  display: grid;
}

我們在設計佈局的時候,肯定會需要知道列的數量,大小,以及行和列之間的間隔。 像這樣:

.container {
  display: grid;
  grid-template-columns: 10% 1fr 2fr 12em;
  grid-gap: 0.3em 0.6em;
}

這裡定義了四個列。單位可以用任意單位或者是 frfr 在網格佈局裡剩餘的空間內,進行比例分配。 上面的示例中第二和第三列的總共3fr。 如果有 600 畫素的水平空間可用:

1fr 等於(1fr / 3fr) * 600px = 200px
2fr 等於(2fr / 3fr) * 600px = 400px

在行之間定義 0.3em 的間隙,並在列之間定義 0.6em

.container 所有的子元素現在都屬於網格的格。 預設情況下,第一個子元素將出現在第 1 行第 1 列。 第二個子元素在第 1 行,第 2 列,第 6 個在第 2 行,第 2 列。 使用 grid-template-rows 屬性可以對行進行大小調整,但高度是由內容撐開的。

Grid 的相容性很好。在 Opera Mini 中不可用, 但 IE11 提供了一個較老的補充規範。在大多數情況下,相容設定很簡單:

  • 舊版本瀏覽器可以使用 flexboxfloatsinline-blocks 或者 display: table。所有的網格屬性都會被忽略。

  • 當瀏覽器支援 grid 時,所有的 flexboxfloatsinline-blockstable 佈局屬性會被禁用。

Grid 工具和資源:

MDN Grid Layout MDN 網格佈局
A Complete Guide to Grid 一個完整的網格指南
Grid by Example 網格例子
Grid “fallbacks” and overrides 網格"後退"和重寫
CSS Grid Playground 網格背景圖
CSS Grid Garden 網格花園
Layoutit! 用它佈局

Firefoxchrome 瀏覽器擁有開發工具和視覺化工具,支援網格佈局。

表單網格

為了逐步增強現有的表格,網格程式碼將放置在 @supports 宣告中:

/* grid layout */
@supports (display: grid) {
  ...
}

在大多數網格佈局中都沒必要這樣寫。 但這個示例需要重置所有的浮動內邊距和外邊距——需要保證這些規則只有在能使用 CSS Grid 的時候才起作用。

這個表單佈局將使用三欄設計:

這個表單的佈局:

  • label 佔一列
  • 複選框或者單選按鈕佔一列或者兩列, 右對齊
  • 複選框或者單選名稱佔三列
  • 其他元素,需要二到三列

外層容器和子元素的樣式:

.formgrid {
  display: grid;
  grid-template-columns: 1fr 1em 2fr;
  grid-gap: 0.3em 0.6em;
  grid-auto-flow: dense;
  align-items: center;
}

input, output, textarea, select, button {
  grid-column: 2 / 4;
  width: auto;
  margin: 0;
}

grid-column 定義了起始和結束的網格間隙。 間隙是兩個cells之間的邊際,所以三欄形式佈局有四個間隙:

  1. 第一列前的第一條間隙
  2. 第一列和第二列之間的間隙
  3. 第二列和第三列之間的間隙
  4. 第三列和右邊的最後一條間隙

grid-column: 2 / 4; 在間隙 2 和 4 之間填充內容,或者說列 2 和列 3 之間。

第一個 HTML 元素是 <input>。 它佔了第二列和第三列,這意味著第一列(間隙1 或者2)是空的。 因此,預設情況下,label 標籤將下降到第2行,第1列。 然而,通過設定 grid-auto-flow: dense;; 在 container 中,瀏覽器將嘗試填補網格中的空單元格,然後再進入一個新的行。

複選框和單選按鈕現在可以設定在間隙1到3(1和2列) ,justify-self: end 靠右對齊:

input[type="checkbox"], input[type="radio"] {
  grid-column: 1 / 3;
  justify-self: end;
  margin: 0;
}

網格上的 labels 將自適應於任何一行的單元格。 所以,現在不像是在浮動佈局中需要設定預設的寬度和間距:

label, input[type="checkbox"] + label, input[type="radio"] + label {
  width: auto;
  padding: 0;
  margin: 0;
}

最後,<textarea> 還可以在單元格垂直方向的頂部而不是中心:

textarea + label {
  align-self: start;
}

下面是最後一個基於網格的表單佈局:

https://codepen.io/SitePoint/pen/bxVaKK

與浮動不同,在新增不同的字型、尺寸或 labels 時需要調整設計的情況下,佈局不會因為這些小調整而打破。

網格學習

一般新的學習可能需要花幾年才能真正實行,但是 CSS Grid 有很好的支援,當你使用浮動佈局或者彈性佈局佈局很困難的時候,提供了另一種佈局的可能性。 表單是一個合適的例項,寫出來的 CSS 程式碼會很精煉。

如果你想學習另一種 CSS 技能,Grid 應該是你的首選。