在本文中,我们将了解如何在HTML表单上使用CSS,为那些难于自定义的表单组件加以样式。如前文所述,文本框和按钮很适合使用CSS,而现在我们得来探索HTML表单样式的那些坑了。

在进一步讨论前,先回顾下两种HTML表单组件:

比较糟糕的
一些元素只能使用很少的样式,而且得依赖一些复杂的技巧,偶尔还得用到CSS3的高级知识。

丑陋的
别指望用CSS给这些元素添加样式了。在最好的情况,你还能写一点不能跨浏览器支持的代码,而且还不可能完全控制这些元素的样式。

CSS的表现力

除了文本框和按钮,表单组件面临的最大问题,是CSS在多数情况下没有足够的表现力来恰当地给复杂组件添加样式。

近来HTML和CSS的演进已在拓展CSS的表现力:

虽然上述这些都是个好的开始,但其中仍有两个问题:第一,某些浏览器并不会实现CSS2.1之外的特性。第二,这些改进并未好到能处理诸如日期选择器之类的复杂组件。

浏览器厂商也为拓展CSS在表单上的表现力做了些试验,最好得了解下哪些可以使用。

警告:虽然这些实验挺有趣的,但它们并非标准、并不可靠。若你要使用它们(通常你也不会这么做),你得自己担起风险,而且使用非标准属性也是可能阻碍Web发展的做法

控制表单元素的外观

基于 WebKit- (Chrome, Safari) 和 Gecko- (Firefox) 的浏览器为HTML组件提供了最高等级的定制。这些定制也是跨平台的,所以浏览器需要一个机制来转换那些能被改变样式的表单组件的原生外观和体验。

于是它们使用了私有属性:-webkit-appearance-moz-appearance这些属性是非标准的,也不应被使用。实际上,它们在Webkit和Gecko上的表现也不尽相同。但是,有一个值是应该知道的:none,使用该值你就可以获得对组件样式的(几乎所有)控制权。

所以,若你在一个元素上应用样式时遇到问题,可以试着使用这些私有属性(译注:用none值覆盖默认值)。下面我们会看到几个例子,但最为人熟知的用例是重置Webkit浏览器上搜索框的样式。

  1. <form>
  2. <input type="search">
  3. </form>
  1. <style>
  2. input[type=search] {
  3. border: 1px dotted #999;
  4. border-radius: 0;
  5. -webkit-appearance: none;
  6. }
  7. </style>

注意:在我们讨论Web技术时,是难于预测未来的,但拓展CSS的表现力确实很难。另一些做了探索工作的标准如Shadow DOM提供了新的视角。我们对完全可配置样式的表单的追求还远未结束。

示例

多选框和单选框

给多选框和单选框添加样式是很让人凌乱的。例如,多选框和单选框的大小往往不会发生改变,而且不同浏览器的表现相当不同。

一个简单例子

考虑如下示例:

  1. <span><input type="checkbox"></span>
  1. span {
  2. display: inline-block;
  3. background: red;
  4. }
  5. input[type=checkbox] {
  6. width : 100px;
  7. height: 100px;
  8. }

不同浏览器的处理如下:

浏览器 渲染效果
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还能找出解决办法来。举一个常见的例子:

  1. <form>
  2. <fieldset>
  3. <p>
  4. <input type="checkbox" id="first" name="fruit-1" value="cherry">
  5. <label for="first">I like cherry</label>
  6. </p>
  7. <p>
  8. <input type="checkbox" id="second" name="fruit-2" value="banana" disabled>
  9. <label for="second">I can't like banana</label>
  10. </p>
  11. <p>
  12. <input type="checkbox" id="third" name="fruit-3" value="strawberry">
  13. <label for="third">I like strawberry</label>
  14. </p>
  15. </fieldset>
  16. </form>

加一些基本样式:

  1. body {
  2. font: 1em sans-serif;
  3. }
  4. form {
  5. display: inline-block;
  6. padding: 0;
  7. margin : 0;
  8. }
  9. fieldset {
  10. border : 1px solid #CCC;
  11. border-radius: 5px;
  12. margin : 0;
  13. padding: 1em;
  14. }
  15. label {
  16. cursor : pointer;
  17. }
  18. p {
  19. margin : 0;
  20. }
  21. p+p {
  22. margin : .5em 0 0;
  23. }

现在,我们来加样式以获得一个定制的复选框。

我们的计划是用我们自己的图像来替换原生的复选框。首先得准备一张具有所有复选框所需状态的图像,这些状态有:未勾选、已勾选、禁用未勾选、禁用已勾选。该图像可用CSS雪碧图来做:

先从隐藏原生的复选框开始,我们只是简单地把它们从页面的可视范围中挪出。这里有两个要重点考虑的事:

  • 别使用display:none来隐藏复选框,因为如前面提到的,我们需要保证复选框对用户可用。使用display:none的话,复选框就不再是用户可访问的,即不能再勾选或者不勾选它。

  • 我们将使用一些CSS3选择器来实现我们的样式。为支持老旧浏览器,可以在我们要用的选择器前加:root伪类。在已有的实现中,支持我们需要的选择器的浏览器也支持:root伪类,而剩下的浏览器就不支持了。所以这是一种用来识别老旧浏览器的方便做法,老旧浏览器中将会看到普通的复选框、而现代浏览器中将会看到定制的复选框。

  1. :root input[type=checkbox] {
  2. /* 原生的复选框会从页面的可视范围中被挪出 */
  3. position: absolute;
  4. left: -1000em;
  5. }

现在我们已经移除了原生的复选框,可以添加我们自己的了,这里会在原生复选框后面的<label>元素使用:before伪元素。下面的选择器中,我们先用属性选择器来获取复选框;然后使用相邻兄弟选择器来获取原来复选框后的label。最后我们通过给:before伪元素添加样式,用其来显示我们定制的复选框。

  1. :root input[type=checkbox] + label:before {
  2. content: "";
  3. display: inline-block;
  4. width : 16px;
  5. height : 16px;
  6. margin : 0 .5em 0 0;
  7. background: url("https://developer.mozilla.org/files/4173/checkbox-sprite.png") no-repeat 0 0;
  8. /* 下一属性用于在文本基线调整复选框的位置 */
  9. vertical-align: bottom;
  10. position: relative;
  11. bottom: 2px;
  12. }

接下来用原来复选框的:checked:disabled伪类来改变我们定制的复选框的状态。由于我们使用了CSS雪碧图,我们只需要调整背景的位置而已。

  1. :root input[type=checkbox]:checked + label:before {
  2. background-position: 0 -16px;
  3. }
  4. :root input[type=checkbox]:disabled + label:before {
  5. background-position: 0 -32px;
  6. }
  7. :root input[type=checkbox]:checked:disabled + label:before {
  8. background-position: 0 -48px;
  9. }

最后也是很重要的一步:当用户使用键盘在不同表单组件间浏览时,每个组件应该能看到聚焦的效果。由于我们隐藏了原生的复选框,所以只能自己实现这一特性来让用户知晓他们正处于何处。下列的CSS实现了对我们的定制复选框的聚焦:

  1. :root input[type=checkbox]:focus + label:before {
  2. outline: 1px dotted black;
  3. }

最终效果如下:

演示

处理选择框噩梦

<select>元素被认为是一个“丑陋的”组件,因为不太可能给它添加跨平台的样式。当然,还是有一些可以探讨的东西的,这里就不长篇大论了,先看个例子:

  1. <select>
  2. <option>Cherry</option>
  3. <option>Banana</option>
  4. <option>Strawberry</option>
  5. </select>
  1. select {
  2. width : 80px;
  3. padding : 10px;
  4. }
  5. option {
  6. padding : 5px;
  7. color : red;
  8. }

后面的表格展示了不同浏览器如何在两种情况下处理这一样式。(渲染效果中)前两列只是简单的例子,后两列则使用了些定制的CSS来获得对组件外观的更多控制,如下所示:

  1. select, option {
  2. -webkit-appearance : none; /* 获得对Webkit浏览器里外观的控制 */
  3. -moz-appearance : none; /* 获得对Gecko浏览器里外观的控制 */
  4. /* 获得对Presto (Opera) 和 Trident (IE)浏览器里外观的控制
  5. 注意这也能在Gecko浏览器里起作用,且对Webkit浏览器有副作用 */
  6. background : none;
  7. }
浏览器 普通渲染(关闭) 普通渲染(打开) 调整后渲染(关闭) 调整后渲染(打开)
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属性的支持程度:[表单组件的属性兼容表]()。

参见

【译】HTML表单高级样式的更多相关文章

  1. HTML表单 CSS样式

    1.HTML表单 <body rightmargin="50" leftmargin="50" background="未标题-1.jpg&qu ...

  2. css修改input表单默认样式重置与自定义大全

    链接地址: 伪元素表单控件默认样式重置与自定义大全 http://www.zhangxinxu.com/wordpress/?p=3381 Chrome 现在不支持通过伪元素修改 meter 元素样式 ...

  3. BootStrap的table表格,栅格系统,form表单的样式

    BootStrap BootStrap的简介 1.    什么是Bootstrap 由两个前端设计师开发的一个前端的框架(Html,css,js) 简化了程序员写css的代码 2.    为什么使用B ...

  4. ios下表单disabled样式重置

    在做最近的一个活动项目时,需要用到表单的disabled状态,但是在IOS下那颜色不是一般的浅,就跟没有一样,一开始通过如下样式重置: input:disabled, input[disabled]{ ...

  5. validform.js+layer.js 表单验证样式

    $("#formAdd").Validform({ tiptype: function (msg, o, cssctl) { if (o.type == 3) {//失败 laye ...

  6. Bootstrap表单布局样式

    1.并排和下拉选项 <form class="form-horizontal" role="form"> <fieldset> < ...

  7. 推荐的bootstrap之 formgroup表单布局样式

    一直没能找到比较好的Form Group样式,直到找到如下样式 转自 https://www.cnblogs.com/jokerjason/p/5721349.html <form class= ...

  8. [moka同学笔记]yii表单dropdownlist样式

    <?= $form->field($modelUser,'name') ?> <div class="form-group field-community-mobil ...

  9. Yii2 ActiveForm表单自定义样式

    实例: <?php $form = ActiveForm::begin([ 'fieldConfig' => [ 'template' => '<div class=" ...

随机推荐

  1. CSS/CSS3语法新特性笔记

    CSS层叠样式表 三大特性 层叠性:相同的样式会覆盖 继承性:属性可向下继承 优先级:范围越小权重越高 选择器 基础选择器 标签选择器 1 body { 2 color:#fff; 3 } 类选择器 ...

  2. Json字符串和Json对象相互转换

    字符串-->json对象:JSON.parse() var str = '{"code":"A001","name":"张三 ...

  3. ibv_get_device_list()函数

    struct ibv_device** ibv_get_device_list(int *num_devices); 描述 函数用来返回一个当前可用的RDMA设备数组. 注意 数组以NULL结尾: R ...

  4. DBScan聚类,打破形状的限制,使用密度聚类

    如何用花盆摆放成国庆字,并且包围这两个字. 在DBSCAN中衡量密度主要使用的指标:半径.最少样本量 算法原理 *直接密度可达 如果一个点在核心对象的半径区域内,那么这个点和核心对象称为直接密度可达, ...

  5. tensorflow源码解析之framework-shape_inference

    目录 什么是形状推断 InferenceContext 关系图 涉及的文件 迭代记录 1. 什么是形状推断 前面我们讲到op的时候,提到了操作的注册器OpRegistry,并且提到,其中注册的数据是一 ...

  6. LGP6011题解

    昨天考试考到了这道题,那就来补一下题解吧. 题意简单不再阐述. 首先删除之后还要向左移动,很容易想到 ODT 平衡树,这个过于一眼,不再阐述. 重点说第二种方法. 向左平移的这个操作,我们是否可以用别 ...

  7. 使用阿里云镜像站NTP服务搭建NTP服务器(基于CentOS 7系统)

    镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 一.NTP服务器介绍 网络时间协议(Network Time Protocol,NTP)服务器,也就是日常所说的NTP服务器,用来提供同步时间服务 ...

  8. MariaDB开启日志审计功能

    对于MySQL.Percona.MariaDB三家都有自己的审计插件,但是MySQL的审计插件是只有企业版才有的,同时也有很多第三方的的MySQL的审计插件,而Percona和MariaDB都是GPL ...

  9. Elman network with additional notes

    // Author: John McCullock // Date: 10-15-05 // Description: Elman Network Example 1. //http://www.mn ...

  10. Kafka消息是采用Pull模式,还是Push模式?

    Kafka最初考虑的问题是,customer应该从brokes拉取消息还是brokers将消息推送到consumer,也就是pull还push.在这方面,Kafka遵循了一种大部分消息系统共同的传统的 ...