aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/learn/forms/styling_web_forms/index.html
blob: 6127db29457cb2fe3334d8525c09cd1977301d7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
---
title: 样式化 HTML 表单
slug: Learn/Forms/Styling_web_forms
tags:
  - CSS
  - Web
  - 例子
  - 指导
  - 样式
  - 表单
translation_of: Learn/Forms/Styling_web_forms
original_slug: Learn/HTML/Forms/Styling_HTML_forms
---
<p>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/HTML_forms_in_legacy_browsers", "Learn/HTML/Forms/Advanced_styling_for_HTML_forms", "Learn/HTML/Forms")}}</p>

<p class="summary">在这篇文章中,用户将学习如何使用HTML表单和CSS以使页面更加美观。令人惊讶的是,这可能有点棘手。由于历史和技术的原因,表单部件不能很好地与CSS配合工作。 由于这些困难,许多开发人员选择<a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets">构建自己的HTML小部件</a>以获得更好的控制和视觉观感。 然而,在现代浏览器中,web设计者越来越多地控制表单元素的设计。让我们深入研究。</p>

<h2 id="为什么使用CSS美化表单组件这么困难?">为什么使用CSS美化表单组件这么困难?</h2>

<p>在1995年左右的Web早期,表单组件(或控件)在 <a href="http://www.ietf.org/rfc/rfc1866.txt">HTML 2规范</a>中被添加到HTML。由于表单组件的复杂性,实现者选择依靠底层操作系统来管理和渲染它们。</p>

<p>若干年后,CSS被创建出来了,那么技术上的必要性,就是使用原生组件来实现表单控制,这是因为风格的要求。在CSS的早期,表单样式控制不是优先事项。</p>

<p>由于用户习惯于各自平台的视觉外观,浏览器厂商不愿意对表单控件样式进行调整;到目前为止,要重建所有控件以使它们可美化仍然是非常困难的。</p>

<p>即使在今天,仍然没有一个浏览器完全实现了CSS 2.1。然而,随着时间的推移,浏览器厂商已经改进了对表单元素的CSS支持,尽管可用性的声誉不好,但现在已经可以使用CSS来设计<a href="/en-US/docs/HTML/Forms">HTML表单</a></p>

<h3 id="涉及到CSS,并非所有组件都是平等的">涉及到CSS,并非所有组件都是平等的</h3>

<p>目前,在使用表单时使用CSS仍然有一些困难。这些问题可以分为三类: </p>

<h4 id="好的">好的</h4>

<p>有些元素在跨平台上时很少出现问题。包括以下结构元素:</p>

<ol>
 <li>{{HTMLElement("form")}}</li>
 <li>{{HTMLElement("fieldset")}}</li>
 <li>{{HTMLElement("label")}}</li>
 <li>{{HTMLElement("output")}}</li>
</ol>

<p>这还包括所有文本字段小部件(单行和多行)和按钮。</p>

<h4 id="不好的">不好的</h4>

<p>一些元素难以被美化,并且可能需要一些复杂的技巧,偶尔需要高级的CSS3知识。</p>

<p>这些包括{{HTMLElement("legend")}}元素,但不能在所有平台上正确定位。 Checkbox和radio按钮也不能直接应用样式,但是,感谢CSS3,你可以解决这个问题。{{htmlattrxref("placeholder", "input")}} 的内容不能以任何标准方式应用样式,但是实现它的所有浏览器也都实现了私有的CSS伪元素或伪类,让你可以对其定义样式。</p>

<p>我们会在<a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">如何构建自定义表单挂件</a>一文中讲述如何处理更多特定的问题。</p>

<h4 id="丑陋的">丑陋的</h4>

<p>有些元素根本不能用应用CSS样式。 这些包括:所有高级用户界面小部件,如范围,颜色或日期控件; 和所有下拉小部件,包括{{HTMLElement("select")}}, {{HTMLElement("option")}}, {{HTMLElement("optgroup")}}{{HTMLElement("datalist")}} 元素。 文件选择器小部件也被称为不可样式化。 新的{{HTMLElement("progress")}}{{HTMLElement("meter")}} 元素也属于这个类别。</p>

<p>所有这些小部件的主要问题来自于它们具有非常复杂的结构,而CSS目前还不足以表达这些小部件的所有细微部分。 如果你想定制这些小部件,你必须依靠JavaScript来构建一个你能够应用样式的DOM树。我们会在 <a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a>一文中探索如何实现这一点。</p>

<h2 id="基本样式美化">基本样式美化</h2>

<p>为了使用CSS美化容易被美化的元素,你并不会碰到任何困难,因为它们的大部分行为同其他HTML元素差不多。但是,每个浏览器的用户代理样式表可能会有点不一致,所以有一些技巧可以帮助您更轻松地设计它们。</p>

<h3 id="Search字段">Search字段</h3>

<p>搜索框是唯一一种应用CSS样式有点棘手的文本字段。 在基于WebKit的浏览器(Chrome,Safari等)上,您必须使用<code>-webkit-appearance</code>专有属性来调整它。 我们在文章中进一步讨论这个属性:<a href="/en-US/docs/Advanced_styling_for_HTML_forms">HTML表单的高级样式</a></p>

<h4 id="Example">Example</h4>

<pre class="brush: html">&lt;form&gt;
  &lt;input type="search"&gt;
&lt;/form&gt;
</pre>

<pre class="brush: css">input[type=search] {
  border: 1px dotted #999;
  border-radius: 0;

  -webkit-appearance: none;
}</pre>

<p><img alt="This is a screenshot of a search filed on Chrome, with and without the use of -webkit-appearance" src="/files/4153/search-chrome-macos.png" style="border-style: solid; border-width: 1px; height: 107px; width: 179px;"></p>

<p>截图中是 Chrome 浏览器中的两个搜索框,在我们的例子中,两个搜索框均被设置为有边框。第一个没有使用<code>-webkit-appearance</code>渲染,而第二个使用了 <code>-webkit-appearance:none</code>. 两者的不同显而易见。</p>

<h3 id="字体和文本">字体和文本</h3>

<p>CSS font和text功能能被很容易的应用到任何组件上(当然你可以在form组件上使用{{cssxref("@font-face")}} )。然而,浏览器的行为经常不一致。默认情况下,一些组件不会从它们的父元素继承 {{cssxref("font-family")}}{{cssxref("font-size")}} 。相反,许多浏览器使用系统默认的字体和文本。为了让form表单的外观和其他内容保持一致,你可以在你的样式表中增加以下内容:</p>

<pre class="brush: css">button, input, select, textarea {
  font-family : inherit;
  font-size   : 100%;
}</pre>

<p>下面的截图显示了不同之处; 左边是Mac OS X上Firefox中元素的默认渲染,其中使用了平台的默认字体样式。 在右边是相同的元素,应用了我们的字体统一样式规则。</p>

<p><img alt="This is a screenshot of the main form widgets on Firefox on Mac OSX, with and without font harmonization" src="/files/4157/font-firefox-macos.png" style="border-style: solid; border-width: 1px; height: 234px; width: 420px;"></p>

<p>关于使用系统默认样式的表单还是使用设计用于匹配内容的自定义样式表单,有很多争议。 作为网站或Web应用程序的设计者,您可以自己做出决定。</p>

<h3 id="盒子模型">盒子模型</h3>

<p>所有文本字段都完全支持与CSS盒模型相关的每个属性({{cssxref("width")}}, {{cssxref("height")}}, {{cssxref("padding")}}, {{cssxref("margin")}}, 和 {{cssxref("border")}})。 但是,像以前一样,浏览器在显示这些小部件时依赖于系统默认的样式。 您需要定义如何将其融入到您的内容中。 如果你既想保持小部件的原生外观和感觉,又想给他们一个一致的尺寸,那么你会遇到一些困难(如果你想保持组件的原生观感,又想给它们一致的大小,你会面临一些困难)。</p>

<p><strong>这是因为每个小部件都有自己的边框,填充和边距的规则。</strong> 所以如果你想给几个不同的小部件相同的大小,你必须使用{{cssxref("box-sizing")}} 属性:</p>

<pre class="brush: css">input, textarea, select, button {
  width : 150px;
  margin: 0;

  -webkit-box-sizing: border-box; /* For legacy WebKit based browsers */
     -moz-box-sizing: border-box; /* For legacy (Firefox &lt;29) Gecko based browsers */
          box-sizing: border-box;
}</pre>

<p><img alt="This is a screenshot of the main form widgets on Chrome on Windows 7, with and without the use of box-sizing." src="/files/4161/size-chrome-win7.png" style="border-style: solid; border-width: 1px; height: 213px; width: 358px;"></p>

<p>在上面的屏幕截图中,左侧的列没有{{cssxref("box-sizing")}},而右侧的列使用了这个属性和<code>border-box</code>。 请注意我们是怎样确保所有元素都占用相同的空间量,尽管平台对每种窗口小部件都有默认规则。</p>

<h3 id="定位(Positioning)">定位(Positioning)</h3>

<p>HTML表单部件的定位通常不是问题; 但是,您应该特别注意两点:</p>

<h4 id="legend">legend</h4>

<p>{{HTMLElement("legend")}}元素易于应用CSS,除了定位。在所有浏览器中, {{HTMLElement("legend")}} 元素定位是其 {{HTMLElement("fieldset")}} 父元素的上边框的最顶端。在HTML流中无法改变它的绝对位置,无法让其远离顶部边框。然而,你可以使用 {{cssxref("position")}} 属性将其位置设置为绝对或相对。除此之外,它近几年是fieldset边框的一部分。</p>

<p>由于{{HTMLElement("legend")}}元素对可访问性非常重要,因为它能被无障碍技术作为每个fieldset中的表单元素的标签读出来,它通常与标题配对,并且在无障碍中被隐藏 。例如:</p>

<h5 id="HTML">HTML</h5>

<pre class="brush: html">&lt;fieldset&gt;
  &lt;legend&gt;Hi!&lt;/legend&gt;
  &lt;h1&gt;Hello&lt;/h1&gt;
&lt;/fieldset&gt;</pre>

<h5 id="CSS">CSS</h5>

<pre class="brush: css">legend {
  width: 1px;
  height: 1px;
  overflow: hidden;
}</pre>

<h4 id="textarea">textarea</h4>

<p>默认情况下,所有浏览器都认为{{HTMLElement("textarea")}} 元素是inline block,与文本底线对齐。 这很少是我们真正想看到的。 要将内联(<code>inline-block</code>)块更改为块(<code>block</code>),使用{{cssxref("display")}}属性非常简单。 但是如果你想以inline方式使用它,通常改变垂直对齐方式:</p>

<pre class="brush: css">textarea {
  vertical-align: top;
}</pre>

<h2 id="示例">示例</h2>

<p>让我们来看一个样式化 HTML 表单的实际的案例。这有助于理清这里面的许多概念。我们将构建下面的"明信片" 联系人表单:</p>

<p><img alt="This is what we want to achieve with HTML and CSS" src="/files/4149/screenshot.png" style="border-style: solid; border-width: 1px; height: 249px; width: 370px;"></p>

<p>如果你想继续关注这个例子,复制我们的 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/postcard-example/postcard-start.html">postcard-start.html</a> 文件,并遵循接下来的指导操作。</p>

<h3 id="The_HTML">The HTML</h3>

<p>HTML 只比我们在 <a href="/en-US/docs/HTML/Forms/My_first_HTML_form" title="/en-US/docs/HTML/Forms/My_first_HTML_form">the first article of this guide</a> 中涉及到的多一些;它只有一些额外的 id 和 title。</p>

<pre class="brush: html">&lt;form&gt;
  &lt;h1&gt;to: Mozilla&lt;/h1&gt;

  &lt;div id="from"&gt;
    &lt;label for="name"&gt;from:&lt;/label&gt;
    &lt;input type="text" id="name" name="user_name"&gt;
  &lt;/div&gt;

  &lt;div id="reply"&gt;
    &lt;label for="mail"&gt;reply:&lt;/label&gt;
    &lt;input type="email" id="mail" name="user_email"&gt;
  &lt;/div&gt;

  &lt;div id="message"&gt;
    &lt;label for="msg"&gt;Your message:&lt;/label&gt;
    &lt;textarea id="msg" name="user_message"&gt;&lt;/textarea&gt;
  &lt;/div&gt;

  &lt;div class="button"&gt;
    &lt;button type="submit"&gt;Send your message&lt;/button&gt;
  &lt;/div&gt;
&lt;/form&gt;</pre>

<p>将上面的代码添加到你 HTML 的 body 中。</p>

<h3 id="组织你的静态文件">组织你的静态文件</h3>

<p>好戏要开始了! 在开始写代码之前,我们需要三个额外的静态文件:</p>

<ol>
 <li>明信片的<a href="/files/4151/background.jpg" title="The postcard background">背景</a>——下载这幅图片,把它和你的 HTML 文件保存在相同目录下。</li>
 <li>打字机字体:<a href="http://www.fontsquirrel.com/fonts/Secret-Typewriter" rel="external" title="http://www.fontsquirrel.com/fonts/Secret-Typewriter">源自 fontsquirrel.com 的 "Secret Typewriter“ 字体</a>——将TTF文件下载到和上面相同的文件夹里。</li>
 <li>手绘字体:<a href="http://www.fontsquirrel.com/fonts/Journal" rel="external" title="http://www.fontsquirrel.com/fonts/Journal">源自 fontsquirrel.com 的 The "Journal" 字体 </a> —— 将TTF文件下载到和上面相同的文件夹里。</li>
</ol>

<p>在你开始之前需要对字体做一些处理:</p>

<ol>
 <li>打开 fontsquirrel <a href="https://www.fontsquirrel.com/tools/webfont-generator">网络字体生成器</a>.</li>
 <li>使用表单,上传你的字体文件并生成一个网络字体包,将这个包下载到你的电脑上。</li>
 <li>解压提供的 zip 文件。</li>
 <li>再解压后的文件内容里你会找到两个  <code>.woff</code> 文件和两个<code>.woff2</code> 文件。将这四个文件拷贝到一个叫 fonts 的文件夹里,而fonts 文件夹位于和上面相同的文件夹里。我们为每种字体使用两个不同的文件以最大限度地保证浏览器兼容性。查看我们的 <a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">Web 字体</a> 一文获取更多信息。</li>
</ol>

<h3 id="CSS_2">CSS</h3>

<p>现在我们可以深入探究本例的 CSS 了。将下面所有的代码块一个接一个地加到{{htmlelement("style")}} 元素里。</p>

<p>首先,我们要准备一些基础。这需要定义 {{cssxref("@font-face")}} 规则,以及所有的 {{HTMLElement("body")}} 元素和 {{HTMLElement("form")}} 元素基本规则:</p>

<pre class="brush: 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/veteran_typewriter-webfont.woff2') format('woff2'),
         url('fonts/veteran_typewriter-webfont.woff') format('woff');
    font-weight: normal;
    font-style: normal;
}

body {
  font  : 21px sans-serif;

  padding : 2em;
  margin  : 0;

  background : #222;
}

form {
  position: relative;

  width  : 740px;
  height : 498px;
  margin : 0 auto;

  background: #FFF url(background.jpg);
}</pre>

<p>现在我们可以定位我们的元素,包括标题和其他表单元素:</p>

<pre class="brush: css">h1 {
  position : absolute;
  left : 415px;
  top  : 185px;

  font : 1em "typewriter", sans-serif;
}

#from {
  position: absolute;
  left : 398px;
  top  : 235px;
}

#reply {
  position: absolute;
  left : 390px;
  top  : 285px;
}

#message {
  position: absolute;
  left : 20px;
  top  : 70px;
}</pre>

<p>现在我们开始处理表单元素本身。首先,让我们确保 {{HTMLElement("label")}} 被赋予了正确的字体:</p>

<pre class="brush: css">label {
  font : .8em "typewriter", sans-serif;
}</pre>

<p>文本域需要一些通用的规则,我们只需简单的移除 {{cssxref("border","borders")}}{{cssxref("background","backgrounds")}}, 并重新定义其{{cssxref("padding")}}{{cssxref("margin")}}</p>

<pre class="brush: css">input, textarea {
  font    : .9em/1.5em "handwriting", sans-serif;

  border  : none;
  padding : 0 10px;
  margin  : 0;
  width   : 240px;

  background: none;
}</pre>

<p>当其中的一个域获得焦点后,我们用浅灰色、半透明的背景高亮它们,注意添加{{cssxref("outline")}} 属性非常重要,这样可以移除由某些浏览器添加的默认高亮效果:</p>

<pre class="brush: css">input:focus, textarea:focus {
  background   : rgba(0,0,0,.1);
  border-radius: 5px;
  outline      : none;
}</pre>

<p>现在我们的文本域已经完成了,我们需要调整单行和多行文本域的显示,使其能够匹配,因为通常情况下它们不会以默认的设置而具有一样的外观。</p>

<p>单行文本需要一些调整才能在 Internet Explorer 中渲染良好。Internet Explorer 没有基于字体的自然高度来定义文本域的高度(而这是所有其他浏览器都有的行为)。为了修正这个问题,我们需要给域添加一个确定的高度,像下面这样:</p>

<pre class="brush: css">input {
    height: 2.5em; /* for IE */
    vertical-align: middle; /* This is optional but it makes legacy IEs look better */
}</pre>

<p>{{HTMLElement("textarea")}} 元素默认地被渲染成一个块级元素。这里有重要地两点是 {{cssxref("resize")}}{{cssxref("overflow")}} 属性。因为我们的设计是一个固定大小的设计,所以我们会使用 <code>resize</code> 属性来防止用户调整我们的多行文本域的大小。{{cssxref("overflow")}} 属性是用来让域在不同的浏览器上渲染得更一致。一些浏览器默认值为 <code>auto</code>,而一些将默认值设为 <code>scroll</code>。在我们得例子中,最好确定每个浏览器都使用 <code>auto</code></p>

<pre class="brush: css">textarea {
  display : block;

  padding : 10px;
  margin  : 10px 0 0 -10px;
  width   : 340px;
  height  : 360px;

  resize  : none;
  overflow: auto;
}</pre>

<p>{{HTMLElement("button")}} 元素上使用 CSS 非常方便;你可以做你任何想做得事情,甚至包括使用 <a href="/en-US/docs/CSS/Pseudo-elements" title="/en-US/docs/CSS/Pseudo-elements">伪元素</a></p>

<pre class="brush: css">button {
  position     : absolute;
  left         : 440px;
  top          : 360px;

  padding      : 5px;

  font         : bold .6em sans-serif;
  border       : 2px solid #333;
  border-radius: 5px;
  background   : none;

  cursor       : pointer;

-webkit-transform: rotate(-1.5deg);
   -moz-transform: rotate(-1.5deg);
    -ms-transform: rotate(-1.5deg);
     -o-transform: rotate(-1.5deg);
        transform: rotate(-1.5deg);
}

button:after {
  content: " &gt;&gt;&gt;";
}

button:hover,
button:focus {
  outline   : none;
  background: #000;
  color   : #FFF;
}</pre>

<p>瞧!</p>

<div class="note">
<p><strong>注意:如果你的例子没有像你预期的那样工作,你想将它同我们的版本检查对比,</strong>你可以在Github 上找到它 —— 查看 <a href="https://mdn.github.io/learning-area/html/forms/postcard-example/">在线演示</a> (也可以查看<a href="https://github.com/mdn/learning-area/tree/master/html/forms/postcard-example">源代码</a>)。</p>
</div>

<h2 id="总结">总结</h2>

<p>如你所见,若我们想构建只包含文本域和按钮的表单,用 CSS 美化它们非常容易。如果你想要知道更多能够让你的处理表单组件时更轻松的 CSS 小技巧,看一看 <a href="http://necolas.github.com/normalize.css" rel="external">normalize.css </a>项目的表单部分。</p>

<p><a href="/en-US/docs/Web/Guide/HTML/Forms/Advanced_styling_for_HTML_forms" title="/en-US/docs/Advanced_styling_for_HTML_forms">下一篇文章中</a>,我们将会看到如何处理落入"不好的" 和"丑陋的" 分类的表单组件。</p>

<p>{{PreviousMenuNext("Learn/HTML/Forms/HTML_forms_in_legacy_browsers", "Learn/HTML/Forms/Advanced_styling_for_HTML_forms", "Learn/HTML/Forms")}}</p>

<h2 id="在本单元中">在本单元中</h2>

<ul>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Your_first_HTML_form">Your first HTML form</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">How to structure an HTML form</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">The native form widgets</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">Sending form data</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Form_validation">Form data validation</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML forms in legacy browsers</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Styling HTML forms</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Advanced styling for HTML forms</a></li>
 <li><a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li>
</ul>