為網頁表單新增樣式

在前面的幾篇文章中,我們展示瞭如何在 HTML 中建立網頁表單。現在,我們將展示如何在 CSS 中為它們設定樣式。

預備知識 HTMLCSS 樣式基礎有基本的瞭解。
目標 瞭解表單樣式背後的問題,並學習一些對你有用的基本樣式技術。

表單小部件樣式設定的挑戰

History

1995 年,HTML 2 規範引入了表單控制元件(又稱“表單小部件”或“表單元素”)。但 CSS 直到 1996 年底才釋出,並且在幾年後才被大多數瀏覽器支援;因此,在此期間,瀏覽器依賴底層作業系統來渲染表單小部件。

即使有了 CSS,瀏覽器廠商最初也不願讓表單元素可樣式化,因為使用者太習慣於各自瀏覽器的外觀。但情況已經發生了變化,現在表單小部件大多可以樣式化,只有少數例外。

小部件型別

易於樣式化

  1. <form>
  2. <fieldset><legend>
  3. 單行文字 <input>s(例如,type 為 text、url、email),除了 <input type="search">
  4. 多行 <textarea>
  5. 按鈕(<input><button> 均可)
  6. <label>
  7. <output>

較難樣式化

文章 高階表單樣式 展示瞭如何為這些設定樣式。

內部結構無法僅透過 CSS 樣式化

例如,日期選擇器日曆以及點選時顯示選項列表的 <select> 上的按鈕無法僅使用 CSS 進行樣式設定。

文章 高階表單樣式如何構建自定義表單控制元件 描述瞭如何為這些設定樣式。

注意:一些專有的 CSS 偽元素,例如 ::-moz-range-track,能夠為這些內部元件設定樣式,但這些在不同瀏覽器之間不一致,因此不是很可靠。我們稍後會提到這些。

為簡單的表單小部件設定樣式

上一節中的“易於樣式化”小部件可以使用文章 你的第一個表單CSS 構建塊 中的技術進行樣式設定。還有一些特殊的選擇器——UI 偽類——可以根據 UI 的當前狀態進行樣式設定。

我們將在本文末尾透過一個示例進行演示——但首先,這裡有一些值得了解的表單樣式方面的特殊之處。

字型和文字

CSS 字型和文字功能可以輕鬆地與任何小部件一起使用(是的,你可以在表單小部件中使用 @font-face)。然而,瀏覽器行為通常不一致。預設情況下,某些小部件不會從其父級繼承 font-familyfont-size。許多瀏覽器而是使用系統的預設外觀。為了使你的表單外觀與內容的其餘部分保持一致,你可以在樣式表中新增以下規則

css
button,
input,
select,
textarea {
  font-family: inherit;
  font-size: 100%;
}

inherit 屬性值使屬性值與其父元素的屬性的計算值匹配;繼承父級的值。

下面的螢幕截圖顯示了差異。左側是 macOS 上 Chrome 中 <input type="text"><input type="date"><select><textarea><input type="submit"><button> 的預設渲染,使用了平臺的預設字型樣式。右側是相同的元素,應用了我們上面的樣式規則。

Form controls with default and inherited font families. By default, some types are serif and others are sans serif. Inheriting should change the fonts of all to the parent's font family - in this case a paragraph. Oddly, input of type submit does not inherit from the parent paragraph.

預設設定在很多方面有所不同。繼承應該將它們的字型更改為父級的字體系列——在這種情況下,是父容器的預設襯線字型。它們都這樣做了,只有一個奇怪的例外——<input type="submit"> 在 Chrome 中不從父段落繼承。相反,它使用 font-family: system-ui。這是使用 <button> 元素而不是其等效輸入型別的另一個原因!

關於表單是使用系統預設樣式看起來更好,還是使用旨在匹配你內容的自定義樣式看起來更好,有很多爭論。這個決定由你作為網站或 Web 應用程式的設計師來做出。

盒模型

所有文字欄位都完全支援與 CSS 盒模型相關的每個屬性,例如 widthheightpaddingmarginborder。然而,與以前一樣,瀏覽器在顯示這些小部件時依賴於系統預設樣式。如何將它們融入你的內容取決於你。如果你想保持小部件的原生外觀和感覺,那麼如果你想為它們提供一致的大小,你會遇到一些困難。

這是因為每個小部件都有自己的邊框、填充和邊距規則。要為幾個不同的小部件提供相同的大小,你可以使用 box-sizing 屬性以及其他屬性的一些一致值

css
input,
textarea,
select,
button {
  width: 150px;
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

在下面的螢幕截圖中,左欄顯示了 <input type="radio"><input type="checkbox"><input type="range"><input type="text"><input type="date"><select><textarea><input type="submit"><button> 的預設渲染。右欄則顯示了應用了我們上面規則的相同元素。請注意,這如何讓我們確保所有元素佔據相同的空間,儘管平臺對每種型別的小部件都有預設規則。

box model properties effect most input types.

螢幕截圖可能不明顯的是,單選按鈕和複選框控制元件看起來仍然相同,但它們居中在 width 屬性提供的 150 畫素水平空間中。其他瀏覽器可能不會使小部件居中,但它們確實遵守了分配的空間。

圖例放置

<legend> 元素可以設定樣式,但控制其位置可能有點棘手。預設情況下,它總是位於其 <fieldset> 父級的頂部邊框上方,靠近左上角。要將其放置在其他位置,例如在欄位集內部的某個位置,或靠近左下角,你需要依賴定位。

請看以下示例

為了以這種方式定點陣圖例,我們使用了以下 CSS(為簡潔起見,省略了其他宣告)

css
fieldset {
  position: relative;
}

legend {
  position: absolute;
  bottom: 0;
  right: 0;
}

<fieldset> 也需要定位,以便 <legend> 相對於它定位(否則 <legend> 將相對於 <body> 定位)。

<legend> 元素對於可訪問性非常重要——輔助技術會將其作為欄位集內每個表單元素的標籤的一部分進行朗讀——但使用上述技術是沒問題的。圖例內容仍然會以相同的方式朗讀;只是視覺位置發生了變化。

注意:你還可以使用 transform 屬性來幫助你定位 <legend>。但是,當你使用例如 transform: translateY(); 定位它時,它會移動,但在 <fieldset> 邊框中留下一個難看的間隙,這不容易去除。

一個具體的樣式示例

讓我們看一個如何為 HTML 表單設定樣式的具體示例。我們將構建一個看起來很漂亮的“明信片”聯絡表單;點選此處檢視完成版本

如果你想跟著這個示例操作,請下載我們的 postcard-start.html 檔案的本地副本,並按照以下說明操作。

HTML

HTML 只比我們在 你的第一個表單 中使用的示例稍微複雜一點;它只多了一些 ID 和一個標題。

html
<form>
  <h1>to: Mozilla</h1>

  <div id="from">
    <label for="name">from:</label>
    <input type="text" id="name" name="user_name" />
  </div>

  <div id="reply">
    <label for="mail">reply:</label>
    <input type="email" id="mail" name="user_email" />
  </div>

  <div id="message">
    <label for="msg">Your message:</label>
    <textarea id="msg" name="user_message"></textarea>
  </div>

  <div class="button">
    <button type="submit">Send your message</button>
  </div>
</form>

將上述程式碼新增到 HTML 的 body 中。

組織你的資產

這才是樂趣的開始!在開始編碼之前,我們需要另外三個資產

  1. 明信片背景 — 下載此圖片並將其儲存在與你的 HTML 工作檔案相同的目錄中。
  2. 一種打字機字型:來自 dafont.com 的“Mom's Typewriter”字型 — 將 TTF 檔案下載到與上面相同的目錄中。
  3. 一種手繪字型:來自 dafont.com 的“Journal”字型 — 將 TTF 檔案下載到與上面相同的目錄中。

你的字型在開始之前還需要一些額外的處理

  1. 訪問 fontsquirrel.com Webfont Generator
  2. 使用表單上傳你的字型檔案並生成一個 webfont kit。將 kit 下載到你的計算機。
  3. 解壓縮提供的 zip 檔案。
  4. 在解壓縮的內容中,你會找到一些字型檔案(在撰寫本文時,是兩個 .woff 檔案和兩個 .woff2 檔案;將來可能會有所不同)。將這些檔案複製到一個名為 fonts 的目錄中,與之前在同一目錄中。我們為每種字型使用兩個不同的檔案以最大限度地提高瀏覽器相容性;有關更多資訊,請參閱我們的 Web 字型 文章。

CSS

現在我們可以深入研究示例的 CSS。將下面顯示的所有程式碼塊一個接一個地新增到 <style> 元素中。

整體佈局

首先,我們透過定義 @font-face 規則以及 <body><form> 元素上設定的所有基本樣式來準備。如果 fontsquirrel 的輸出與我們上面描述的不同,你可以在你下載的 webfont kit 中的 stylesheet.css 檔案中找到正確的 @font-face 塊(你需要用它們替換下面的 @font-face 塊,並更新字型檔案的路徑)

css
@font-face {
  font-family: "handwriting";
  src:
    url("fonts/journal-webfont.woff2") format("woff2"),
    url("fonts/journal-webfont.woff") format("woff");
  font-weight: normal;
  font-style: normal;
}

@font-face {
  font-family: "typewriter";
  src:
    url("fonts/momot___-webfont.woff2") format("woff2"),
    url("fonts/momot___-webfont.woff") format("woff");
  font-weight: normal;
  font-style: normal;
}

body {
  font: 1.3rem sans-serif;
  padding: 0.5em;
  margin: 0;
  background: #222222;
}

form {
  position: relative;
  width: 740px;
  height: 498px;
  margin: 0 auto;
  padding: 1em;
  box-sizing: border-box;
  background: white url("background.jpg");

  /* we create our grid */
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: 10em 1em 1em 1em;
}

請注意,我們使用了一些 CSS 網格Flexbox 來佈局表單。透過這種方式,我們可以輕鬆定位我們的元素,包括標題和所有表單元素

css
h1 {
  font:
    1em "typewriter",
    monospace;
  align-self: end;
}

#message {
  grid-row: 1 / 5;
}

#from,
#reply {
  display: flex;
}

標籤和控制元件

現在我們可以開始處理表單元素本身了。首先,讓我們確保 <label> 獲得正確的字型

css
label {
  font:
    0.8em "typewriter",
    sans-serif;
}

文字欄位需要一些通用規則。換句話說,我們刪除它們的 bordersbackgrounds,並重新定義它們的 paddingmargin

css
input,
textarea {
  font:
    1.4em/1.5em "handwriting",
    cursive,
    sans-serif;
  border: none;
  padding: 0 10px;
  margin: 0;
  width: 80%;
  background: none;
}

當這些欄位之一獲得焦點時,我們用淺灰色透明背景突出顯示它們(為提高可用性和鍵盤可訪問性,始終擁有焦點樣式很重要)

css
input:focus,
textarea:focus {
  background: rgb(0 0 0 / 10%);
  border-radius: 5px;
}

現在我們的文字欄位已完成,我們需要調整單行和多行文字欄位的顯示以匹配,因為它們通常在預設情況下看起來不一樣。

調整文字區域

<textarea> 元素預設渲染為行內塊元素。這裡重要的兩件事是 resizeoverflow 屬性。雖然我們的設計是固定大小的設計,我們可以使用 resize 屬性來阻止使用者調整我們的多行文字欄位的大小,但最好不要阻止使用者調整文字區域的大小。 overflow 屬性用於使欄位在不同瀏覽器中渲染更一致。某些瀏覽器預設值為 auto,而某些瀏覽器預設值為 scroll。在我們的例子中,最好確保所有人都使用 auto

css
textarea {
  display: block;

  padding: 10px;
  margin: 10px 0 0 -10px;
  width: 100%;
  height: 90%;

  border-right: 1px solid;

  /* resize  : none; */
  overflow: auto;
}

設定提交按鈕樣式

<button> 元素使用 CSS 設定樣式非常方便;你可以做任何你想做的事情,甚至使用 偽元素

css
button {
  padding: 5px;
  font: bold 0.6em sans-serif;
  border: 2px solid #333333;
  border-radius: 5px;
  background: none;
  cursor: pointer;
  transform: rotate(-1.5deg);
}

button::after {
  content: " >>>";
}

button:hover,
button:focus {
  background: black;
  color: white;
}

最終結果

瞧!你的表單現在應該看起來像這樣

The final look and layout of the form after applying all styling and tweaking to it as described above

注意:如果你的示例沒有達到你的預期,並且你想與我們的版本進行比較,你可以在 GitHub 上找到它——檢視即時執行(另請參閱原始碼)。

總結

如你所見,只要我們想用純文字欄位和按鈕構建表單,使用 CSS 設定它們的樣式就很容易。在下一篇文章中,我們將瞭解如何處理屬於“差”和“醜”類別的表單小部件。