在本文中,我們將了解如何在HTML表單上使用CSS,為那些難於自定義的表單組件加以樣式。如前文所述,文本框和按鈕很適合使用CSS,而現在我們得來探索HTML表單樣式的那些坑了。
在進一步討論前,先回顧下兩種HTML表單組件:
比較糟糕的
一些元素只能使用很少的樣式,而且得依賴一些復雜的技巧,偶爾還得用到CSS3的高級知識。
丑陋的
別指望用CSS給這些元素添加樣式了。在最好的情況,你還能寫一點不能跨瀏覽器支持的代碼,而且還不可能完全控制這些元素的樣式。
CSS的表現力
除了文本框和按鈕,表單組件面臨的最大問題,是CSS在多數情況下沒有足夠的表現力來恰當地給復雜組件添加樣式。
近來HTML和CSS的演進已在拓展CSS的表現力:
-
CSS2.1很受限,只提供了三個偽類:
-
CSS Selector Level 3新增了幾個和HTML表單相關的偽類:
-
CSS Basic UI Level 3也添加了幾個偽類用於描述組件狀態:
-
CSS Selector Level 4正處於開發狀態,而且討論的重點並不在於增加更多內容以改進表單:
:user-error只是
:invalid
偽類的一個增強版、
雖然上述這些都是個好的開始,但其中仍有兩個問題:第一,某些瀏覽器並不會實現CSS2.1之外的特性。第二,這些改進並未好到能處理諸如日期選擇器之類的復雜組件。
瀏覽器廠商也為拓展CSS在表單上的表現力做了些試驗,最好得了解下哪些可以使用。
警告:雖然這些實驗挺有趣的,但它們並非標准、並不可靠。若你要使用它們(通常你也不會這么做),你得自己擔起風險,而且使用非標准屬性也是可能阻礙Web發展的做法。
控制表單元素的外觀
基於 WebKit- (Chrome, Safari) 和 Gecko- (Firefox) 的瀏覽器為HTML組件提供了最高等級的定制。這些定制也是跨平台的,所以瀏覽器需要一個機制來轉換那些能被改變樣式的表單組件的原生外觀和體驗。
於是它們使用了私有屬性:-webkit-appearance 或 -moz-appearance。這些屬性是非標准的,也不應被使用。實際上,它們在Webkit和Gecko上的表現也不盡相同。但是,有一個值是應該知道的:none
,使用該值你就可以獲得對組件樣式的(幾乎所有)控制權。
所以,若你在一個元素上應用樣式時遇到問題,可以試着使用這些私有屬性(譯注:用none
值覆蓋默認值)。下面我們會看到幾個例子,但最為人熟知的用例是重置Webkit瀏覽器上搜索框的樣式。
<form>
<input type="search">
</form>
<style>
input[type=search] {
border: 1px dotted #999;
border-radius: 0;
-webkit-appearance: none;
}
</style>
注意:在我們討論Web技術時,是難於預測未來的,但拓展CSS的表現力確實很難。另一些做了探索工作的標准如Shadow DOM提供了新的視角。我們對完全可配置樣式的表單的追求還遠未結束。
示例
多選框和單選框
給多選框和單選框添加樣式是很讓人凌亂的。例如,多選框和單選框的大小往往不會發生改變,而且不同瀏覽器的表現相當不同。
一個簡單例子
考慮如下示例:
<span><input type="checkbox"></span>
span {
display: inline-block;
background: red;
}
input[type=checkbox] {
width : 100px;
height: 100px;
}
不同瀏覽器的處理如下:
瀏覽器 | 渲染效果 |
---|---|
Firefox 16 (Mac OSX) | ![]() |
Chrome 22 (Mac OSX) | ![]() |
Opera 12.01 (Mac OSX) | ![]() |
Internet Explorer 9 (Windows 7) | ![]() |
Internet Explorer 7 (Windows XP) | ![]() |
復雜點的例子
由於Opera和IE沒有諸如-webkit-appearance
和-moz-appearance
之類的特性,所以使用這類特性是不太合適的。幸運的是,在這種情況下用CSS還能找出解決辦法來。舉一個常見的例子:
<form>
<fieldset>
<p>
<input type="checkbox" id="first" name="fruit-1" value="cherry">
<label for="first">I like cherry</label>
</p>
<p>
<input type="checkbox" id="second" name="fruit-2" value="banana" disabled>
<label for="second">I can't like banana</label>
</p>
<p>
<input type="checkbox" id="third" name="fruit-3" value="strawberry">
<label for="third">I like strawberry</label>
</p>
</fieldset>
</form>
加一些基本樣式:
body {
font: 1em sans-serif;
}
form {
display: inline-block;
padding: 0;
margin : 0;
}
fieldset {
border : 1px solid #CCC;
border-radius: 5px;
margin : 0;
padding: 1em;
}
label {
cursor : pointer;
}
p {
margin : 0;
}
p+p {
margin : .5em 0 0;
}
現在,我們來加樣式以獲得一個定制的復選框。
我們的計划是用我們自己的圖像來替換原生的復選框。首先得准備一張具有所有復選框所需狀態的圖像,這些狀態有:未勾選、已勾選、禁用未勾選、禁用已勾選。該圖像可用CSS雪碧圖來做:
先從隱藏原生的復選框開始,我們只是簡單地把它們從頁面的可視范圍中挪出。這里有兩個要重點考慮的事:
別使用
display:none
來隱藏復選框,因為如前面提到的,我們需要保證復選框對用戶可用。使用display:none
的話,復選框就不再是用戶可訪問的,即不能再勾選或者不勾選它。我們將使用一些CSS3選擇器來實現我們的樣式。為支持老舊瀏覽器,可以在我們要用的選擇器前加:root偽類。在已有的實現中,支持我們需要的選擇器的瀏覽器也支持
:root
偽類,而剩下的瀏覽器就不支持了。所以這是一種用來識別老舊瀏覽器的方便做法,老舊瀏覽器中將會看到普通的復選框、而現代瀏覽器中將會看到定制的復選框。
:root input[type=checkbox] {
/* 原生的復選框會從頁面的可視范圍中被挪出 */
position: absolute;
left: -1000em;
}
現在我們已經移除了原生的復選框,可以添加我們自己的了,這里會在原生復選框后面的<label>
元素使用:before偽元素。下面的選擇器中,我們先用屬性選擇器來獲取復選框;然后使用相鄰兄弟選擇器來獲取原來復選框后的label
。最后我們通過給:before
偽元素添加樣式,用其來顯示我們定制的復選框。
:root input[type=checkbox] + label:before {
content: "";
display: inline-block;
width : 16px;
height : 16px;
margin : 0 .5em 0 0;
background: url("https://developer.mozilla.org/files/4173/checkbox-sprite.png") no-repeat 0 0;
/* 下一屬性用於在文本基線調整復選框的位置 */
vertical-align: bottom;
position: relative;
bottom: 2px;
}
接下來用原來復選框的:checked和:disabled偽類來改變我們定制的復選框的狀態。由於我們使用了CSS雪碧圖,我們只需要調整背景的位置而已。
:root input[type=checkbox]:checked + label:before {
background-position: 0 -16px;
}
:root input[type=checkbox]:disabled + label:before {
background-position: 0 -32px;
}
:root input[type=checkbox]:checked:disabled + label:before {
background-position: 0 -48px;
}
最后也是很重要的一步:當用戶使用鍵盤在不同表單組件間瀏覽時,每個組件應該能看到聚焦的效果。由於我們隱藏了原生的復選框,所以只能自己實現這一特性來讓用戶知曉他們正處於何處。下列的CSS實現了對我們的定制復選框的聚焦:
:root input[type=checkbox]:focus + label:before {
outline: 1px dotted black;
}
最終效果如下:
處理選擇框噩夢
<select>
元素被認為是一個“丑陋的”組件,因為不太可能給它添加跨平台的樣式。當然,還是有一些可以探討的東西的,這里就不長篇大論了,先看個例子:
<select>
<option>Cherry</option>
<option>Banana</option>
<option>Strawberry</option>
</select>
select {
width : 80px;
padding : 10px;
}
option {
padding : 5px;
color : red;
}
后面的表格展示了不同瀏覽器如何在兩種情況下處理這一樣式。(渲染效果中)前兩列只是簡單的例子,后兩列則使用了些定制的CSS來獲得對組件外觀的更多控制,如下所示:
select, option {
-webkit-appearance : none; /* 獲得對Webkit瀏覽器里外觀的控制 */
-moz-appearance : none; /* 獲得對Gecko瀏覽器里外觀的控制 */
/* 獲得對Presto (Opera) 和 Trident (IE)瀏覽器里外觀的控制
注意這也能在Gecko瀏覽器里起作用,且對Webkit瀏覽器有副作用 */
background : none;
}
瀏覽器 | 普通渲染(關閉) | 普通渲染(打開) | 調整后渲染(關閉) | 調整后渲染(打開) |
---|---|---|---|---|
Firefox 16 (Mac OSX) | ![]() |
![]() |
![]() |
![]() |
Firefox 16 (Windows 7) | ![]() |
![]() |
![]() |
![]() |
Chrome 22 (Mac OSX) | ![]() |
![]() |
![]() |
![]() |
Chrome 22 (Windows 7) | ![]() |
![]() |
![]() |
![]() |
Opera 12.01 (Mac OSX) | ![]() |
![]() |
![]() |
![]() |
Internet Explorer 9 (Windows 7) | ![]() |
![]() |
N/A | N/A |
Internet Explorer 7 (Windows XP) | ![]() |
![]() |
N/A | N/A |
如你所見,即使使用了 -*-qppearance
屬性,仍會有問題存在:
padding屬性在不同操作系統和瀏覽器中的處理是不一致的。
老舊的IE不支持平滑的樣式。
火狐沒有能給予下拉箭頭樣式的方式。
若想要給下拉菜單中的
<option>
元素以樣式,則Chrome和Opera在不同系統下的表現不盡相同。
同時,在本例中,我們只討論了三個CSS屬性;想想要考慮更多的CSS屬性會有多么混亂。可見,CSS確實不太適合用來改變這些組件的外觀和體驗,但它仍讓你能做些調整,如果你願意忍受不同瀏覽器或不同操作系統上的不同的話。
我們將在下篇文章:[表單組件的屬性兼容表]()中嘗試指出哪些屬性是可用的。
通向漂亮表單之路:一些有用的庫和拓展工具
盡管CSS在復選框和單選框上的表現力已經夠用了,但離其支持高級表單組件仍然遙遙無期。即使在<select>
元素上有一些可能,但文件組件、日期選擇器等仍不能被添加樣式。
若你想獲得對表單組件的完整控制權,你就得依賴Javascript,別無選擇。在[怎樣創建定制表單組件]()一文中,我們將了解如何自己實現它,而如今有一些很有用的庫可以幫到你:
Uni-form是一個規范了表單格式和使用CSS給予表單樣式的框架。在和jQuery一起使用時,它也提供了些額外的可選特性。
Formalize是一些常見Javascript框架(如jQuery、Dojo、YUI等)的一個插件,用於規范化和定制表單。
Niceforms是個提供了完整web表單定制的獨立Javascript方法。你可以使用一些內建的主題、也可自己創建。
下面幾個庫則不止用於處理表單,但它們在處理HTML表單時有很多有趣的特性:
jQuery UI提供了些非常有趣的可定制高級組件,比如日期選擇器(特別關注了無障礙訪問)。
Twitter Bootstrap非常有用,如果你想規范化你的表單的話。
WebShim是一個龐大的工具,用於處理那些支持HTML5的瀏覽器。其web表單部分挺有用的。
要知道,綁定CSS和Javascript會引起副作用。所以若你選擇了上述的一種庫,就得時常保證在腳本失效時會可回退的樣式表。造成腳本失效的原因很多,特別在移動端,故你的Web站點或app設計得能最好地處理這些情況。
結論
當在HTML表單上使用CSS仍存在許多坑時,有很多方法可以繞過這些坑。本來是沒有確切、通用的解決方案的,但現代瀏覽器帶來了新可能。而現在,最佳方案是研究不同瀏覽器對用在HTML表單組件的CSS的支持程度。
下篇文章,我們將探索各種HTML表單組件對那些最重要的CSS屬性的支持程度:[表單組件的屬性兼容表]()。