2.表单
表单是用户输入内容的地方。表单涉及的控件很多,而且一直很难给它们应用样式。无法控制样式的部分,可以通过自定义控件来解决。
2.1 简单的表单
2.1.1 fieldset与legend
fieldset
用于分组相关信息块,legend
表明每个fieldset的目的。
<fieldset> <legend>Your contact details</legend> <!-- 省略 --> </fieldset>
2.1.2 字段名
label
元素用于给每个表单元素添加一个有意义的描述性的名字。在多数浏览器中,点击label元素也会把输入焦点定位到相关的表单元素。
label最大的作用是为使用辅助设备的人增强表单可用性。
将label
与具体表单元素相关联的方式:
1、隐式的:
<label>Email <input name="comment-email" type="email" /></label>
2、显式的:
<!-- 把label的for属性设为与相关表单控件的id属性相同的值。 --> <label for="comment-email">Email Address:</label> <input name="comment-email" id="comment-email" type="email" />
每个表单控件几乎都会有name和id属性。id属性是表单输入字段与label
元素间建立联系的关键,name属性则是表单正确地将数据提交给服务器的关键。
id和name值可以不一样,但为了保持一致性,让它们相同比较好。
2.1.3 输入字段与文本区
textarea
元素用于输入多行文本,通过cols和rows设置文本区默认的宽度和高度。
<textarea name="comment-text" id="comment-text" cols="20" rows="10"></textarea>
input
元素是个多面手。默认情况下,它被浏览器渲染为一个单行文本输入框,即type属性的默认值是text。
HTML5扩展了type属性。
在有屏幕键盘的设备上,改变type的值会触发软键盘布局相应改变。
2.1.4 把fieldset整合起来
<form id="comments_form" action="/comments/" method="post"> <div class="fieldset-wrapper"> <fieldset> <legend>Your contact details</legend> <p class="field field-text"> <label for="comment-author">Name:</label> <input name="comment-author" id="comment-author" type="text" /> </p> <!-- 省略 --> </fieldset> </div> <!-- 省略 --> <p class="field-submit"> <button id="submit" class="submit" name="submit" type="submit">Post comment</button> </p> </form>
/* 去掉fieldset的默认样式 */ fieldset { border: 0; padding: 0.01em 0 0 0; margin: 0; min-width: 0; } @-moz-document url-prefix() { fieldset { display: table-cell; } }
/* 给fieldset的包装元素应用样式。 */ .fieldset-wrapper { padding: 1em; margin-bottom: 1em; border: 1px solid #eee; background-color: #fff; Box-shadow: 0 0 .25em rgba(0,0.25); } /* :root引用的是HTML元素(文本根元素) */ :root .fieldset-wrapper { /* 不支持Box-shadow的浏览器只会显示边框,这里去掉这个边框 */ border: 0; }
legend { /* 去掉legend的默认样式 */ padding: 0 0 .5em 0; font-weight: bold; color: #777; display: table; }
2.1.5 文本输入控件
input,textarea { font: inherit; }
默认情况下,label
是一个行内元素。文本输入框的默认宽度取决于浏览器。
.field-text { max-width: 20em; } .field-text label { cursor: pointer; } .field-text label,.field-text input { width: 100%; Box-sizing: border-Box; }
将宽度设置为百分比(width: 100%
),同时再用em
单位给它设置一个最大宽度(max-width: 20em
),可以实现可伸缩的输入字段,且不会过宽。
设置文本输入框的样式:
.field-text input,.field-text textarea { padding: .375em .3125em .3125em; /* 内边距 */ border: 1px solid #ccc; /* 边框 */ border-radius: .25em; /* 边框圆角 */ }
2.1.6 处理聚焦状态
设置input元素获得焦点时的样式:
.field-text :focus { outline: 0; Box-shadow: 0 0 .5em rgba(93,162,248,0.5); border-color: #5da2f8; }
2.1.7 留言区
很多浏览器支持让用户缩放文本区。有些浏览器允许横向和纵向缩放文本区,而有些则只允许纵向缩放。
textarea { height: 10em; resize: vertical; /* 指定缩放的轴向 */ }
2.1.8 单选按钮
<div class="fieldset-wrapper"> <fieldset> <legend>Remember Me</legend> <p class="field"> <label><input name="remember" type="radio" value="yes" />Yes</label> </p> <p class="field"> <label><input name="remember" type="radio" value="no" checked="checked" />No</label> </p> </fieldset> </div>
input[type="radio"] { margin-right: .75em; }
单选按钮的input
类型是radio
,为了让用户从两个选项中选择一个,必须让两个input
元素的name
属性相同。
2.1.9 按钮
HTML支持两种创建按钮的方式:
1、将input
的type属性设置为button、reset或submit:
<input type="submit" value="Post comment" />
2、使用button
元素,可以指定相同的type属性值:
<button type="submit">Post comment</button>
button
控件如果用在表单外部,显然不能提交提交,但可以响应JavaScript的调用。reset
类型的控件(如今用得已经不多了)用于将表单重置回其初始值。
submit类型的控件用于将表单数据发送到表单的action属性指定的URL,当然前提是这个控件必须在表单内部。对于button元素而言,其type属性的默认值是submit。
我们建议使用button
来创建按钮,因为这样就可以在button
里嵌入其他元素(如span
或图片),便于应用样式。
表单控件在不同浏览器中的默认样式不相同。
2.2 表单反馈与帮助
<input name="comment-url" id="comment-url" type="url" placeholder="http://example.com" />
占位符(placeholder)文本可以修改的样式有限,各种浏览器都为它提供了不同的伪元素。
::-webkit-input-placeholder { font-style: italic; } :-ms-input-placeholder { font-style: italic; } ::-moz-placeholder { font-style: italic; }
占位符文本是为了提供输入示例,因此绝对不能把它们当成字段名来使用。
占位符会在用户输入时消失,而用户需要在任何情况下都能看到字段名。
支持HTML5的浏览器自带表单验证功能,相应地也有一批CSS伪类可用于辅助客户端验证。
只要使用较新的HTML5表单属性,浏览器就会帮你验证表单字段的值。比如,把input
的type属性设置为email后,如果输入了无效的电子邮件地址并提交表单,浏览器就会给你显示一条错误消息。
输入文本无效时的样式:
.field-text :invalid { border-color: #e72633; Box-shadow: 0 0 .5em rgba(229,43,37,0.5); }
2.3 高级表单样式
<form id="comments_form" action="/comments/" method="post"> <div class="fieldset-wrapper"> <fieldset> <legend>Your contact details</legend> <p class="field field-text"> <label for="applicant-name">Name:</label> <input name="applicant-name" id="applicant-name" type="text" /> </p> <p class="field field-text"> <label for="applicant-email">Email Address:</label> <input name="applicant-email" id="applicant-email" type="email" /> </p> <p class="field field-text"> <label for="applicant-twitter">Twitter handle:</label> <span class="field-prefixed"> <span class="field-prefix" id="applicant-twitter-prefix" aria-label="You can omit the @">@</span> <input aria-describedby="applicant-twitter-prefix" name="applicant-twitter" id="applicant-twitter" type="text" /> </span> </p> </fieldset> </div> <div class="fieldset-wrapper"> <fieldset> <legend>Which languages have you mastered?</legend> <ul class="checkBoxes"> <li> <input type="checkBox" name="lang-as" id="lang-as" /> <label for="lang-as">ActionScript</label> </li> <!-- 省略 --> </ul> </fieldset> </div> <p class="field-submit"> <button id="submit" class="submit" name="submit" type="submit">Send application</button> </p> </form>
/* 省略 */ label { cursor: pointer; display: block; } .field { max-width: 20em; } .field-text label,.field-text input,.field-prefixed,.field-text textarea { width: 100%; max-width: 100%; -webkit-appearance: none; Box-sizing: border-Box; } .field-text input,.field-text textarea { padding: .375em .3125em .3125em; border: 1px solid #ccc; border-radius: .25em; } .checkBoxes { list-style: none; padding: 0; column-width: 10em; /* 让复选框组织成列。 */ } /* 省略 */
在视口足够大的时候显示行内布局。
@media only screen and (min-width: 35em) { .flexBox .field-text { display: flex; max-width: 28em; } .flexBox .field-text label { /* 所有字段名的宽度都为8em,既不扩展也不收缩。 */ flex: 0 0 8em; /* flex: flex-grow flex-shrink flex-basis */ display: flex; align-items: center; } }
这里input
元素的宽度设置成了width: 100%
,但flex
属性的默认值是0 1 auto
,因此它会收缩,给固定宽度的字段名腾出地方。
使用Flex实现带前缀的输入字段:
<p class="field field-text"> <label for="applicant-twitter">Twitter handle:</label> <span class="field-prefixed"> <span class="field-prefix" id="applicant-twitter-prefix" aria-label="You can omit the @">@</span> <input aria-describedby="applicant-twitter-prefix" name="applicant-twitter" id="applicant-twitter" type="text" /> </span> </p>
/* 把前置文本放在一个行内块中。 */ .field-prefix { display: inline-block; /* 省略 */ border-radius: .25em; } .field-prefixed input { max-width: 12em; } /* 把.field-prefix转换成一个FlexBox容器。 */ .flexBox .field-prefixed { display: flex; } .flexBox .field-prefix { display: flex; border-right: 0; border-radius: .25em 0 0 .25em; align-items: center; } /* 给input元素重新应用max-width,让它自动填满所有剩余空间。*/ .flexBox .field-prefixed input { max-width: 100%; border-radius: 0 .25em .25em 0; }
人造复选框:
:root input[type="checkBox"] + label { /* 未选中的复选框字段名 */ background-image: url(images/checkBox-unchecked.png); } :root input[type="checkBox"]:checked + label { /* 选中的复选框字段名 */ background-image: url(images/checkBox-checked.png); } /* 让复选框本身不可见,但仍然可以被访问和聚焦。这里我们使用一个复选框图片,作为label元素的背景。 */ :root input[type="checkBox"] { position: absolute; overflow: hidden; width: 1px; height: 1px; clip: rect(0 0 0 0); }
参考资料: