diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/learn/html/forms | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/zh-cn/learn/html/forms')
16 files changed, 8002 insertions, 0 deletions
diff --git a/files/zh-cn/learn/html/forms/advanced_styling_for_html_forms/index.html b/files/zh-cn/learn/html/forms/advanced_styling_for_html_forms/index.html new file mode 100644 index 0000000000..94128b7229 --- /dev/null +++ b/files/zh-cn/learn/html/forms/advanced_styling_for_html_forms/index.html @@ -0,0 +1,467 @@ +--- +title: 高级设计 HTML 表单 +slug: Learn/HTML/Forms/Advanced_styling_for_HTML_forms +translation_of: Learn/Forms/Advanced_form_styling +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/Styling_HTML_forms", "Learn/HTML/Forms/Property_compatibility_table_for_form_widgets", "Learn/HTML/Forms")}}</div> + +<p class="summary">在本文中,我们将看到<a href="https://developer.mozilla.org/en-US/docs/HTML">HTML</a>表单怎样使用<a href="https://developer.mozilla.org/en-US/docs/CSS">CSS</a>装饰难以定制的表单小部件。如<a href="/en-US/docs/HTML/Forms/Styling_HTML_forms">前面章节</a>所示,文本域和按钮完全可以使用CSS,现在我们将深入探索HTML表单样式。</p> + +<p>在继续之前,让我们回忆一下两种表单小部件:</p> + +<dl> + <dt>bad</dt> + <dd>这个元素很难设计,需要一些复杂的技巧,有时还涉及到高级的CSS3的知识。</dd> + <dt>ugly</dt> + <dd>忘记使用CSS来设计这些元素吧。你最多能做一点点事情,还不能保证可以跨浏览器,而且在它们出现时永远不能做到完全的受控。</dd> +</dl> + +<h2 id="CSS表现力">CSS表现力</h2> + +<p>除了文本框和按钮之外,使用其他表单小部件的主要问题是在许多情况下,CSS的表现不能满足设计复杂的小部件的要求。</p> + +<p>HTML和CSS最新的发展扩展了CSS的表现力:</p> + +<ul> + <li><a href="http://www.w3.org/TR/CSS21/selector.html#dynamic-pseudo-classes" rel="external" title="http://www.w3.org/TR/CSS21/selector.html#dynamic-pseudo-classes">CSS 2.1</a> 非常受限,只给出三个伪类: + + <ul> + <li>{{cssxref(":active")}}</li> + <li>{{cssxref(":focus")}}</li> + <li>{{cssxref(":hover")}}</li> + </ul> + </li> + <li><a href="http://www.w3.org/TR/css3-selectors/" rel="external" title="http://www.w3.org/TR/css3-selectors/">CSS Selector Level 3</a> 增加了三个与HTML表单相关的伪类: + <ul> + <li>{{cssxref(":enabled")}}</li> + <li>{{cssxref(":disabled")}}</li> + <li>{{cssxref(":checked")}}</li> + <li>{{cssxref(":indeterminate")}}</li> + </ul> + </li> + <li><a href="http://dev.w3.org/csswg/css3-ui/#pseudo-classes" rel="external" title="http://dev.w3.org/csswg/css3-ui/#pseudo-classes">CSS Basic UI Level 3</a> 也增加了几个伪类用于描述小部件的状态: + <ul> + <li>{{cssxref(":default")}}</li> + <li>{{cssxref(":valid")}}</li> + <li>{{cssxref(":invalid")}}</li> + <li>{{cssxref(":in-range")}}</li> + <li>{{cssxref(":out-of-range")}}</li> + <li>{{cssxref(":required")}}</li> + <li>{{cssxref(":optional")}}</li> + <li>{{cssxref(":read-only")}}</li> + <li>{{cssxref(":read-write")}}</li> + </ul> + </li> + <li><a href="http://dev.w3.org/csswg/selectors4/" rel="external" title="http://dev.w3.org/csswg/selectors4/">CSS Selector Level 4</a> 目前处于积极应用和重点讨论的状态,但并不打算为表单做更多的改善: + <ul> + <li>{{cssxref(":user-error")}} 只是改进了伪类{{cssxref(":invalid")}}。</li> + </ul> + </li> +</ul> + +<p>所有这一切是一个好的开端,但是有两个问题。首先,一些浏览器不需要实现CSS 2.1之上的特性。其次在设计像日期选择器这样的复杂的小部件时,这些实在不够好。</p> + +<p>浏览器厂家在CSS表现力在表单方面的扩展做了一些尝试,在某些情况下,知道什么可用也挺不错的。</p> + +<div class="warning"> +<p><strong>警告:</strong> 尽管 这些尝试很有趣,但<strong>它们是非标准的,也就是不可靠的。</strong>. 如果你使用它们(也许你并不常用),你要自己承担风险,使用非标准的属性<a href="http://www.alistapart.com/articles/every-time-you-call-a-proprietary-feature-css3-a-kitten-dies/" title="http://www.alistapart.com/articles/every-time-you-call-a-proprietary-feature-css3-a-kitten-dies/">对于Web并不是好事</a> 。</p> +</div> + +<ul> + <li><a href="/en-US/docs/CSS/CSS_Reference/Mozilla_Extensions" title="/en-US/docs/CSS/CSS_Reference/Mozilla_Extensions">Mozilla CSS 扩展</a> + + <ul> + <li>{{cssxref(":-moz-placeholder")}}</li> + <li>{{cssxref(":-moz-submit-invalid")}}</li> + <li>{{cssxref(":-moz-ui-invalid")}}</li> + <li>{{cssxref(":-moz-ui-valid")}}</li> + </ul> + </li> + <li><a href="/en-US/docs/CSS/CSS_Reference/Webkit_Extensions" title="/en-US/docs/CSS/CSS_Reference/Webkit_Extensions">WebKit CSS 扩展</a> + <ul> + <li>{{cssxref("::-webkit-input-placeholder")}}</li> + <li><a href="http://trac.webkit.org/wiki/Styling%20Form%20Controls" rel="external" title="http://trac.webkit.org/wiki/Styling Form Controls">其他</a></li> + </ul> + </li> + <li><a href="http://msdn.microsoft.com/en-us/library/ie/hh869403%28v=vs.85%29.aspx" rel="external" title="http://msdn.microsoft.com/en-us/library/ie/hh869403%28v=vs.85%29.aspx">Microsoft CSS 扩展</a> + <ul> + <li><code><a href="http://msdn.microsoft.com/en-us/library/ie/hh772745%28v=vs.85%29.aspx" rel="external" title="http://msdn.microsoft.com/en-us/library/ie/hh772745%28v=vs.85%29.aspx">:-ms-input-placeholder</a></code></li> + </ul> + </li> +</ul> + +<h3 id="控制表单元素的外观">控制表单元素的外观</h3> + +<p>基于WebKit(Chrome, Safari)和 Gecko(Firefox)的浏览器提供更高级的HTML部件定制。它们也实现了跨平台,因此需要一种方式把原生小部件转换为用户可设置样式的小部件。</p> + +<p>为此,它们使用了专有属性:{{cssxref("-webkit-appearance")}}或{{cssxref("-moz-appearance")}}。这<strong>些属性是非标准的,不应该使用。</strong>事实上,它们在WebKit 和Gecko中的表现也是不相同的。然而,有一个值很好用:<code>none</code>,用这个值,你(几乎完全)能控制一个已知小部件的样式。</p> + +<p>因此,如果你在应用一个元素的样式时遇到麻烦,可以尝试使用那些专有属性。我们下面有一些例子,这个属性最成功的例子是WebKit浏览器中的搜索域的样式:</p> + +<pre class="brush: html"><form> + <input type="search"> +</form></pre> + +<pre class="brush: css"><style> +input[type=search] { + border: 1px dotted #999; + border-radius: 0; + + -webkit-appearance: none; +} +</style></pre> + +<p>{{EmbedLiveSample("Controlling_the_appearance_of_form_elements", 250, 40)}}</p> + +<div class="note"> +<p><strong>注意:</strong>当我们谈及Web技术的时总是很难预测未来。扩展CSS表现力是很困难的,其他规范也做了一些探索性的工作,如<a href="http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html" rel="external" title="http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html">Shadow DOM</a>提供了一些观点。可完全设置样式的表单的问题还远未结束。</p> +</div> + +<h2 id="举例">举例</h2> + +<h3 id="复选框和单选按钮">复选框和单选按钮</h3> + +<p>独自设计复选框或单选按钮的样式是让人抓狂的。例如由于浏览器反应各不相同,在修改复选框和单选按钮的大小时,并不保证确实能改变它们。</p> + +<h4 id="一个简单的测试用例">一个简单的测试用例</h4> + +<p>让我们研究一下下面的测试用例:</p> + +<pre class="brush: html"><span><input type="checkbox"></span></pre> + +<pre class="brush: css">span { + display: inline-block; + background: red; +} + +input[type=checkbox] { + width : 100px; + height: 100px; +}</pre> + +<p>这里是不同的浏览器的处理方式:</p> + +<table> + <thead> + <tr> + <th scope="col">浏览器</th> + <th scope="col">视图</th> + </tr> + </thead> + <tbody> + <tr> + <td>Firefox 57 (Mac OSX)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15671/firefox-mac-checkbox.png"></td> + </tr> + <tr> + <td>Firefox 57 (Windows 10)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15691/firefox-windows-checkbox.png"></td> + </tr> + <tr> + <td>Chrome 63 (Mac OSX)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15676/chrome-mac-checkbox.png"></td> + </tr> + <tr> + <td>Chrome 63 (Windows 10)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15681/chrome-windows-checkbox.png"></td> + </tr> + <tr> + <td>Opera 49 (Mac OSX)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15701/opera-mac-checkbox.png"></td> + </tr> + <tr> + <td>Internet Explorer 11 (Windows 10)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15696/ie11-checkbox.png"></td> + </tr> + <tr> + <td>Edge 16 (Windows 10)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15686/edge-checkbox.png"></td> + </tr> + </tbody> +</table> + +<h4 id="更复杂的例子">更复杂的例子</h4> + +<p>由于Opera和Internet Explorer没有像{{cssxref("-webkit-appearance")}}或{{cssxref("-moz-appearance")}}这样的特性,使用它们是不合适的。幸运的是,CSS有足够多的表现方式可以找到解决方法。让我们做一个很普通的例子:</p> + +<pre class="brush: html"><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></pre> + +<p>带有一些基本的样式:</p> + +<pre class="brush: css">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; +}</pre> + +<div class="note"> +<p><strong>注:下面的内容(仅限样式化 checkbox 部分)与英文版出入极大,猜测已经是过时内容</strong></p> +</div> + +<p>现在,让我们设计一个定制复选框的样式</p> + +<p>计划用自己的图像替换原生的复选框,首先需要准备复选框在所有状态下的图像,那些状态是:未选、已选、禁用不选、禁用已选。该图像将用作CSS精灵:</p> + +<p><img alt="Check box CSS Sprite" src="/files/4173/checkbox-sprite.png" style="height: 64px; width: 16px;"></p> + +<p>一开始要隐藏初始复选框。可以简单的把它们从页面视图中拿开。这里要考虑两个重要的事情:</p> + +<ul> + <li>不能用<code>display:none</code>来隐藏复选框,因为后面我们需要把复选框对用户可见。而使用<code>display:none</code>,用户不能再访问这个复选框,这就表示复选框不能选择或不选择。</li> + <li>我们将使用CSS3选择器来实现定制的样式,为了支持旧版浏览器,可以在所有选择器前设置{{cssxref(":root")}}伪类。目前所有我们需要支持的浏览器都支持{{cssxref(":root")}}伪类,但是其他的并不能保证。这是一个过滤旧的Internet Explorer的便利方式的例子。那些旧版浏览器将看到传统的复选框,而新式的浏览器可以看到定制的复选框。</li> +</ul> + +<pre class="brush: css">:root input[type=checkbox] { + /* original check box are push outside the viexport */ + position: absolute; + left: -1000em; +}</pre> + +<p>现在加上自己的图像就可以摆脱原来的复选框了,为此,要在初始的复选框后面加上{{HTMLElement("label")}}元素,并使用它的{{cssxref(":before")}}伪元素。因此在下面章节中,要使用<a href="/en-US/docs/CSS/Attribute_selectors" title="/en-US/docs/CSS/Attribute_selectors">selector属性</a>来选择复选框,然后使用<a href="/en-US/docs/CSS/Adjacent_sibling_selectors" title="/en-US/docs/CSS/Adjacent_sibling_selectors">adjacent sibling selector</a>来选择原有复选框后面的<code>label</code>。最后,访问{{cssxref(":before")}}伪元素来设计复选框显示定制样式。</p> + +<pre class="brush: css">: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; + +/* The following is used to adjust the position of + the check boxes on the text baseline */ + + vertical-align: bottom; + position: relative; + bottom: 2px; +}</pre> + +<p>在初始复选框上使用{{cssxref(":checked")}}和{{cssxref(":disabled")}}伪类来改变定制复选框的状态。因为使用了CSS精灵,我们需要做的只是修改背景的位置。</p> + +<pre class="brush: 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; +}</pre> + +<p>最后一件(但是很重要的)事情:当用户使用键盘从一个表单小部件导航到另一个表单小部件时,每个小部件都应该被显式聚焦。因为我们隐藏了初始的复选框,我们必须自己实现这个特性,让用户知道定制复选框在表单中的位置,下列的CSS实现了它们聚焦。</p> + +<pre class="brush: css">:root input[type=checkbox]:focus + label:before { + outline: 1px dotted black; +}</pre> + +<p>你可以在线查看结果:</p> + +<p>{{EmbedLiveSample("A_more_complex_example", 250, 130)}}</p> + +<h3 id="Dealing_with_the_select_nightmare">Dealing with the select nightmare</h3> + +<p>{{HTMLElement("select")}} 元素被认为是一个 "丑陋的" 组件,因为不可能保证它在跨平台时样式化的一致性。然而,有些事情是可能的。废话少说,让我们来看一个例子:</p> + +<pre class="brush: html"><select> + <option>Cherry</option> + <option>Banana</option> + <option>Strawberry</option> +</select></pre> + +<pre class="brush: css">select { + width : 80px; + padding : 10px; +} + +option { + padding : 5px; + color : red; +}</pre> + +<p>下面的表格显示了在两种情况下不同浏览器的处理方式。头两列就是上面的例子。后面两列使用了其他的定制CSS,可以对小部件的外观进行更多的控制:</p> + +<pre class="brush: css">select, option { + -webkit-appearance : none; /* To gain control over the appearance on WebKit/Chromium */ + -moz-appearance : none; /* To gain control over the appearance on Gecko */ + + /* To gain control over the appearance on and Trident (IE) + Note that it also works on Gecko and has partial effects on WebKit */ + background : none; +}</pre> + +<table> + <thead> + <tr> + <th colspan="1" rowspan="2" scope="col">Browser</th> + <th colspan="2" scope="col">Regular rendering</th> + <th colspan="2" scope="col">Tweaked rendering</th> + </tr> + <tr> + <th scope="col">closed</th> + <th scope="col">open</th> + <th scope="col">closed</th> + <th scope="col">open</th> + </tr> + </thead> + <tbody> + <tr> + <td>Firefox 57 (Mac OSX)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15672/firefox-mac-select-1-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15673/firefox-mac-select-1-open.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15674/firefox-mac-select-2-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15675/firefox-mac-select-2-open.png"></td> + </tr> + <tr> + <td>Firefox 57 (Windows 10)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15692/firefox-windows-select-1-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15693/firefox-windows-select-1-open.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15694/firefox-windows-select-2-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15695/firefox-windows-select-2-open.png"></td> + </tr> + <tr> + <td>Chrome 63 (Mac OSX)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15677/chrome-mac-select-1-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15678/chrome-mac-select-1-open.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15684/chrome-windows-select-2-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15680/chrome-mac-select-2-open.png"></td> + </tr> + <tr> + <td>Chrome 63 (Windows 10)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15682/chrome-windows-select-1-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15683/chrome-windows-select-1-open.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15684/chrome-windows-select-2-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15685/chrome-windows-select-2-open.png"></td> + </tr> + <tr> + <td>Opera 49 (Mac OSX)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15702/opera-mac-select-1-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15703/opera-mac-select-1-open.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15704/opera-mac-select-2-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15705/opera-mac-select-2-open.png"></td> + </tr> + <tr> + <td>IE11 (Windows 10)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15697/ie11-select-1-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15698/ie11-select-1-open.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15699/ie11-select-2-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15700/ie11-select-2-open.png"></td> + </tr> + <tr> + <td>Edge 16 (Windows 10)</td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15687/edge-select-1-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15688/edge-select-1-open.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15689/edge-select-2-closed.png"></td> + <td><img alt="" src="https://mdn.mozillademos.org/files/15690/edge-select-2-open.png"></td> + </tr> + </tbody> +</table> + +<p>如你所见,计时使用了<code>-*-appearance</code>属性的帮助,任然有一些遗留的问题:</p> + +<ul> + <li>不同的操作系统和浏览器对属性{{cssxref("padding")}} 属性的处理各不相同。</li> + <li>Internet Explorer旧版本不允许平滑样式</li> + <li>Firefox没有实现下拉箭头的样式。</li> + <li>如果要在下拉列表内实现{{HTMLElement("option")}}元素样式,Chrome和Opera浏览器的表现在不同的系统中是不一样的。</li> +</ul> + +<p>在我们的例子中,只使用了三个CSS属性,在考虑使用更多CSS属性时,可以想象是很混乱的。正如我们看到的,CSS始终不适合用来修改这些小部件的外观,但是仍然可以用来稍微做一些事情。如果愿意的话,可以演示一下在不同操作系统和浏览器之间的区别。</p> + +<p>我们也可以帮助了解在下一章节中哪个属性更合适:<a href="/en-US/docs/Properties_compatibility_table_for_forms_widgets" title="/en-US/docs/Properties_compatibility_table_for_forms_widgets">Properties compatibility table for form widgets</a></p> + +<h2 id="走向更完美表单之路:有用的库和polyfills(腻子)">走向更完美表单之路:有用的库和polyfills(腻子)</h2> + +<p>虽然对于复选框和单选按钮而言,CSS的表示方式足够丰富,但是对更高级的小部件来说差距仍然很大。即使可以用{{HTMLElement("select")}}元素作一些事情,但是对file小部件的样式完全没用。对于日期选择器也同样如此。</p> + +<p>要实现对表单小部件的完全控制,你别无选择,只能选择依靠JavaScript。在文章<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> + +<ul> + <li><a href="http://sprawsm.com/uni-form/" rel="external" title="http://sprawsm.com/uni-form/">Uni-form</a>是一个对采用CSS样式的表单标记实现标准化的框架,在使用jQuery时,还提供一些附加特性,但这是可选的。</li> + <li><a href="http://formalize.me/" rel="external" title="http://formalize.me/">Formalize</a>是对公共JavaScript框架的扩展(如jQuery, Dojo, YUI等),有助于规范和定制表单。</li> + <li><a href="http://www.emblematiq.com/lab/niceforms/" rel="external" title="http://www.emblematiq.com/lab/niceforms/">Niceforms</a>是一个独立的JavaScript方法,能提供web表单的完整定制。</li> +</ul> + +<p>下面的库不止应用于表单,他们在处理HTML表单时是非常有趣的:</p> + +<ul> + <li><a href="http://jqueryui.com/" rel="external" title="http://jqueryui.com/">jQuery UI</a>做了一些有趣的改进,可以定制象日期选择器(特别关注可访问性)这样的小部件。</li> + <li><a href="http://twitter.github.com/bootstrap/base-css.html#forms" rel="external" title="http://twitter.github.com/bootstrap/base-css.html#forms">Twitter Bootstrap</a>在规范表单时是非常有用的。</li> + <li><a href="http://afarkas.github.com/webshim/demos/demos/webforms.html" rel="external" title="http://afarkas.github.com/webshim/demos/demos/webforms.html">WebShim</a>是一个大型工具,可以用来处理浏览器对HTML5的支持。对web表单部分确实有用。</li> +</ul> + +<p>记住,使用CSS和JavaScript是有副作用的。所以在选择使用那些库时,应该在脚本失败的情况下能回滚样式表。脚本失败的原因很多,尤其在手机应用中,因此你需要尽可能好的设计你的Web站点或应用。</p> + +<h2 id="相关链接">相关链接</h2> + +<p>虽然HTML表单使用CSS仍有一些黑洞,但通常也有方法绕过它们。即使没有清楚的,通用的解决方案,但新式的浏览器也提供了新的可能性。目前最好的方法是更多的学习不同浏览器支持CSS的方式,并应用于HTML表单小部件。</p> + +<p>在本指南的下一章节中,我们将探讨不同的HTML表单小部件怎样很好的支持更重要的CSS属性:<a href="/en-US/docs/Properties_compatibility_table_for_forms_widgets" title="/en-US/docs/Properties_compatibility_table_for_forms_widgets">Properties compatibility table for form widgets</a>.</p> + +<h2 id="相关链接_2">相关链接</h2> + +<ul> + <li><a href="http://diveintohtml5.info/forms.html" rel="external" title="http://diveintohtml5.info/forms.html">Dive into HTML5: Forms</a></li> + <li><a href="http://www.smashingmagazine.com/2011/06/27/useful-ideas-and-guidelines-for-good-web-form-design/" rel="external" title="http://www.smashingmagazine.com/2011/06/27/useful-ideas-and-guidelines-for-good-web-form-design/">Useful ideas and guidelines for good web form design</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/Styling_HTML_forms", "Learn/HTML/Forms/Property_compatibility_table_for_form_widgets", "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> + +<p> + <audio style="display: none;"></audio> +</p> diff --git a/files/zh-cn/learn/html/forms/data_form_validation/index.html b/files/zh-cn/learn/html/forms/data_form_validation/index.html new file mode 100644 index 0000000000..62758a26e6 --- /dev/null +++ b/files/zh-cn/learn/html/forms/data_form_validation/index.html @@ -0,0 +1,874 @@ +--- +title: 表单数据校验 +slug: Learn/HTML/Forms/Data_form_validation +tags: + - HTML +translation_of: Learn/Forms/Form_validation +--- +<p>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms/How_to_build_custom_form_widgets", "Learn/HTML/Forms")}}</p> + +<p class="summary">表单校验帮助我们确保用户以正确格式填写表单数据,确保提交的数据能使我们的应用程序正常工作。本文将告诉您需要了解的有关表单校验的内容。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">预备知识:</th> + <td>计算机基础能力,对 <a href="/en-US/docs/Learn/HTML">HTML</a>、<a href="/en-US/docs/Learn/CSS">CSS</a> 和 <a href="/en-US/docs/Learn/JavaScript">JavaScript</a> 有一定的理解。</td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>理解表单校验是什么,为什么它很重要,以及如何实现它。</td> + </tr> + </tbody> +</table> + +<h2 id="什么是表单数据校验?">什么是表单数据校验?</h2> + +<p>访问任何一个带注册表单的网站,你都会发现,当你提交了没有输入符合预期格式的信息的表单时,注册页面都会给你一个反馈,这些信息可能看起来像下面这样的:</p> + +<ul> + <li>“该字段是必填的”(该字段不能留空)</li> + <li>“请输入你的电话号码,它的格式是:xxx-xxxx”(它要求你输入的数据格式为三个数字接一个横杠,然后再接着是四个数字)</li> + <li>“请输入一个合法的邮箱地址”(如果你输入的数据不符合“somebody@example.com“的邮箱格式)</li> + <li>“你的密码长度应该是8至30位的,并且至少应该包含一个大写字母、一个符号以及一个数字”</li> +</ul> + +<p>这就是<strong>表单校验</strong> —— 当你向 Web 应用输入数据时,应用会验证你输入的数据是否是正确的。如果验证通过,应用允许提交这些数据到服务器并储存到数据库中(通常情况下),如果验证未通过,则 Web 应用会提示你有错误的数据,并且一般都会明确的告诉你错误发生在哪里。表单校验可以通过许多不同的方式实现。</p> + +<div class="note"> +<p><strong>译者注</strong>:下面一段在英文原文中已经删除</p> +</div> + +<p>(事实上,没有人愿意填写表单 —— 很多证据表明,用户对填写表单这件事情都感到很烦恼,如果他们在填写表单的过程中遇到一些自己无法理解的问题,通常都会导致他们直接离开你的 Web 应用,简而言之,<a href="https://www.slideshare.net/jwegesin/forms-suck/">表单是一个很烦人的东西</a>。)</p> + +<p>我们希望把填写表单变的越简单越好。那么,为什么我们还坚持进行表单的数据校验呢?这有三个最主要的原因:</p> + +<ul> + <li><strong>我们希望以正确的格式获取到正确的数据</strong> —— 如果我们的用户数据以不正确的格式存储,或者他们没有输入正确的信息/完全省略信息,我们的应用程序将无法正常运行。</li> + <li><strong>我们希望保护我们的用户</strong> ——强制用户输入安全的密码,有利于保护他们的账户信息。</li> + <li><strong>我们希望保护我们自己</strong> —— 恶意用户有很多通过滥用应用中缺乏保护的表单破坏应用的方法(具体请参见<a href="/zh-CN/docs/learn/Server-side/First_steps/Website_security">网站安全</a>)。</li> +</ul> + +<div class="blockIndicator warning"> +<p>警告: 永远不要相信从客户端传递到服务器的数据。 即使您的表单正确验证并防止输入格式错误,恶意用户仍然可以更改网络请求。</p> +</div> + +<h3 id="不同类型的表单数据校验">不同类型的表单数据校验</h3> + +<p>在 Web 中,你可能会遇见各种不同的表单校验:</p> + +<ul> + <li><strong>客户端校验</strong>发生在浏览器端,表单数据被提交到服务器之前,这种方式相较于服务器端校验来说,用户体验更好,它能实时的反馈用户的输入校验结果,这种类型的校验可以进一步细分成下面这些方式: + + <ul> + <li><strong>JavaScript</strong> 校验,这是可以完全自定义的实现方式;</li> + <li>HTML5 <strong>内置校验</strong>,这不需要 JavaScript ,而且性能更好,但是不能像JavaScript那样可自定义。</li> + </ul> + </li> + <li><strong>服务器端校验</strong>则是发生在浏览器提交数据并被服务器端程序接收之后 —— 通常服务器端校验都是发生在将数据写入数据库之前,如果数据没通过校验,则会直接从服务器端返回错误消息,并且告诉浏览器端发生错误的具体位置和原因,服务器端校验不像客户端校验那样有好的用户体验,因为它直到整个表单都提交后才能返回错误信息。但是服务器端校验是你的应用对抗错误/恶意数据的最后防线,在这之后,数据将被持久化至数据库。当今<a href="/zh-CN/docs/learn/Server-side/First_steps/Web_frameworks">所有的服务端框架</a>都提供了数据<strong>校验</strong>与<strong>清洁</strong>功能(让数据更安全)。</li> +</ul> + +<p>在真实的项目开发过程中,开发者一般都倾向于使用客户端校验与服务器端校验的组合校验方式以更好的保证数据的正确性与安全性。</p> + +<h2 id="使用内置表单数据校验">使用内置表单数据校验</h2> + +<p><a href="/en-US/docs/HTML/HTML5" title="/en-US/docs/HTML/HTML5">HTML5</a> 一个特别有用的新功能就是,可以在不写一行脚本代码的情况下,即对用户的输入进行数据校验,这都是通过表单元素的<a href="/zh-CN/docs/Web/Guide/HTML/HTML5/Constraint_validation">校验属性</a>实现的,这些属性可以让你定义一些规则,用于限定用户的输入,比如某个输入框是否必须输入,或者某个输入框的字符串的最小最大长度限制,或者某个输入框必须输入一个数字、邮箱地址等;还有数据必须匹配的模式。如果表单中输入的数据都符合这些限定规则,那么表示这个表单校验通过,否则则认为校验未通过。</p> + +<p>当一个元素校验通过时:</p> + +<ul> + <li>该元素将可以通过 CSS 伪类 {{cssxref(":valid")}} 进行特殊的样式化;</li> + <li>如果用户尝试提交表单,如果没有其它的控制来阻止该操作(比如JavaScript即可阻止提交),那么该表单的数据会被提交。</li> +</ul> + +<p>如果一个元素未校验通过:</p> + +<ul> + <li>该元素将可以通过 CSS 伪类 {{cssxref(":invalid")}} 进行特殊的样式化;</li> + <li>如果用户尝试提交表单,浏览器会展示出错误消息,并停止表单的提交。 </li> +</ul> + +<h3 id="input_元素的校验约束_—_starting_simple">input 元素的校验约束 — starting simple</h3> + +<p>在这一节,我们将会看到一些用于{{HTMLElement("input")}}元素校验的HTML5的特性。</p> + +<p>让我们用一个简单的例子开始 — 一个可以让你从香蕉或樱桃中选择你最喜欢的水果的input。 这个包含了一个简单的文本{{HTMLElement("input")}} 和一个与之匹配的label,还有一个 submit {{htmlelement("button")}}。你可以在GitHub <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-start.html">fruit-start.html</a>找到源码,在线例子如下:</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html"><form> + <label for="choose">Would you prefer a banana or cherry?</label> + <input id="choose" name="i_like"> + <button>Submit</button> +</form></pre> + +<pre class="brush: css">input:invalid { + border: 2px dashed red; +} + +input:valid { + border: 2px solid black; +}</pre> +</div> + +<p>{{EmbedLiveSample("Hidden_code", "100%", 50)}}</p> + +<p>开始之前,先拷贝一份 <code>fruit-start.html</code> 放在你硬盘上的新目录里。</p> + +<h3 id="required_属性">required 属性</h3> + +<p>最简单的HTML5校验功能是 {{htmlattrxref("required", "input")}}属性 — 如果要使输入成为必需的,则可以使用此属性标记元素。 当设置此属性时,如果输入为空,该表单将不会提交(并将显示错误消息),输入也将被视为无效。</p> + +<p>添加一个 <code>required</code> 属性到你的 input 元素, 如下所示:</p> + +<pre class="brush: html"><form> + <label for="choose">Would you prefer a banana or cherry?</label> + <input id="choose" name="i_like" required> + <button>Submit</button> +</form></pre> + +<p>同时注意在示例文件中包含的 CSS :</p> + +<pre class="brush: css">input:invalid { + border: 2px dashed red; +} + +input:valid { + border: 2px solid black; +}</pre> + +<p>以上样式效果为:在校验失败时 输入框会有一个亮红色的虚线边框, 在校验通过时会有一个更微妙的黑色边框。在以下示例中尝试新的行为:</p> + +<p>{{EmbedLiveSample("required_属性", "100%", 50)}}</p> + +<h3 id="使用正则表达式校验">使用正则表达式校验</h3> + +<p>另一个常用的校验功能是 {{htmlattrxref("pattern","input")}} 属性, 以 <a href="/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions" title="/en-US/docs/JavaScript/Guide/Regular_Expressions">Regular Expression</a> 作为 value 值. 正则表达式 (regex) 是一个可以用来匹配文本字符串中字符的组合的模式,所以它们是理想的表单校验器,也可以支持 JavaScript 中许多其它的用途。</p> + +<p>正则表达式相当复杂,我们不打算在本文中详尽地教你。</p> + +<p>下面是一些例子,让你对它们的工作原理有个基本的了解:</p> + +<ul> + <li><code>a</code> — 匹配一个字符<code>a</code>(不能匹配 <code>b</code>, <code>aa</code>等等.)</li> + <li><code>abc</code> — 匹配 <code>a</code>, 其次 <code>b</code>, 最后 <code>c</code>.</li> + <li><code>a*</code> — 匹配0个或者多个字符 <code>a</code> (<code>+</code> 代表至少匹配一个或者多个).</li> + <li><code>[^a]</code> — 匹配一个字符,但它<strong>不能</strong>是<code>a</code>.</li> + <li><code>a|b</code> — 匹配一个字符 <code>a</code> 或者 <code>b</code>.</li> + <li><code>[abc]</code> — 匹配一个字符,它可以是<code>a</code>,<code>b</code>或<code>c</code>.</li> + <li><code>[^abc]</code> — 匹配一个字符,但它<strong>不可以</strong>是<code>a</code>,<code>b</code>或<code>c</code>.</li> + <li><code>[a-z]</code> — 匹配字符范围 <code>a-z</code>且全部小写 (你可以使用 <code>[A-Za-z]</code> 涵盖大小写, 或 <code>[A-Z]</code> 来限制必须大写).</li> + <li><code>a.c</code> — 匹配字符 <code>a</code>,中间匹配任意一个字符,最后匹配字符<code> c</code>.</li> + <li><code>a{5}</code> — 匹配字符 <code>a</code>五次.</li> + <li><code>a{5,7}</code> — 匹配字符 <code>a</code>五到七次,不能多或者少.</li> +</ul> + +<p>你也可以在这些表达式中使用数字和其他字符, 例如:</p> + +<ul> + <li><code>[ -]</code> — 匹配一个空格或者虚线.</li> + <li><code>[0-9]</code> — 匹配数字范围0~9.</li> +</ul> + +<p>你可以任意地组合这些,你可以任意指定不同的部分:</p> + +<ul> + <li><code>[Ll].*k</code> — 匹配一个大写<code>L</code>或者小写的<code>l</code>, 之后匹配0个或多个任意类型的字符, 最后匹配一个小写字母 k.</li> + <li><code>[A-Z][A-Za-z' -]+</code> — 一个大写字母后面跟着匹配一个及以上的大小写字母或者中划线或者撇号或者空格. 这个可以用于校验英语会话中城市或城镇名, 但这需要首字母以大写开头,不包括其他字符,例如来自英国的Manchester, Ashton-under-lyne, 以及Bishop's Stortford等.</li> + <li><code>[0-9]{3}[ -][0-9]{3}[ -][0-9]{4}</code> — 简单的匹配一个美国内的电话号码 — 三个数字 0<code>-</code>9, 后面跟着一个空格或者中划线, 之后匹配三个数字 0<code>-</code>9, 再跟着一个空格或者中划线, 最后跟着四个数字 0<code>-</code>9. 但实际情况可能更加复杂,因为有些人会给号码加上括号什么的,这里的表达式只是用来做一个简单的演示.</li> +</ul> + +<p>不管怎么说, 让我们来实现这些例子 — 更新你的html文档表单增加一个 <code>pattern</code> 属性, 如下:</p> + +<pre class="brush: html"><form> + <label for="choose">Would you prefer a banana or a cherry?</label> + <input id="choose" name="i_like" required pattern="banana|cherry"> + <button>Submit</button> +</form></pre> + +<div class="hidden"> +<pre class="brush: css">input:invalid { + border: 2px dashed red; +} + +input:valid { + border: 2px solid black; +}</pre> +</div> + +<p>{{EmbedLiveSample("使用正则表达式校验", "100%", 50)}}</p> + +<p>这个例子中, 该 {{HTMLElement("input")}} 元素接受两个值中的一个: 字符串 "banana" 或者字符串"cherry".</p> + +<p>在这个基础上, 尝试把<code>pattern</code> 属性内部的表达式改变成上面的几个例子, 然后看看这些表达式如何影响您可以输入的值以使输入值有效. 尝试写一些你自己设计的,看看它如何工作。尽量让他们与水果有关这样你的例子才会有意义.</p> + +<div class="note"> +<p><strong>注意:</strong> 一些 {{HTMLElement("input")}} 元素类型不需要{{htmlattrxref("pattern","input")}} 属性进行校验. 指定特定 <code>email</code> 类型 就会使用匹配电子邮件格式的正则表达式来校验(如果有 {{htmlattrxref("multiple","input")}} 属性请用逗号来分割多个邮箱). 进一步来说, 字段 <code>url</code> 类型则会自动校验输入的是否为一个合法的链接.</p> +</div> + +<div class="note"> +<p><strong>注意</strong>: 该 {{HTMLElement("textarea")}} 元素不支持{{htmlattrxref("pattern","input")}} 属性.</p> +</div> + +<h3 id="限制输入的长度">限制输入的长度</h3> + +<p>所有文本框 ({{HTMLElement("input")}} 或 {{HTMLElement("textarea")}}) 都可以使用{{htmlattrxref("minlength","input")}} 和 {{htmlattrxref("maxlength","input")}} 属性来限制长度. 如果输入的字段长度小于 {{htmlattrxref("minlength","input")}} 的值或大于 {{htmlattrxref("maxlength","input")}} 值则无效. 浏览器通常不会让用户在文本字段中键入比预期更长的值,不过更精细的设置总归是更好的。</p> + +<p>在数字条目中 (i.e. <code><input type="number"></code>), 该 {{htmlattrxref("min","input")}} 和 {{htmlattrxref("max","input")}} 属性同样提供校验约束.如果字段的值小于{{htmlattrxref("min","input")}} 属性的值或大于 {{htmlattrxref("max","input")}} 属性的值,该字段则无效.</p> + +<p>让我来看看另外一个例子. 创建一个 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-start.html">fruit-start.html</a> 文件副本.</p> + +<p>现在删除 <code><body></code> 元素中的内容, 替换成下面的代码:</p> + +<pre class="brush: html"><form> + <div> + <label for="choose">Would you prefer a banana or a cherry?</label> + <input id="choose" name="i_like" required minlength="6" maxlength="6"> + </div> + <div> + <label for="number">How many would you like?</label> + <input type="number" id="number" name="amount" value="1" min="1" max="10"> + </div> + <div> + <button>Submit</button> + </div> +</form></pre> + +<ul> + <li>这里我们看到 <code>text</code> 条目的属性<code>minlength</code> 和 <code>maxlength</code> 都为6 — 这 banana 和 cherry的长度都为6. 输入少于这个长度的字符显示无效, 大多浏览器不能输入超过该限制的长度的字符.</li> + <li>我们同时也能让 <code>number</code> 条目数值限制在 <code>min</code> 为 1 和 一个 <code>max</code> 为 10 中 — 输入超出范围则显示无效, 并且您将无法使用递增/递减箭头将该值改变到此范围之外。</li> +</ul> + +<div class="hidden"> +<pre>input:invalid { + border: 2px dashed red; +} + +input:valid { + border: 2px solid black; +} + +div { + margin-bottom: 10px; +}</pre> +</div> + +<p>这里是运行的例子:</p> + +<p>{{EmbedLiveSample("限制输入的长度", "100%", 70)}}</p> + +<div class="note"> +<p><strong>注意</strong>: <code><input type="number"></code> (或者其他类型, 像 <code>range</code>) 也可以获取到一个{{htmlattrxref("step", "input")}} 属性, 指定了值在增减过程固定改变的值 (如向上增加和向下减少的按钮).</p> +</div> + +<h3 id="完整的例子">完整的例子</h3> + +<p>这里就是一个完整的展示 HTML 中使用校验属性的例子:</p> + +<pre class="brush: html"><form> + <p> + <fieldset> + <legend>Title<abbr title="This field is mandatory">*</abbr></legend> + <input type="radio" required name="title" id="r1" value="Mr"><label for="r1">Mr.</label> + <input type="radio" required name="title" id="r2" value="Ms"><label for="r2">Ms.</label> + </fieldset> + </p> + <p> + <label for="n1">How old are you?</label> + <!-- 这里的pattern属性可以用作不支持number类input浏览器的备用方法 + 请注意当与数字输入框一起使用时,支持pattern属性的浏览器会使它沉默失效。 + 它仅仅是在这里用作备用 --> + <input type="number" min="12" max="120" step="1" id="n1" name="age" + pattern="\d+"> + </p> + <p> + <label for="t1">What's your favorite fruit?<abbr title="This field is mandatory">*</abbr></label> + <input type="text" id="t1" name="fruit" list="l1" required + pattern="[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range"> + <datalist id="l1"> + <option>Banana</option> + <option>Cherry</option> + <option>Apple</option> + <option>Strawberry</option> + <option>Lemon</option> + <option>Orange</option> + </datalist> + </p> + <p> + <label for="t2">What's your e-mail?</label> + <input type="email" id="t2" name="email"> + </p> + <p> + <label for="t3">Leave a short message</label> + <textarea id="t3" name="msg" maxlength="140" rows="5"></textarea> + </p> + <p> + <button>Submit</button> + </p> +</form></pre> + +<pre class="brush: css">body { + font: 1em sans-serif; + padding: 0; + margin : 0; +} + +form { + max-width: 200px; + margin: 0; + padding: 0 5px; +} + +p > label { + display: block; +} + +input[type=text], +input[type=email], +input[type=number], +textarea, +fieldset { +/* 需要在基于WebKit的浏览器上对表单元素进行恰当的样式设置 */ + -webkit-appearance: none; + + width : 100%; + border: 1px solid #333; + margin: 0; + + font-family: inherit; + font-size: 90%; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +input:invalid { + box-shadow: 0 0 5px 1px red; +} + +input:focus:invalid { + outline: none; +}</pre> + +<p>{{EmbedLiveSample("完整的例子", "100%", 420)}}</p> + +<h3 id="自定义错误信息">自定义错误信息</h3> + +<p>正如我们上面所看到的例子, 每次我们提交无效的表单数据时, 浏览器总会显示错误信息. 但是显示的信息取决于你所使用的浏览器.</p> + +<p>这些自动生成的错误有两个缺点:</p> + +<ul> + <li>没有标准可以让 CSS 来改变他们的界面外观.</li> + <li>这依赖于他们使用的浏览器环境, 意味着你可能在这种语言的页面里得到另一种语言的错误提示.</li> +</ul> + +<table> + <caption>在英文页面上的法语反馈信息版本</caption> + <thead> + <tr> + <th scope="col">浏览器</th> + <th scope="col">渲染</th> + </tr> + </thead> + <tbody> + <tr> + <td>Firefox 17 (Windows 7)</td> + <td><img alt="Example of an error message with Firefox in French on an English page" src="/files/4329/error-firefox-win7.png" style="height: 97px; width: 228px;"></td> + </tr> + <tr> + <td>Chrome 22 (Windows 7)</td> + <td><img alt="Example of an error message with Chrome in French on an English page" src="/files/4327/error-chrome-win7.png" style="height: 96px; width: 261px;"></td> + </tr> + <tr> + <td>Opera 12.10 (Mac OSX)</td> + <td><img alt="Example of an error message with Opera in French on an English page" src="/files/4331/error-opera-macos.png" style="height: 83px; width: 218px;"></td> + </tr> + </tbody> +</table> + +<p>要自定义这些消息的外观和文本, 你必须使用 JavaScript; 不能使用 HTML 和 CSS 来改变.</p> + +<p>HTML5 提供 <a href="http://www.w3.org/TR/html5/forms.html#the-constraint-validation-api" rel="external" title="http://www.w3.org/TR/html5/forms.html#the-constraint-validation-api">constraint validation API</a> 来检测和自定义表单元素的状态. 除此之外,他可以改变错误信息的文本. 让我们快速的看一个例子:</p> + +<pre class="brush: html"><form> + <label for="mail">I would like you to provide me an e-mail</label> + <input type="email" id="mail" name="mail"> + <button>Submit</button> +</form></pre> + +<p>在JavaScript 中, 你调用 <a href="/en-US/docs/HTML/HTML5/Constraint_validation#Constraint_API's_element.setCustomValidity()" title="/en-US/docs/HTML/HTML5/Constraint_validation#Constraint_API's_element.setCustomValidity()"><code>setCustomValidity()</code></a> 方法:</p> + +<pre class="brush: js">var email = document.getElementById("mail"); + +email.addEventListener("input", function (event) { + if (email.validity.typeMismatch) { + email.setCustomValidity("I expect an e-mail, darling!"); + } else { + email.setCustomValidity(""); + } +});</pre> + +<p>{{EmbedLiveSample("自定义错误信息", "100%", 50)}}</p> + +<h2 id="使用_JavaScript校验表单"> 使用 JavaScript校验表单</h2> + +<p>如果你想控制原生错误信息的界面外观,或者你想处理不支持HTML内置表单校验的浏览器,则必须使用 Javascript。</p> + +<h3 id="约束校验的_API">约束校验的 API</h3> + +<p>越来越多的浏览器支持限制校验API,并且这逐渐变得可靠。这些 API 由成组的方法和属性构成,可在特定的表单元素接口上调用:</p> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement">HTMLButtonElement</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLFieldSetElement">HTMLFieldSetElement</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement">HTMLInputElement</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLOutputElement">HTMLOutputElement</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement">HTMLSelectElement</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement">HTMLTextAreaElement</a></li> +</ul> + +<h4 id="约束校验的_API_及属性">约束校验的 API 及属性</h4> + +<table> + <thead> + <tr> + <th scope="col">属性</th> + <th scope="col">描述</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>validationMessage</code></td> + <td>一个本地化消息,描述元素不满足校验条件时(如果有的话)的文本信息。如果元素无需校验(<code>willValidate</code> 为 <code>false</code>),或元素的值满足校验条件时,为空字符串。</td> + </tr> + <tr> + <td><code>validity</code></td> + <td>一个 {{domxref("ValidityState")}} 对象,描述元素的验证状态。详见有关可能的验证状态的文章。</td> + </tr> + <tr> + <td><code>validity.customError</code></td> + <td>如果元素设置了自定义错误,返回 <code>true</code> ;否则返回<code>false</code>。</td> + </tr> + <tr> + <td><code>validity.patternMismatch</code></td> + <td>如果元素的值不匹配所设置的正则表达式,返回 <code>true</code>,否则返回 <code>false</code>。<br> + <br> + 当此属性为 <code>true</code> 时,元素将命中 {{cssxref(":invalid")}} CSS 伪类。</td> + </tr> + <tr> + <td><code>validity.rangeOverflow</code></td> + <td>如果元素的值高于所设置的最大值,返回 <code>true</code>,否则返回 <code>false</code>。<br> + <br> + 当此属性为 <code>true</code> 时,元素将命中 {{cssxref(":invalid")}} CSS 伪类。</td> + </tr> + <tr> + <td><code>validity.rangeUnderflow</code></td> + <td>如果元素的值低于所设置的最小值,返回 <code>true</code>,否则返回 <code>false</code>。<br> + <br> + 当此属性为 <code>true</code> 时,元素将命中 {{cssxref(":invalid")}} CSS 伪类。</td> + </tr> + <tr> + <td><code>validity.stepMismatch</code></td> + <td>如果元素的值不符合 step 属性的规则,返回 <code>true</code>,否则返回 <code>false</code>。<br> + <br> + 当此属性为 <code>true</code> 时,元素将命中 {{cssxref(":invalid")}} CSS 伪类。</td> + </tr> + <tr> + <td><code>validity.tooLong</code></td> + <td>如果元素的值超过所设置的最大长度,返回 <code>true</code>,否则返回 <code>false</code>。<br> + <br> + 当此属性为 <code>true</code> 时,元素将命中 {{cssxref(":invalid")}} CSS 伪类。</td> + </tr> + <tr> + <td><code>validity.typeMismatch</code></td> + <td>如果元素的值出现语法错误,返回 <code>true</code>,否则返回 <code>false</code>。<br> + <br> + 当此属性为 <code>true</code> 时,元素将命中 {{cssxref(":invalid")}} CSS 伪类。</td> + </tr> + <tr> + <td><code>validity.valid</code></td> + <td>如果元素的值不存在校验问题,返回 <code>true</code>,否则返回 <code>false</code>。<br> + <br> + 当此属性为 <code>true</code> 时,元素将命中 {{cssxref(":valid")}} CSS 伪类,否则命中 {{cssxref(":invalid")}} CSS 伪类。</td> + </tr> + <tr> + <td><code>validity.valueMissing</code></td> + <td>如果元素设置了 required 属性且值为空,返回 <code>true</code>,否则返回 <code>false</code>。<br> + <br> + 当此属性为 true 时,元素将命中 {{cssxref(":invalid")}} CSS 伪类。</td> + </tr> + <tr> + <td><code>willValidate</code></td> + <td>如果元素在表单提交时将被校验,返回 <code>true</code>,否则返回 <code>false</code>。</td> + </tr> + </tbody> +</table> + +<h4 id="约束校验_API_的方法">约束校验 API 的方法</h4> + +<table> + <thead> + <tr> + <th scope="col">方法</th> + <th scope="col">描述</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>checkValidity()</code></td> + <td>如果元素的值不存在校验问题,返回 <code>true</code>,否则返回 <code>false</code>。如果元素校验失败,此方法会触发{{event("invalid")}} 事件。</td> + </tr> + <tr> + <td>{{domxref("HTMLFormElement.reportValidity()")}}</td> + <td>如果元素或它的子元素控件符合校验的限制,返回 <code>true</code> . 当返回为 <code>false</code> 时, 对每个无效元素可撤销 {{event("invalid")}} 事件会被唤起并且校验错误会报告给用户 。</td> + </tr> + <tr> + <td> + <p><code>setCustomValidity(<em>message</em>)</code></p> + </td> + <td>为元素添加一个自定义的错误消息;如果设置了自定义错误消息,该元素被认为是无效的,则显示指定的错误。这允许你使用 JavaScript 代码来建立校验失败,而不是用标准约束校验 API 所提供的。这些自定义信息将在向用户报告错误时显示。<br> + <br> + 如果参数为空,则清空自定义错误。</td> + </tr> + </tbody> +</table> + +<p>对于旧版浏览器,可以使用 <a href="https://hyperform.js.org/" rel="external" title="https://hyperform.js.org/">polyfill(例如 Hyperform</a>),来弥补其对约束校验 API 支持的不足。既然你已经使用 JavaScript,在您的网站或 Web 应用程序的设计和实现中使用 polyfill 并不是累赘。</p> + +<h4 id="使用约束校验_API_的例子">使用约束校验 API 的例子</h4> + +<p>让我们看看如何使用这个 API 来构建自定义错误消息。首先,HTML:</p> + +<pre class="brush: html"><form novalidate> + <p> + <label for="mail"> + <span>Please enter an email address:</span> + <input type="email" id="mail" name="mail"> + <span class="error" aria-live="polite"></span> + </label> + </p> + <button>Submit</button> +</form></pre> + +<p>这个简单的表单使用 {{htmlattrxref("novalidate","form")}} 属性关闭浏览器的自动校验;这允许我们使用脚本控制表单校验。但是,这并不禁止对约束校验 API的支持或是以下 CSS 伪类:{{cssxref(":valid")}}、{{cssxref(":invalid")}}、{{cssxref(":in-range")}} 、{{cssxref(":out-of-range")}} 的应用。这意味着,即使浏览器在发送数据之前没有自动检查表单的有效性,您仍然可以自己做,并相应地设置表单的样式。</p> + +<p><a href="/en-US/docs/Accessibility/ARIA/ARIA_Live_Regions" title="/en-US/docs/Accessibility/ARIA/ARIA_Live_Regions"><code>aria-live</code></a> 属性确保我们的自定义错误信息将呈现给所有人,包括使用屏幕阅读器等辅助技术的人。</p> + +<h5 id="CSS">CSS</h5> + +<p>以下 CSS 样式使我们的表单和其错误输出看起来更有吸引力。</p> + +<pre class="brush: css">/* 仅为了使示例更好看 */ +body { + font: 1em sans-serif; + padding: 0; + margin : 0; +} + +form { + max-width: 200px; +} + +p * { + display: block; +} + +input[type=email]{ + -webkit-appearance: none; + + width: 100%; + border: 1px solid #333; + margin: 0; + + font-family: inherit; + font-size: 90%; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +/* 校验失败的元素样式 */ +input:invalid{ + border-color: #900; + background-color: #FDD; +} + +input:focus:invalid { + outline: none; +} + +/* 错误消息的样式 */ +.error { + width : 100%; + padding: 0; + + font-size: 80%; + color: white; + background-color: #900; + border-radius: 0 0 5px 5px; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.error.active { + padding: 0.3em; +}</pre> + +<h5 id="JavaScript">JavaScript</h5> + +<p>以下 JavaScript 代码演示如何设置自定义错误校验。</p> + +<pre class="brush: js">// 有许多方式可以获取 DOM 节点;在此我们获取表单本身和 +// email 输入框,以及我们将放置错误信息的 span 元素。 + +var form = document.getElementsByTagName('form')[0]; +var email = document.getElementById('mail'); +var error = document.querySelector('.error'); + +email.addEventListener("input", function (event) { + // 当用户输入信息时,校验 email 字段 + if (email.validity.valid) { + // 如果校验通过,清除已显示的错误消息 + error.innerHTML = ""; // 重置消息的内容 + error.className = "error"; // 重置消息的显示状态 + } +}, false); +form.addEventListener("submit", function (event) { + // 当用户提交表单时,校验 email 字段 + if (!email.validity.valid) { + + // 如果校验失败,显示一个自定义错误 + error.innerHTML = "I expect an e-mail, darling!"; + error.className = "error active"; + // 还需要阻止表单提交事件,以取消数据传送 + event.preventDefault(); + } +}, false);</pre> + +<p>这是运行结果:</p> + +<p>{{EmbedLiveSample("使用校验约束_API_的例子", "100%", 130)}}</p> + +<p>约束校验 API 为您提供了一个强大的工具来处理表单校验,让您可以对用户界面进行远超过仅仅使用 HTML 和 CSS所能得到的控制。</p> + +<h3 id="不使用内建_API_时的表单校验">不使用内建 API 时的表单校验</h3> + +<p>有时,例如使用旧版浏览器或<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">自定义小部件</a>,您将无法(或不希望)使用约束校验API。 在这种情况下,您仍然可以使用 JavaScript 来校验您的表单。 校验表单比起真实数据校验更像是一个用户界面问题。</p> + +<p>要校验表单,您必须问自己几个问题:</p> + +<dl> + <dt>我应该进行什么样的校验?</dt> + <dd>你需要确定如何校验你的数据:字符串操作,类型转换,正则表达式等。这取决于你。 只要记住,表单数据一般都是文本,并总是以字符串形式提供给脚本。</dd> + <dt>如果表单校验失败,我该怎么办?</dt> + <dd>这显然是一个 UI 问题。 您必须决定表单的行为方式:表单是否发送数据? 是否突出显示错误的字段?是否显示错误消息?</dd> + <dt>如何帮助用户纠正无效数据?</dt> + <dd>为了减少用户的挫折感,提供尽可能多的有用的信息是非常重要的,以便引导他们纠正他们的输入。 您应该提供前期建议,以便他们知道预期的输入是什么以及明确的错误消息。 如果您想深入了解表单校验用户界面要求,那么您应该阅读一些有用的文章: + <ul> + <li>SmashingMagazine: <a href="http://uxdesign.smashingmagazine.com/2012/06/27/form-field-validation-errors-only-approach/" rel="external" title="http://uxdesign.smashingmagazine.com/2012/06/27/form-field-validation-errors-only-approach/">Form-Field Validation: The Errors-Only Approach</a></li> + <li>SmashingMagazine: <a href="http://www.smashingmagazine.com/2009/07/07/web-form-validation-best-practices-and-tutorials/" rel="external" title="http://www.smashingmagazine.com/2009/07/07/web-form-validation-best-practices-and-tutorials/">Web Form Validation: Best Practices and Tutorials</a></li> + <li>Six Revision: <a href="http://sixrevisions.com/user-interface/best-practices-for-hints-and-validation-in-web-forms/" rel="external" title="http://sixrevisions.com/user-interface/best-practices-for-hints-and-validation-in-web-forms/">Best Practices for Hints and Validation in Web Forms</a></li> + <li>A List Apart: <a href="http://www.alistapart.com/articles/inline-validation-in-web-forms/" rel="external" title="http://www.alistapart.com/articles/inline-validation-in-web-forms/">Inline Validation in Web Forms</a></li> + </ul> + </dd> +</dl> + +<h4 id="不使用约束校验API_的例子">不使用约束校验API 的例子</h4> + +<p>为了说明这一点,让我们重构一下前面的例子,以便它可以在旧版浏览器中使用:</p> + +<pre class="brush: html"><form> + <p> + <label for="mail"> + <span>Please enter an email address:</span> + <input type="text" class="mail" id="mail" name="mail"> + <span class="error" aria-live="polite"></span> + </label> + <p> + <!-- Some legacy browsers need to have the `type` attribute + explicitly set to `submit` on the `button`element --> + <button type="submit">Submit</button> +</form></pre> + +<p>正如你所看到的,HTML 几乎是一样的;我们只是关闭了 HTML 校验功能。 请注意,<a href="/en-US/docs/Accessibility/ARIA" title="/en-US/docs/Accessibility/ARIA">ARIA</a> 是与 HTML5 无关的独立规范。</p> + +<h5 id="CSS_2">CSS</h5> + +<p>同样的,CSS也不需要太多的改动, 我们只需将 {{cssxref(":invalid")}} 伪类变成真实的类,并避免使用不适用于 Internet Explorer 6 的属性选择器。</p> + +<pre class="brush: css">/* 仅为了使示例更好看 */ +body { + font: 1em sans-serif; + padding: 0; + margin : 0; +} + +form { + max-width: 200px; +} + +p * { + display: block; +} + +input.mail { + -webkit-appearance: none; + + width: 100%; + border: 1px solid #333; + margin: 0; + + font-family: inherit; + font-size: 90%; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +/* 校验失败的元素样式 */ +input.invalid{ + border-color: #900; + background-color: #FDD; +} + +input:focus.invalid { + outline: none; +} + +/* 错误消息的样式 */ +.error { + width : 100%; + padding: 0; + + font-size: 80%; + color: white; + background-color: #900; + border-radius: 0 0 5px 5px; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.error.active { + padding: 0.3em; +}</pre> + +<h5 id="JavaScript_2">JavaScript</h5> + +<p>JavaScript 代码有很大的变化,需要做更多的工作。</p> + +<pre class="brush: js">// 使用旧版浏览器选择 DOM 节点的方法较少 +var form = document.getElementsByTagName('form')[0]; +var email = document.getElementById('mail'); + +// 以下是在 DOM 中访问下一个兄弟元素的技巧 +// 这比较危险,很容易引起无限循环 +// 在现代浏览器中,应该使用 element.nextElementSibling +var error = email; +while ((error = error.nextSibling).nodeType != 1); + +// 按照 HTML5 规范 +var emailRegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/; + +// 许多旧版浏览器不支持 addEventListener 方法 +// 这只是其中一种简单的处理方法 +function addEvent(element, event, callback) { + var previousEventCallBack = element["on"+event]; + element["on"+event] = function (e) { + var output = callback(e); + + // 返回 `false` 来停止回调链,并中断事件的执行 + if (output === false) return false; + + if (typeof previousEventCallBack === 'function') { + output = previousEventCallBack(e); + if(output === false) return false; + } + } +}; + +// 现在我们可以重构字段的约束校验了 +// 由于不使用 CSS 伪类, 我们必须明确地设置 valid 或 invalid 类到 email 字段上 +addEvent(window, "load", function () { + // 在这里验证字段是否为空(请记住,该字段不是必需的) + // 如果非空,检查它的内容格式是不是合格的 e-mail 地址 + var test = email.value.length === 0 || emailRegExp.test(email.value); + + email.className = test ? "valid" : "invalid"; +}); + +// 处理用户输入事件 +addEvent(email, "input", function () { + var test = email.value.length === 0 || emailRegExp.test(email.value); + if (test) { + email.className = "valid"; + error.innerHTML = ""; + error.className = "error"; + } else { + email.className = "invalid"; + } +}); + +// 处理表单提交事件 +addEvent(form, "submit", function () { + var test = email.value.length === 0 || emailRegExp.test(email.value); + + if (!test) { + email.className = "invalid"; + error.innerHTML = "I expect an e-mail, darling!"; + error.className = "error active"; + + // 某些旧版浏览器不支持 event.preventDefault() 方法 + return false; + } else { + email.className = "valid"; + error.innerHTML = ""; + error.className = "error"; + } +});</pre> + +<p>该结果如下:</p> + +<p>{{EmbedLiveSample("不使用内建_API_时的表单校验", "100%", 130)}}</p> + +<p>正如你所看到的,建立自己的校验系统并不难。 困难的部分是使其足够通用,以跨平台和任何形式使用它可以创建。 有许多库可用于执行表单校验; 你应该毫不犹豫地使用它们。 这里有一些例子:</p> + +<ul> + <li>独立的库(原生 Javascript 实现): + <ul> + <li><a href="http://rickharrison.github.com/validate.js/" rel="external" title="http://rickharrison.github.com/validate.js/">Validate.js</a></li> + </ul> + </li> + <li>jQuery 插件: + <ul> + <li><a href="http://bassistance.de/jquery-plugins/jquery-plugin-validation/" rel="external" title="http://bassistance.de/jquery-plugins/jquery-plugin-validation/">Validation</a></li> + <li><a href="http://unwrongest.com/projects/valid8/" rel="external" title="http://unwrongest.com/projects/valid8/">Valid8</a><span style="display: none;"> </span></li> + </ul> + </li> +</ul> + +<h4 id="远程校验"> 远程校验</h4> + +<p>在某些情况下,执行一些远程校验可能很有用。 当用户输入的数据与存储在应用程序服务器端的附加数据绑定时,这种校验是必要的。 一个应用实例就是注册表单,在这里你需要一个用户名。 为了避免重复,执行一个 AJAX 请求来检查用户名的可用性,要比让先用户发送数据,然后因为表单重复了返回错误信息要好得多。</p> + +<p>执行这样的校验需要采取一些预防措施:</p> + +<ul> + <li>它要求公开 API 和一些数据;您需要确保它不是敏感数据。</li> + <li>网络滞后需要执行异步校验。这需要一些用户界面的工作,以确保如果校验没有适当的执行,用户不会被阻止。</li> +</ul> + +<h2 id="结论">结论</h2> + +<p>表单校验并不需要复杂的 JavaScript,但它需要对用户的仔细考虑。 一定要记住帮助您的用户更正他提供的数据。 为此,请务必:</p> + +<ul> + <li>显示明确的错误消息。</li> + <li>放宽输入格式限制。</li> + <li>指出错误发生的位置(特别是在大型表单中)。</li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms/How_to_build_custom_form_widgets", "Learn/HTML/Forms")}}</p> diff --git a/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_1/index.html b/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_1/index.html new file mode 100644 index 0000000000..93cf5069c2 --- /dev/null +++ b/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_1/index.html @@ -0,0 +1,418 @@ +--- +title: Example 1 +slug: Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_1 +tags: + - HTML + - 表单 +translation_of: Learn/Forms/How_to_build_custom_form_controls/Example_1 +--- +<p>这是第一个<a href="/en-US/docs/Web/Guide/HTML/Forms/How_to_build_custom_form_widgets">如果构建自定义表单小部件</a>的代码解释事例。</p> + +<h2 id="Basic_state" name="Basic_state">基本状态</h2> + +<h3 id="Basic_state_HTML" name="Basic_state_HTML">HTML</h3> + +<pre class="brush: html"><div class="select"> + <span class="value">Cherry</span> + <ul class="optList hidden"> + <li class="option">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> +</div></pre> + +<h3 id="Basic_state_CSS" name="Basic_state_CSS">CSS</h3> + +<pre class="brush: css">/* --------------- */ +/* Required Styles */ +/* --------------- */ + +.select { + position: relative; + display : inline-block; +} + +.select.active, +.select:focus { + box-shadow: 0 0 3px 1px #227755; + outline: none; +} + +.select .optList { + position: absolute; + top : 100%; + left : 0; +} + +.select .optList.hidden { + max-height: 0; + visibility: hidden; +} + +/* ------------ */ +/* Fancy Styles */ +/* ------------ */ + +.select { + font-size : 0.625em; /* 10px */ + font-family : Verdana, Arial, sans-serif; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + padding : 0.1em 2.5em 0.2em 0.5em; /* 1px 25px 2px 5px */ + width : 10em; /* 100px */ + + border : 0.2em solid #000; /* 2px */ + border-radius : 0.4em; /* 4px */ + + box-shadow : 0 0.1em 0.2em rgba(0,0,0,.45); /* 0 1px 2px */ + + background : #F0F0F0; + background : -webkit-linear-gradient(90deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); + background : linear-gradient(0deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); +} + +.select .value { + display : inline-block; + width : 100%; + overflow : hidden; + + white-space : nowrap; + text-overflow : ellipsis; + vertical-align: top; +} + +.select:after { + content : "▼"; + position: absolute; + z-index : 1; + height : 100%; + width : 2em; /* 20px */ + top : 0; + right : 0; + + padding-top : .1em; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + text-align : center; + + border-left : .2em solid #000; + border-radius: 0 .1em .1em 0; + + background-color : #000; + color : #FFF; +} + +.select .optList { + z-index : 2; + + list-style: none; + margin : 0; + padding: 0; + + background: #f0f0f0; + border: .2em solid #000; + border-top-width : .1em; + border-radius: 0 0 .4em .4em; + + box-shadow: 0 .2em .4em rgba(0,0,0,.4); + + -moz-box-sizing : border-box; + box-sizing : border-box; + + min-width : 100%; + max-height: 10em; /* 100px */ + overflow-y: auto; + overflow-x: hidden; +} + +.select .option { + padding: .2em .3em; +} + +.select .highlight { + background: #000; + color: #FFFFFF; +} +</pre> + +<h3 id="基本状态结果">基本状态结果</h3> + +<div>{{ EmbedLiveSample('Basic_state', 120, 130) }}</div> + +<h2 id="Active_state" name="Active_state">活动状态</h2> + +<h3 id="Active_state_HTML" name="Active_state_HTML">HTML</h3> + +<pre class="brush:html"><div class="select active"> + <span class="value">Cherry</span> + <ul class="optList hidden"> + <li class="option">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> +</div></pre> + +<h3 id="Active_state_CSS" name="Active_state_CSS">CSS</h3> + +<pre class="brush:css">/* --------------- */ +/* Required Styles */ +/* --------------- */ + +.select { + position: relative; + display : inline-block; +} + +.select.active, +.select:focus { + box-shadow: 0 0 3px 1px #227755; + outline: none; +} + +.select .optList { + position: absolute; + top : 100%; + left : 0; +} + +.select .optList.hidden { + max-height: 0; + visibility: hidden; +} + +/* ------------ */ +/* Fancy Styles */ +/* ------------ */ + +.select { + font-size : 0.625em; /* 10px */ + font-family : Verdana, Arial, sans-serif; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + padding : 0.1em 2.5em 0.2em 0.5em; /* 1px 25px 2px 5px */ + width : 10em; /* 100px */ + + border : 0.2em solid #000; /* 2px */ + border-radius : 0.4em; /* 4px */ + + box-shadow : 0 0.1em 0.2em rgba(0,0,0,.45); /* 0 1px 2px */ + + background : #F0F0F0; + background : -webkit-linear-gradient(90deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); + background : linear-gradient(0deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); +} + +.select .value { + display : inline-block; + width : 100%; + overflow : hidden; + + white-space : nowrap; + text-overflow : ellipsis; + vertical-align: top; +} + +.select:after { + content : "▼"; + position: absolute; + z-index : 1; + height : 100%; + width : 2em; /* 20px */ + top : 0; + right : 0; + + padding-top : .1em; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + text-align : center; + + border-left : .2em solid #000; + border-radius: 0 .1em .1em 0; + + background-color : #000; + color : #FFF; +} + +.select .optList { + z-index : 2; + + list-style: none; + margin : 0; + padding: 0; + + background: #f0f0f0; + border: .2em solid #000; + border-top-width : .1em; + border-radius: 0 0 .4em .4em; + + box-shadow: 0 .2em .4em rgba(0,0,0,.4); + + -moz-box-sizing : border-box; + box-sizing : border-box; + + min-width : 100%; + max-height: 10em; /* 100px */ + overflow-y: auto; + overflow-x: hidden; +} + +.select .option { + padding: .2em .3em; +} + +.select .highlight { + background: #000; + color: #FFFFFF; +}</pre> + +<h3 id="活动状态结果">活动状态结果</h3> + +<div>{{ EmbedLiveSample('Active_state', 120, 130) }}</div> + +<h2 id="Open_state" name="Open_state">展开状态</h2> + +<h3 id="Open_state_HTML" name="Open_state_HTML">HTML</h3> + +<pre class="brush:html"><div class="select active"> + <span class="value">Cherry</span> + <ul class="optList"> + <li class="option highlight">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> +</div></pre> + +<h3 id="Open_state_CSS" name="Open_state_CSS">CSS</h3> + +<pre class="brush:css">/* --------------- */ +/* Required Styles */ +/* --------------- */ + +.select { + position: relative; + display : inline-block; +} + +.select.active, +.select:focus { + box-shadow: 0 0 3px 1px #227755; + outline: none; +} + +.select .optList { + position: absolute; + top : 100%; + left : 0; +} + +.select .optList.hidden { + max-height: 0; + visibility: hidden; +} + +/* ------------ */ +/* Fancy Styles */ +/* ------------ */ + +.select { + font-size : 0.625em; /* 10px */ + font-family : Verdana, Arial, sans-serif; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + padding : 0.1em 2.5em 0.2em 0.5em; /* 1px 25px 2px 5px */ + width : 10em; /* 100px */ + + border : 0.2em solid #000; /* 2px */ + border-radius : 0.4em; /* 4px */ + + box-shadow : 0 0.1em 0.2em rgba(0, 0, 0, .45); /* 0 1px 2px */ + + background : #F0F0F0; + background : -webkit-linear-gradient(90deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); + background : linear-gradient(0deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); +} + +.select .value { + display : inline-block; + width : 100%; + overflow : hidden; + + white-space : nowrap; + text-overflow : ellipsis; + vertical-align: top; +} + +.select:after { + content : "▼"; + position: absolute; + z-index : 1; + height : 100%; + width : 2em; /* 20px */ + top : 0; + right : 0; + + padding-top : .1em; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + text-align : center; + + border-left : .2em solid #000; + border-radius: 0 .1em .1em 0; + + background-color : #000; + color : #FFF; +} + +.select .optList { + z-index : 2; + + list-style: none; + margin : 0; + padding: 0; + + background: #f0f0f0; + border: .2em solid #000; + border-top-width : .1em; + border-radius: 0 0 .4em .4em; + + box-shadow: 0 .2em .4em rgba(0,0,0,.4); + + -moz-box-sizing : border-box; + box-sizing : border-box; + + min-width : 100%; + max-height: 10em; /* 100px */ + overflow-y: auto; + overflow-x: hidden; +} + +.select .option { + padding: .2em .3em; +} + +.select .highlight { + background: #000; + color: #FFF; +}</pre> + +<h3 id="展开状态结果">展开状态结果</h3> + +<div>{{ EmbedLiveSample('Open_state', 120, 130) }}</div> diff --git a/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_2/index.html b/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_2/index.html new file mode 100644 index 0000000000..3a9546631f --- /dev/null +++ b/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_2/index.html @@ -0,0 +1,212 @@ +--- +title: Example 2 +slug: Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_2 +tags: + - HTML + - 表单 +translation_of: Learn/Forms/How_to_build_custom_form_controls/Example_2 +--- +<p>这是解释 <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">如何构建自定义表单小部件</a>的第二个示例。</p> + +<h2 id="JS" name="JS">使用JS</h2> + +<h3 id="HTML_内容">HTML 内容</h3> + +<pre class="brush: html"><form class="no-widget"> + <select name="myFruit"> + <option>Cherry</option> + <option>Lemon</option> + <option>Banana</option> + <option>Strawberry</option> + <option>Apple</option> + </select> + + <div class="select"> + <span class="value">Cherry</span> + <ul class="optList hidden"> + <li class="option">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> + </div> +<form> +</pre> + +<h3 id="CSS_内容">CSS 内容</h3> + +<pre class="brush: css">.widget select, +.no-widget .select { + position : absolute; + left : -5000em; + height : 0; + overflow : hidden; +} + +/* --------------- */ +/* Required Styles */ +/* --------------- */ + +.select { + position: relative; + display : inline-block; +} + +.select.active, +.select:focus { + box-shadow: 0 0 3px 1px #227755; + outline: none; +} + +.select .optList { + position: absolute; + top : 100%; + left : 0; +} + +.select .optList.hidden { + max-height: 0; + visibility: hidden; +} + +/* ------------ */ +/* Fancy Styles */ +/* ------------ */ + +.select { + font-size : 0.625em; /* 10px */ + font-family : Verdana, Arial, sans-serif; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + padding : 0.1em 2.5em 0.2em 0.5em; /* 1px 25px 2px 5px */ + width : 10em; /* 100px */ + + border : 0.2em solid #000; /* 2px */ + border-radius : 0.4em; /* 4px */ + + box-shadow : 0 0.1em 0.2em rgba(0,0,0,.45); /* 0 1px 2px */ + + background : #F0F0F0; + background : -webkit-linear-gradient(90deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); + background : linear-gradient(0deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); +} + +.select .value { + display : inline-block; + width : 100%; + overflow : hidden; + + white-space : nowrap; + text-overflow : ellipsis; + vertical-align: top; +} + +.select:after { + content : "▼"; + position: absolute; + z-index : 1; + height : 100%; + width : 2em; /* 20px */ + top : 0; + right : 0; + + padding-top : .1em; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + text-align : center; + + border-left : .2em solid #000; + border-radius: 0 .1em .1em 0; + + background-color : #000; + color : #FFF; +} + +.select .optList { + z-index : 2; + + list-style: none; + margin : 0; + padding: 0; + + background: #f0f0f0; + border: .2em solid #000; + border-top-width : .1em; + border-radius: 0 0 .4em .4em; + + box-shadow: 0 .2em .4em rgba(0,0,0,.4); + + -moz-box-sizing : border-box; + box-sizing : border-box; + + min-width : 100%; + max-height: 10em; /* 100px */ + overflow-y: auto; + overflow-x: hidden; +} + +.select .option { + padding: .2em .3em; +} + +.select .highlight { + background: #000; + color: #FFFFFF; +}</pre> + +<h3 id="JavaScript_内容">JavaScript 内容</h3> + +<pre class="brush: js">window.addEventListener("load", function () { + var form = document.querySelector('form'); + + form.classList.remove("no-widget"); + form.classList.add("widget"); +});</pre> + +<h3 id="使用JS的结果">使用JS的结果</h3> + +<p>{{ EmbedLiveSample('JS', 120, 130) }}</p> + +<h2 id="No_JS" name="No_JS">不使用JS</h2> + +<h3 id="HTML_内容_2">HTML 内容</h3> + +<pre class="brush: html"><form class="no-widget"> + <select name="myFruit"> + <option>Cherry</option> + <option>Lemon</option> + <option>Banana</option> + <option>Strawberry</option> + <option>Apple</option> + </select> + + <div class="select"> + <span class="value">Cherry</span> + <ul class="optList hidden"> + <li class="option">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> + </div> +<form></pre> + +<h3 id="CSS_内容_2">CSS 内容</h3> + +<pre class="brush: css">.widget select, +.no-widget .select { + position : absolute; + left : -5000em; + height : 0; + overflow : hidden; +}</pre> + +<h3 id="不使用JS的结果">不使用JS的结果</h3> + +<p>{{ EmbedLiveSample('No_JS', 120, 130) }}</p> diff --git a/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_3/index.html b/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_3/index.html new file mode 100644 index 0000000000..a4a58880e4 --- /dev/null +++ b/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_3/index.html @@ -0,0 +1,246 @@ +--- +title: Example 3 +slug: Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_3 +tags: + - HTML + - 表单 +translation_of: Learn/Forms/How_to_build_custom_form_controls/Example_3 +--- +<p>这是解释 <a href="https://developer.mozilla.org/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets">如何构建自定义表单小部件</a> 的第三个示例。</p> + +<h2 id="Change_states" name="Change_states">Change states</h2> + +<h3 id="HTML_内容">HTML 内容</h3> + +<pre class="brush: html"><form class="no-widget"> + <select name="myFruit" tabindex="-1"> + <option>Cherry</option> + <option>Lemon</option> + <option>Banana</option> + <option>Strawberry</option> + <option>Apple</option> + </select> + + <div class="select" tabindex="0"> + <span class="value">Cherry</span> + <ul class="optList hidden"> + <li class="option">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> + </div> +</form></pre> + +<h3 id="CSS_内容">CSS 内容</h3> + +<pre class="brush: css">.widget select, +.no-widget .select { + position : absolute; + left : -5000em; + height : 0; + overflow : hidden; +} + +/* --------------- */ +/* Required Styles */ +/* --------------- */ + +.select { + position: relative; + display : inline-block; +} + +.select.active, +.select:focus { + box-shadow: 0 0 3px 1px #227755; + outline: none; +} + +.select .optList { + position: absolute; + top : 100%; + left : 0; +} + +.select .optList.hidden { + max-height: 0; + visibility: hidden; +} + +/* ------------ */ +/* Fancy Styles */ +/* ------------ */ + +.select { + font-size : 0.625em; /* 10px */ + font-family : Verdana, Arial, sans-serif; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + padding : 0.1em 2.5em 0.2em 0.5em; /* 1px 25px 2px 5px */ + width : 10em; /* 100px */ + + border : 0.2em solid #000; /* 2px */ + border-radius : 0.4em; /* 4px */ + + box-shadow : 0 0.1em 0.2em rgba(0,0,0,.45); /* 0 1px 2px */ + + background : #F0F0F0; + background : -webkit-linear-gradient(90deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); + background : linear-gradient(0deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); +} + +.select .value { + display : inline-block; + width : 100%; + overflow : hidden; + + white-space : nowrap; + text-overflow : ellipsis; + vertical-align: top; +} + +.select:after { + content : "▼"; + position: absolute; + z-index : 1; + height : 100%; + width : 2em; /* 20px */ + top : 0; + right : 0; + + padding-top : .1em; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + text-align : center; + + border-left : .2em solid #000; + border-radius: 0 .1em .1em 0; + + background-color : #000; + color : #FFF; +} + +.select .optList { + z-index : 2; + + list-style: none; + margin : 0; + padding: 0; + + background: #f0f0f0; + border: .2em solid #000; + border-top-width : .1em; + border-radius: 0 0 .4em .4em; + + box-shadow: 0 .2em .4em rgba(0,0,0,.4); + + -moz-box-sizing : border-box; + box-sizing : border-box; + + min-width : 100%; + max-height: 10em; /* 100px */ + overflow-y: auto; + overflow-x: hidden; +} + +.select .option { + padding: .2em .3em; +} + +.select .highlight { + background: #000; + color: #FFFFFF; +}</pre> + +<h3 id="JavaScript_内容">JavaScript 内容</h3> + +<pre class="brush: js">// ------- // +// HELPERS // +// ------- // + +NodeList.prototype.forEach = function (callback) { + Array.prototype.forEach.call(this, callback); +} + +// -------------------- // +// Function definitions // +// -------------------- // + +function deactivateSelect(select) { + if (!select.classList.contains('active')) return; + + var optList = select.querySelector('.optList'); + + optList.classList.add('hidden'); + select.classList.remove('active'); +} + +function activeSelect(select, selectList) { + if (select.classList.contains('active')) return; + + selectList.forEach(deactivateSelect); + select.classList.add('active'); +}; + +function toggleOptList(select, show) { + var optList = select.querySelector('.optList'); + + optList.classList.toggle('hidden'); +} + +function highlightOption(select, option) { + var optionList = select.querySelectorAll('.option'); + + optionList.forEach(function (other) { + other.classList.remove('highlight'); + }); + + option.classList.add('highlight'); +}; + +// ------------- // +// Event binding // +// ------------- // + +window.addEventListener("load", function () { + var form = document.querySelector('form'); + + form.classList.remove("no-widget"); + form.classList.add("widget"); +}); + +window.addEventListener('load', function () { + var selectList = document.querySelectorAll('.select'); + + selectList.forEach(function (select) { + var optionList = select.querySelectorAll('.option'); + + optionList.forEach(function (option) { + option.addEventListener('mouseover', function () { + highlightOption(select, option); + }); + }); + + select.addEventListener('click', function (event) { + toggleOptList(select); + }, false); + + select.addEventListener('focus', function (event) { + activeSelect(select, selectList); + }); + + select.addEventListener('blur', function (event) { + deactivateSelect(select); + }); + }); +});</pre> + +<h3 id="结果">结果</h3> + +<p>{{ EmbedLiveSample('Change_states') }}</p> diff --git a/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_4/index.html b/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_4/index.html new file mode 100644 index 0000000000..472102adb2 --- /dev/null +++ b/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/example_4/index.html @@ -0,0 +1,294 @@ +--- +title: Example 4 +slug: Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_4 +tags: + - HTML + - Web + - 表单 + - 高级 +translation_of: Learn/Forms/How_to_build_custom_form_controls/Example_4 +--- +<p>这是解释 <a href="/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">如何构建自定义表单小部件</a> 的第四个示例。</p> + +<h2 id="Change_states" name="Change_states">改变状态</h2> + +<h3 id="HTML_内容">HTML 内容</h3> + +<pre class="brush: html"><form class="no-widget"> + <select name="myFruit"> + <option>Cherry</option> + <option>Lemon</option> + <option>Banana</option> + <option>Strawberry</option> + <option>Apple</option> + </select> + + <div class="select"> + <span class="value">Cherry</span> + <ul class="optList hidden"> + <li class="option">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> + </div> +</form></pre> + +<h3 id="CSS_内容">CSS 内容</h3> + +<pre class="brush: css">.widget select, +.no-widget .select { + position : absolute; + left : -5000em; + height : 0; + overflow : hidden; +} + +/* --------------- */ +/* Required Styles */ +/* --------------- */ + +.select { + position: relative; + display : inline-block; +} + +.select.active, +.select:focus { + box-shadow: 0 0 3px 1px #227755; + outline: none; +} + +.select .optList { + position: absolute; + top : 100%; + left : 0; +} + +.select .optList.hidden { + max-height: 0; + visibility: hidden; +} + +/* ------------ */ +/* Fancy Styles */ +/* ------------ */ + +.select { + font-size : 0.625em; /* 10px */ + font-family : Verdana, Arial, sans-serif; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + padding : 0.1em 2.5em 0.2em 0.5em; /* 1px 25px 2px 5px */ + width : 10em; /* 100px */ + + border : 0.2em solid #000; /* 2px */ + border-radius : 0.4em; /* 4px */ + + box-shadow : 0 0.1em 0.2em rgba(0,0,0,.45); /* 0 1px 2px */ + + background : #F0F0F0; + background : -webkit-linear-gradient(90deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); + background : linear-gradient(0deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); +} + +.select .value { + display : inline-block; + width : 100%; + overflow : hidden; + + white-space : nowrap; + text-overflow : ellipsis; + vertical-align: top; +} + +.select:after { + content : "▼"; + position: absolute; + z-index : 1; + height : 100%; + width : 2em; /* 20px */ + top : 0; + right : 0; + + padding-top : .1em; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + text-align : center; + + border-left : .2em solid #000; + border-radius: 0 .1em .1em 0; + + background-color : #000; + color : #FFF; +} + +.select .optList { + z-index : 2; + + list-style: none; + margin : 0; + padding: 0; + + background: #f0f0f0; + border: .2em solid #000; + border-top-width : .1em; + border-radius: 0 0 .4em .4em; + + box-shadow: 0 .2em .4em rgba(0,0,0,.4); + + -moz-box-sizing : border-box; + box-sizing : border-box; + + min-width : 100%; + max-height: 10em; /* 100px */ + overflow-y: auto; + overflow-x: hidden; +} + +.select .option { + padding: .2em .3em; +} + +.select .highlight { + background: #000; + color: #FFFFFF; +}</pre> + +<h3 id="JavaScript_内容">JavaScript 内容</h3> + +<pre class="brush: js">// ------- // +// HELPERS // +// ------- // + +NodeList.prototype.forEach = function (callback) { + Array.prototype.forEach.call(this, callback); +} + +// -------------------- // +// Function definitions // +// -------------------- // + +function deactivateSelect(select) { + if (!select.classList.contains('active')) return; + + var optList = select.querySelector('.optList'); + + optList.classList.add('hidden'); + select.classList.remove('active'); +} + +function activeSelect(select, selectList) { + if (select.classList.contains('active')) return; + + selectList.forEach(deactivateSelect); + select.classList.add('active'); +}; + +function toggleOptList(select, show) { + var optList = select.querySelector('.optList'); + + optList.classList.toggle('hidden'); +} + +function highlightOption(select, option) { + var optionList = select.querySelectorAll('.option'); + + optionList.forEach(function (other) { + other.classList.remove('highlight'); + }); + + option.classList.add('highlight'); +}; + +function updateValue(select, index) { + var nativeWidget = select.previousElementSibling; + var value = select.querySelector('.value'); + var optionList = select.querySelectorAll('.option'); + + nativeWidget.selectedIndex = index; + value.innerHTML = optionList[index].innerHTML; + highlightOption(select, optionList[index]); +}; + +function getIndex(select) { + var nativeWidget = select.previousElementSibling; + + return nativeWidget.selectedIndex; +}; + +// ------------- // +// Event binding // +// ------------- // + +window.addEventListener("load", function () { + var form = document.querySelector('form'); + + form.classList.remove("no-widget"); + form.classList.add("widget"); +}); + +window.addEventListener('load', function () { + var selectList = document.querySelectorAll('.select'); + + selectList.forEach(function (select) { + var optionList = select.querySelectorAll('.option'); + + optionList.forEach(function (option) { + option.addEventListener('mouseover', function () { + highlightOption(select, option); + }); + }); + + select.addEventListener('click', function (event) { + toggleOptList(select); + }); + + select.addEventListener('focus', function (event) { + activeSelect(select, selectList); + }); + + select.addEventListener('blur', function (event) { + deactivateSelect(select); + }); + }); +}); + +window.addEventListener('load', function () { + var selectList = document.querySelectorAll('.select'); + + selectList.forEach(function (select) { + var optionList = select.querySelectorAll('.option'), + selectedIndex = getIndex(select); + + select.tabIndex = 0; + select.previousElementSibling.tabIndex = -1; + + updateValue(select, selectedIndex); + + optionList.forEach(function (option, index) { + option.addEventListener('click', function (event) { + updateValue(select, index); + }); + }); + + select.addEventListener('keyup', function (event) { + var length = optionList.length, + index = getIndex(select); + + if (event.keyCode === 40 && index < length - 1) { index++; } + if (event.keyCode === 38 && index > 0) { index--; } + + updateValue(select, index); + }); + }); +});</pre> + +<h3 id="结果">结果</h3> + +<p>{{ EmbedLiveSample('Change_states') }}</p> diff --git a/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/index.html b/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/index.html new file mode 100644 index 0000000000..24636e7858 --- /dev/null +++ b/files/zh-cn/learn/html/forms/how_to_build_custom_form_widgets/index.html @@ -0,0 +1,776 @@ +--- +title: 如何构建表单小工具 +slug: Learn/HTML/Forms/How_to_build_custom_form_widgets +tags: + - HTML + - 例子 + - 表单 + - 高级 +translation_of: Learn/Forms/How_to_build_custom_form_controls +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/Form_validation", "Learn/HTML/Forms/Sending_forms_through_JavaScript", "Learn/HTML/Forms")}}</div> + +<p class="summary">在许多情况下,<a href="/en-US/docs/HTML/Forms/The_native_form_widgets" title="/en-US/docs/HTML/Forms/The_native_form_widgets">可用的 HTML 表单小组件</a><em>是不够的</em>。如果要在某些小部件(例如 {{HTMLElement("select")}}元素)上执行<a href="/en-US/docs/Advanced_styling_for_HTML_forms" title="/en-US/docs/Advanced_styling_for_HTML_forms">高级样式</a>,或者如果要提供自定义表现,则别无选择,只能构建自己的小部件。</p> + +<p>在本文中,我们会看到如何构建这样的组件。为此,我们将使用这样一个例子:重建 {{HTMLElement("select")}}元素。</p> + +<div class="note"> +<p><strong>注意:</strong> 我们将专注于构建小部件,而不是怎样让代码更通用或可复用;那会涉及一些非基础的JavaScript代码和未知环境下的DOM操作,这超过了这篇文章的范围。</p> +</div> + +<h2 id="设计_结构_和语义">设计, 结构, 和语义</h2> + +<p>在构建一个自定义控件之前,首先你要确切的知道你要什么。 这将为您节省宝贵的时间。 特别地,清楚地定义控件的所有状态非常重要。 为了做到这一点,从状态和行为表现都众所周知的现有小控件开始是很好的选择,这样你可以轻松的尽量模仿这些控件。</p> + +<p>在我们的示例中,我们将重建HTML<select>元素,这是我们希望实现的结果:</p> + +<p><img alt="The three states of a select box" src="/files/4481/custom-select.png" style="height: 135px; width: 366px;"></p> + +<p>上面图片显示了我们控件的三个主要状态:正常状态(左); 活动状态(中)和打开状态(右)。</p> + +<p>在行为方面,我们希望我们的控件像任何原生控件一样对鼠标和键盘都可用。 让我们从定义控件如何到达每个状态开始:</p> + +<dl> + <dt>以下情况控件将会呈现正常状态:</dt> + <dd> + <ul> + <li>页面加载</li> + <li>控件处于活动状态,但用户点击控件以外的任何位置</li> + <li>控件是活动状态,但用户使用键盘将焦点移动到另一个小部件</li> + </ul> + + <div class="note"> + <p><strong>注意:</strong> 在页面上移动焦点通常是通过按Tab键来完成的,但这并不是哪都通用的标准。 例如,在Safari中页面上的链接间的循环切换默认下是通过使用<a href="http://www.456bereastreet.com/archive/200906/enabling_keyboard_navigation_in_mac_os_x_web_browsers/">组合键Option + Tab</a>完成的。</p> + </div> + </dd> + <dt>以下情况控件将会呈现活动状态:</dt> + <dd> + <ul> + <li>用户点击</li> + <li>用户按下tab让控件获得了焦点。</li> + <li>控件呈现打开状态然后用户点击控件。</li> + </ul> + </dd> + <dt>以下情况控件将会呈现打开状态:</dt> + <dd> + <ul> + <li>控件在非打开状态时被用户点击。</li> + </ul> + </dd> +</dl> + +<p>我们知道如何改变状态后,定义如何改变小工具的值还很重要:</p> + +<dl> + <dt>以下情况控件的值将会被改变:</dt> + <dd> + <ul> + <li>控件在打开状态下用户点击一个选项</li> + <li>控件在活动状态下用户按下键盘上方向键或者下方向键</li> + </ul> + </dd> +</dl> + +<p>最后,让我们定义控件的选项将要怎么表现:</p> + +<ul> + <li>当控件在打开状态时,被选中的选项将被突出显示</li> + <li>当鼠标悬停在某个选项上时,该选项将被突出显示,并且之前突出显示的选项将返回正常的状态</li> +</ul> + +<p>对于我们的例子的目的,我们将就此结束;但是,如果你是一个认真的读者,你会注意到我们省略了一些东西,例如,你认为用户在小部件处于打开状态时点击tab键会发生什么?答案是:什么也不会发生。好吧,似乎很明显这就是正确的行为,但事实是,因为在我们的规范中没有定义这种情况,我们很容易忽略这种行为。在团队环境中尤其是这样,因为设计小部件行为的人与实现的人通常是不同的。</p> + +<p>另外一个有趣的例子是:当小部件处于打开状态时,用户按下键盘上方向键和下方向键将会发生什么?这个问题有些棘手,如果你认为活动状态和打开状态是完全不同的,那么答案就是“什么都不会发生”,因为我们没有定义任何在打开状态下键盘的交互行为。从另一个方面看,如果你认为活动状态和打开状态是有重叠的部分,那么控件的值可能会改变,但是被选中的选项肯定不会相应的进行突出显示,同样是因为我们没有定义在控件打开状态下的任何键盘交互事件(我们仅仅定义了控件打开会发生什么,而没有定义在其打开后会发生什么)</p> + +<p>在我们的例子中,缺失的规范是显而易见的,所以我们将着手处理他们,但是对于一些没有人想到去定义正确行为的小部件而言,这的确是一个问题。所以在设计阶段花费时间是值得的,因为如果你定义的行为不够好,或者忘记定义了一个行为,那么在用户开始实际使用时,将会很难去重新定义它们。如果你在定义时有疑问,请征询他人的意见,如果你有预算,请不要犹豫的去进行<a href="https://en.wikipedia.org/wiki/Usability_testing">用户可行性测试</a>,这个过程被称为UX design (User Experience <em>Design</em>用户体验设计),如果你想要深入的学习相关的内容,请查阅下面这些有用资源:</p> + +<ul> + <li><a href="http://www.uxmatters.com/" rel="external" title="http://www.uxmatters.com/">UXMatters.com</a></li> + <li><a href="http://uxdesign.com/" rel="external" title="http://uxdesign.com/">UXDesign.com</a></li> + <li><a href="http://uxdesign.smashingmagazine.com/" rel="external" title="http://uxdesign.smashingmagazine.com/">The UX Design section of SmashingMagazine</a></li> +</ul> + +<div class="note"> +<p><strong>注意: </strong>另外, 在绝大多数系统中,还有一种方法能够打开{{HTMLElement("select")}}元素来观察其所有的选项(这和用鼠标点击{{HTMLElement("select")}}元素是一样的)。通过Windows下的Alt + 向下箭头实现,在我们的例子中没有实现---但是这样做会很方便,因为鼠标点击事件就是由该原理实现的。</p> +</div> + +<h3 id="定义语义化的_HTML_结构">定义语义化的 HTML 结构</h3> + +<p>现在控件的基本功能已经决定了,可以开始构建自定义控件了。第一步是要确定 HTML 结构并给予一些基本的语义规则。第一步就是去确定它的HTML结构并给予一些基本的语义。重构{{HTMLElement("select")}}元素需要怎么做如下:</p> + +<pre class="brush: html"><!-- 这是我们小部件的主要容器. + tabindex属性是用来让用户聚焦在小部件上的. + 稍后我们会发现最好通过JavaScript来设定它的值. --> +<div class="select" tabindex="0"> + + <!-- 这个容器用来显示组件现在的值 --> + <span class="value">Cherry</span> + + <!-- 这个容器包含我们的组件的所有可用选项. + 因为他是一个列表,用ul元素是有意义的. --> + <ul class="optList"> + <!-- 每个选项只包含用来显示的值, + 稍后我们会知道如何处理和表单一起发送的真实值 --> + <li class="option">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> + +</div></pre> + +<p>注意类名的使用:不管实际使用了哪种底层HTML元素,它们都标识每个相关的部分。这很重要,因为这样做能确保我们的CSS和JavaScript不会和HTML结构强绑定,这样我们就可以在不破坏使用小部件的代码的情况下进行实现更改。比如,如果你希望增加一个等价的{{HTMLElement("optgroup")}}元素。</p> + +<h3 id="使用_CSS_创建外观">使用 CSS 创建外观</h3> + +<p>现在我们有了控件结构,我们可以开始设计我们的控件了。构建自定义控件的重点是能够完全按照我们的期望设置它的样式。为了达到这个目的,我们将 CSS部分的工作分为两部分:第一部分是让我们的控件表现得像一个{{HTMLElement("select")}}元素所必需的的CSS规则,第二部分包含了让组件看起来像我们所希望那样的精妙样式。</p> + +<h4 id="所需的样式">所需的样式</h4> + +<p>所需的样式是那些用以处理我们组件的三种状态的必须样式。</p> + +<pre class="brush: css">.select { + /* 这将为选项列表创建一个上下文定位 */ + position: relative; + + /* 这将使我们的组件成为文本流的一部分,同时又可以调整大小 */ + display : inline-block; +}</pre> + +<p>我们需要一个额外的类 <code>active</code> 来定义我们的组件处于其激活状态时的的界面外观。因为我们的组件是可以聚焦的, 我们通过{{cssxref(":focus")}} 伪类重复自定义样式来确保它们表现得一样。</p> + +<pre class="brush: css">.select .active, +.select:focus { + outline: none; + + /* 这里的 box-shadow 属性并非必须,但确保活动状态能看出来非常重要---我们 + 将其作为一个默认值,你可以随意地覆盖掉它. */ + box-shadow: 0 0 3px 1px #227755; +}</pre> + +<p>现在,让我们处理选项列表:</p> + +<pre class="brush: css">/* 这里的 .select 选择器是一个糖衣语法,用来确保我们定义的类是 + 在我们的组件里的那个。 */ +.select .optList { + /* 这可以确保我们的选项列表将会显示在值的下面,并且会处在 + HTML 流之外*/ + position : absolute; + top : 100%; + left : 0; +}</pre> + +<p>我们需要一个额外的类来处理选项列表隐藏时的情况。为了管理没有完全匹配的活动状态和打开状态之间的差异,这是有必要的。</p> + +<pre class="brush: css">.select .optList.hidden { + /* 这是一个以可访问形式隐藏列表的简单方法, + 对可访问性我们将在最后进一步拓展 */ + max-height: 0; + visibility: hidden; +}</pre> + +<h4 id="美化">美化</h4> + +<p>所以现在我们的基本功能已经就位,有趣的事情就可以开始了。下面是一个可行的简单的例子,和本文开头的截图是相对应的。不管怎样,你可以随意的体验一下看看能收获什么。</p> + +<pre class="brush: css">.select { + /* 出于可访问性方面的原因,所有尺寸都会由em值表示 + (用来确保用户在文本模式下使用浏览器缩放时组件的可缩放性). + 在大多数浏览器下的默认换算是1em == 16px. + 如果你对em和px的转换感到疑惑, 请参考http://riddle.pl/emcalc/ */ + font-size : 0.625em; /* 这个(=10px)是以em方式表达的这个环境里的字体大小 */ + font-family : Verdana, Arial, sans-serif; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + /* 我们需要为将要添加的向下箭头准备一些额外的空间 */ + padding : .1em 2.5em .2em .5em; /* 1px 25px 2px 5px */ + width : 10em; /* 100px */ + + border : .2em solid #000; /* 2px */ + border-radius : .4em; /* 4px */ + box-shadow : 0 .1em .2em rgba(0,0,0,.45); /* 0 1px 2px */ + + /* 第一段声明是为了不支持线性梯度填充的浏览器准备的。 + 第二段声明是因为基于WebKit的浏览器没有预先定义它。 + 如果你想为过时的浏览器提供支持, 请参阅 http://www.colorzilla.com/gradient-editor/ */ + background : #F0F0F0; + background : -webkit-linear-gradient(90deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); + background : linear-gradient(0deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); +} + +.select .value { + /* 因为值的宽度可能超过组件的宽度,我们需要确保他不会改变组件的宽度 */ + display : inline-block; + width : 100%; + overflow : hidden; + + vertical-align: top; + + /* 如果内容溢出了, 最好有一个恰当的缩写. */ + white-space : nowrap; + text-overflow: ellipsis; +}</pre> + +<p>我们不需要一个额外的元素来设计向下的箭头,而使用{{cssxref(":after")}} 伪类来替代。然而,这也可以通过使用一张加在<code>select</code> class上的简单的背景图像来实现。</p> + +<pre class="brush: css">.select:after { + content : "▼"; /* 我们使用了unicode 编码的字符 U+25BC; 参阅 http://www.utf8-chartable.de */ + position: absolute; + z-index : 1; /* 这对于防止箭头覆盖选项列表很重要 */ + top : 0; + right : 0; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + height : 100%; + width : 2em; /* 20px */ + padding-top : .1em; /* 1px */ + + border-left : .2em solid #000; /* 2px */ + border-radius: 0 .1em .1em 0; /* 0 1px 1px 0 */ + + background-color : #000; + color : #FFF; + text-align : center; +}</pre> + +<p>接下来,让我们定义选项列表的样式。</p> + +<pre class="brush: css">.select .optList { + z-index : 2; /* 我们明确的表示选项列表会始终与向下箭头重叠 */ + + /* 这会重置ul元素的默认样式 */ + list-style: none; + margin : 0; + padding: 0; + + -moz-box-sizing : border-box; + box-sizing : border-box; + + /* 这会确保即使数值比组件小,选项列表仍能变得跟组件自身一样大*/ + min-width : 100%; + + /* 万一列表太长了, 它的内容会从垂直方向溢出(会自动添加一个竖向滚动条) + 但是水平方向不会(因为我们没有设定宽度, 列表会自适应宽度. 如果不能的话,内容会被截断) */ + max-height: 10em; /* 100px */ + overflow-y: auto; + overflow-x: hidden; + + border: .2em solid #000; /* 2px */ + border-top-width : .1em; /* 1px */ + border-radius: 0 0 .4em .4em; /* 0 0 4px 4px */ + + box-shadow: 0 .2em .4em rgba(0,0,0,.4); /* 0 2px 4px */ + background: #f0f0f0; +}</pre> + +<p>对于选项,我们需要添加一个 <code>highlight</code> 类以便能标明用户将要选择的值或者已经选择的值。</p> + +<pre class="brush: css">.select .option { + padding: .2em .3em; /* 2px 3px */ +} + +.select .highlight { + background: #000; + color: #FFFFFF; +}</pre> + +<p>这是三种状态的结果:</p> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">基本状态</th> + <th scope="col" style="text-align: center;">活动状态</th> + <th scope="col" style="text-align: center;">打开状态</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{EmbedLiveSample("Basic_state",120,130, "", "/Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_1")}}</td> + <td>{{EmbedLiveSample("Active_state",120,130, "", "/Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_1")}}</td> + <td>{{EmbedLiveSample("Open_state",120,130, "", "/Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_1")}}</td> + </tr> + <tr> + <td colspan="3" style="text-align: center;"><a href="/zh-CN/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_1" title="/zh-CN/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_1">Check out the source code</a></td> + </tr> + </tbody> +</table> + +<h2 id="通过JavaScript让您的小部件动起来">通过JavaScript让您的小部件动起来</h2> + +<p>现在我们的设计和结构已经完成了。我们可以写些JavaScript代码来让这个部件真正生效。</p> + +<div class="warning"> +<p><strong>警告:</strong>下面的代码仅仅是教学性质的,并且不应该照搬使用。在许多方面,正如我们所看到的,这种方案不具有前瞻性,而且可能在旧浏览器上会不工作。这里面还有冗余的部分,在生产环境下,代码需要优化。</p> +</div> + +<div class="note"> +<p><strong>注意:</strong>创建可复用的组件可能是一件需要些技巧的事情。<a href="http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html" rel="external" title="http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html">W3C 网络组件草案</a> 是对这类特定问题的答案之一。<a href="http://x-tags.org/" rel="external" title="http://x-tags.org/">X-Tag 项目 </a>是对这一规格的实验性实现;我们建议你看看它。</p> +</div> + +<h3 id="它为什么不生效?">它为什么不生效?</h3> + +<p>在我们开始之前,要记住一件和 JavaScript 有关的非常重要的事情:在浏览器中,<strong>这是一种不可靠的技术。</strong>当你构建一个自定义组件时,你会不得不得依赖于<strong> </strong>JavaScript,因为这是将所有的东西联系在一起的线索。但是,很多情况下,JavaScript 不能在浏览器中运行。</p> + +<ul> + <li>用户关掉了 JavaScript: 这是最不常见的情形。现在只有很少的人会关掉 JavaScript。</li> + <li>脚本没有加载。这是最常见的情形,特别是在移动端上,在那些网络非常不可靠的地方。</li> + <li>脚本是有问题的。你应该总是考虑这种可能性。</li> + <li>脚本和第三方脚本冲突。这可能会由用户使用的跟踪脚本和一些书签工具引发。</li> + <li>脚本与一个浏览器的拓展冲突,或者受其影响。 (比如 Firefox 的 <a href="https://addons.mozilla.org/fr/firefox/addon/noscript/" rel="external" title="https://addons.mozilla.org/fr/firefox/addon/noscript/">NoScript</a> 拓展 或者 Chrome 的 <a href="https://chrome.google.com/webstore/detail/notscripts/odjhifogjcknibkahlpidmdajjpkkcfn" rel="external" title="https://chrome.google.com/webstore/detail/notscripts/odjhifogjcknibkahlpidmdajjpkkcfn">NotScripts</a> 拓展)。</li> + <li>用户在使用老旧的浏览器,而且你需要的一些功能没有被支持。当你使用一些最新的 API 时,这种情况会经常发生。</li> +</ul> + +<p>因为这些风险,认真考虑 JavaScript 不生效时会发生什么是很重要的。处理这个问题的细节超出了这篇文章的范围,因为这与你有多么想使你的脚本具有通用性和可复用性更加相关,不过我们将在我们的例子中考虑与其相关的基本内容。</p> + +<p>在我们的例子中,如果JavaScript代码没有运行,我们会回退到显示一个标准的 {{HTMLElement("select")}} 元素。为了实现这一点,我们需要两样东西。</p> + +<p>首先,在每次使用我们的自定义部件前,我们需要添加一个标准的 {{HTMLElement("select")}} 元素。实际上,为了能将来自我们自定义的表单组件和以及其他部分的表单数据发送出去,这个元素也是需要的。我们随后会详细的解释这一点。</p> + +<pre class="brush: html"><body class="no-widget"> + <form> + <select name="myFruit"> + <option>Cherry</option> + <option>Lemon</option> + <option>Banana</option> + <option>Strawberry</option> + <option>Apple</option> + </select> + + <div class="select"> + <span class="value">Cherry</span> + <ul class="optList hidden"> + <li class="option">Cherry</li> + <li class="option">Lemon</li> + <li class="option">Banana</li> + <li class="option">Strawberry</li> + <li class="option">Apple</li> + </ul> + </div> + </form> + +</body></pre> + +<p>第二,我们需要两个新的 classes 来隐藏不需要的元素(即,当我们的脚本没有运行时的自定义组件, 或是脚本正常运行时的"真正的" {{HTMLElement("select")}} 元素)。注意默认情况下,我们的 HTML 代码会隐藏我们的自定义组件。</p> + +<pre class="brush: css">.widget select, +.no-widget .select { + /* 这个CSS选择器大体上说的是: + - 要么我们将body的class设置为"widget",隐藏真实的{{HTMLElement("select")}}元素 + - 或是我们没有改变body的class,这样body的class还是"no-widget", + 因此class为"select"的元素需要被隐藏 */ + position : absolute; + left : -5000em; + height : 0; + overflow : hidden; +}</pre> + +<p>接下来我们需要一个 JavaScript 开关来决定脚本是否运行。这个开关非常简单:如果页面加载时,我们的脚本运行了,它将会移除 <code>no-widget</code> class ,并添加 <code>widget</code> class,由此切换 {{HTMLElement("select")}} 元素和自定义组件的可视性。</p> + +<pre class="brush: js">window.addEventListener("load", function () { + document.body.classList.remove("no-widget"); + document.body.classList.add("widget"); +});</pre> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">无 JS</th> + <th scope="col" style="text-align: center;">有 JS</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{EmbedLiveSample("No_JS",120,130, "", "/Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_2")}}</td> + <td>{{EmbedLiveSample("JS",120,130, "", "/Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_2")}}</td> + </tr> + <tr> + <td colspan="2" style="text-align: center;"><a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_2" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_2">Check out the source code</a></td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>注意:</strong> 如果你真的想让你的代码变得通用和可重用,最好不要做一个 class 选择器开关,而是通过添加一个组件 class 的方式来隐藏{{HTMLElement("select")}} 元素,并且动态地在每一个{{HTMLElement("select")}} 元素后面添加代表页面中自定义组件的 DOM 树。</p> +</div> + +<h3 id="让工作变得更简单">让工作变得更简单</h3> + +<p>在我们将要构建的代码之中,我们将会使用标准的 DOM API 来完成我们所要做的所有工作。尽管 DOM API 在浏览器中得到了更好支持,但是在旧的浏览器上还是会出现问题。( 特别是非常老的 Internet Explorer)。</p> + +<p>如果你想要避免旧浏览器带来的麻烦,这儿有两种解决方案:使用专门的框架,比如 <a href="http://jquery.com/" rel="external" title="http://jquery.com/">jQuery</a>, <a href="https://github.com/julienw/dollardom" rel="external" title="https://github.com/julienw/dollardom">$dom</a>, <a href="http://prototypejs.org/" rel="external" title="http://prototypejs.org/">prototype</a>, <a href="http://dojotoolkit.org/" rel="external" title="http://dojotoolkit.org/">Dojo</a>, <a href="http://yuilibrary.com/" rel="external" title="http://yuilibrary.com/">YUI</a>, 或者类似的框架,或者通过填充你想使用的缺失的特性 (这可以通过条件加载轻松完成——例如使用 <a href="http://yepnopejs.com/" rel="external" title="http://yepnopejs.com/">yepnope</a> 这样的库。</p> + +<p>我们打算使用的特性如下所示(按照风险程度从高到低排列):</p> + +<ol> + <li>{{domxref("element.classList","classList")}}</li> + <li>{{domxref("EventTarget.addEventListener","addEventListener")}}</li> + <li><code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach" title="/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach">forEach</a></code> (这不是 DOM而是现代 JavaScript )</li> + <li>{{domxref("element.querySelector","querySelector")}} 和 {{domxref("element.querySelectorAll","querySelectorAll")}}</li> +</ol> + +<p>除了那些特定特性的的可用性以外,在开始之前,仍然存在一个问题。由函数{{domxref("element.querySelectorAll","querySelectorAll()")}} 返回的对象是一个{{domxref("NodeList")}} 而不是 <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Array" title="/en-US/docs/JavaScript/Reference/Global_Objects/Array">Array</a></code>。这一点非常重要,因为 <code>Array</code> 对象支持 <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach" title="/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach">forEach</a></code> 函数,但是 {{domxref("NodeList")}} 不支持。由于 {{domxref("NodeList")}} 看起来实在是像一个 <code>Array</code> 并且因为 <code>forEach</code> 是这样的便于使用。我们可以轻易地添加对 {{domxref("NodeList")}}的支持,使我们的生活更轻松一些,像这样:</p> + +<pre class="brush: js">NodeList.prototype.forEach = function (callback) { + Array.prototype.forEach.call(this, callback); +}</pre> + +<p>我们没有开玩笑,这真的很容易实现。</p> + +<h3 id="构造事件回调">构造事件回调</h3> + +<p>基础已经准备好了,我们现在可以开始定义用户每次同我们的组件交互时会用到的所有函数了。</p> + +<pre class="brush: js">// 这个函数会用在每当我们想要停用一个自定义组件的时候 +// 它需要一个参数: +// select :要停用的带有 'select' 类的节点 +function deactivateSelect(select) { + + // 如果组件没有运行,不用进行任何操作 + if (!select.classList.contains('active')) return; + + // 我们需要获取自定义组件的选项列表 + var optList = select.querySelector('.optList'); + + // 关闭选项列表 + optList.classList.add('hidden'); + + // 然后停用组件本身 + select.classList.remove('active'); +} + +// 每当用户想要激活(或停用)这个组件的时候,会调用这个函数 +// 它需要2个参数: +// select : 要激活的带有'select'类的DOM节点 +// selectList : 包含所有带'select'类的DOM节点的列表 +function activeSelect(select, selectList) { + + // 如果组件已经激活了,不进行任何操作 + if (select.classList.contains('active')) return; + + // 我们需要关闭所有自定义组件的活动状态 + // 因为deactiveselect函数满足forEach回调函数的所有请求, + // 我们直接使用它,不使用中间匿名函数 + selectList.forEach(deactivateSelect); + + // 然后我们激活特定的组件 + select.classList.add('active'); +} + +// 每当用户想要打开/关闭选项列表的时候,会调用这个函数 +// 它需要一个参数: +// select : 要触发的列表的DOM节点 +function toggleOptList(select) { + + // 该列表不包含在组件中 + var optList = select.querySelector('.optList'); + + // 我们改变列表的class去显示/隐藏它 + optList.classList.toggle('hidden'); +} + +// 每当我们要高亮一个选项的时候,会调用该函数 +// 它需要两个参数: +// select : 带有'select'类的DOM节点,包含了需要高亮强调的选项 +// option : 需要高亮强调的带有'option'类的DOM节点 +function highlightOption(select, option) { + + // 为我们的自定义select元素获取所有有效选项的列表 + var optionList = select.querySelectorAll('.option'); + + // 我们移除所有选项的高亮强调 + optionList.forEach(function (other) { + other.classList.remove('highlight'); + }); + + // 我们高亮强调正确的选项 + option.classList.add('highlight'); +};</pre> + +<p>这是你需要用来处理组件不同状态的所有代码。</p> + +<p>接下来,我们将这些函数绑定到合适的事件上:</p> + +<pre class="brush: js">// 我们处理文档加载时的事件绑定。 +window.addEventListener('load', function () { + var selectList = document.querySelectorAll('.select'); + + // 每个自定义组件都需要初始化 + selectList.forEach(function (select) { + + // 它的'option'元素也需要 + var optionList = select.querySelectorAll('.option'); + + // 每当用户的鼠标悬停在一个选项上时,我们高亮这个指定的选项 + optionList.forEach(function (option) { + option.addEventListener('mouseover', function () { + // 注意:'select'和'option'变量是我们函数调用范围内有效的闭包 。 + highlightOption(select, option); + }); + }); + + // 每当用户点击一个自定义的select元素时 + select.addEventListener('click', function (event) { + // 注意:'select'变量是我们函数调用范围内有效的闭包。 + + // 我们改变选项列表的可见性 + toggleOptList(select); + }); + + // 如果组件获得了焦点 + // 每当用户点击它或是用tab键访问这个组件时,组件获得焦点 + select.addEventListener('focus', function (event) { + // 注意:'select'和'selectlist'变量是我们函数调用范围内有效的闭包 。 + + // 我们激活这个组件 + activeSelect(select, selectList); + }); + + // 如果组件失去焦点 + select.addEventListener('blur', function (event) { + // 注意:'select'变量是我们函数调用范围内有效的闭包。 + + // 我们关闭这个组件 + deactivateSelect(select); + }); + }); +});</pre> + +<p>此时,我们的组件会根据我们的设计改变状态,但是它的值仍然没有更新。我们接下来会处理这件事。</p> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">Live example</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{EmbedLiveSample("Change_states",120,130, "", "/Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_3")}}</td> + </tr> + <tr> + <td style="text-align: center;"><a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_3" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_3">Check out the source code</a></td> + </tr> + </tbody> +</table> + +<h3 id="处理组件的值">处理组件的值</h3> + +<p>既然我们的组件已经开始工作了,我们必须添加代码,使其能够根据用户的输入更新取值,并且能将取值随表单数据一同发送。</p> + +<p>实现这一点最简单的方法是使用后台原生组件。这样的一个组件会使用浏览器提供的所有内置控件跟踪值,并且在表单提交时,取值也会像往常一样发送。当有现成的功能时,我们再做重复工作就毫无意义了。</p> + +<p>像前面所看到的那样,出于可访问性的原因,我们已经使用了一个原生的选择组件作为后备显示内容;我们可轻松的将它的值与我们的自定义组件之间的值同步。</p> + +<pre class="brush: js">// 这个函数更新显示的值并将其通过原生组件同步 +// 它需要2个参数: +// select : 含有要更新的值的'select'类的DOM节点 +// index : 要被选择的值的索引 +function updateValue(select, index) { + // 我们需要为了给定的自定义组件获取原生组件 + // 在我们的例子中, 原生组件是自定义组件的‘同胞’ + var nativeWidget = select.previousElementSibling; + + // 我们也需要得到自定义组件的值占位符, + var value = select.querySelector('.value'); + + // 还有整个选项列表。 + var optionList = select.querySelectorAll('.option'); + + // 我们将被选择的索引设定为我们的选择的索引 + nativeWidget.selectedIndex = index; + + // 更新相应的值占位符 + value.innerHTML = optionList[index].innerHTML; + + // 然后高亮我们自定义组件里对应的选项 + highlightOption(select, optionList[index]); +}; + +// 这个函数返回原生组件里当前选定的索引 +// 它需要1个参数: +// select : 跟原生组件有关的'select'类DOM节点 +function getIndex(select) { + // 我们需要为了给定的自定义组件访问原生组件 + // 在我们的例子中, 原生组件是自定义组件的一个“同胞” + var nativeWidget = select.previousElementSibling; + + return nativeWidget.selectedIndex; +};</pre> + +<p>通过这两个函数,我们可以将原生组件绑定到自定义的组件上。</p> + +<pre class="brush: js">// 我们在文档加载时处理事件的绑定。 +window.addEventListener('load', function () { + var selectList = document.querySelectorAll('.select'); + + // 每个自定义组件都需要初始化 + selectList.forEach(function (select) { + var optionList = select.querySelectorAll('.option'), + selectedIndex = getIndex(select); + + // 使我们的自定义组件可以获得焦点 + select.tabIndex = 0; + + // 我们让原生组件无法获得焦点 + select.previousElementSibling.tabIndex = -1; + + // 确保默认选中的值正确显示 + updateValue(select, selectedIndex); + + // 每当用户点击一个选项的时候,更新相应的值 + optionList.forEach(function (option, index) { + option.addEventListener('click', function (event) { + updateValue(select, index); + }); + }); + + // 每当用户在获得焦点的组件上用键盘操作时,更新相应的值 + select.addEventListener('keyup', function (event) { + var length = optionList.length, + index = getIndex(select); + + // 当用户点击向下箭头时,跳转到下一个选项 + if (event.keyCode === 40 && index < length - 1) { index++; } + + // 当用户点击向上箭头时,跳转到上一个选项 + if (event.keyCode === 38 && index > 0) { index--; } + + updateValue(select, index); + }); + }); +});</pre> + +<p>在上面的代码里,值得注意的是 <code><a href="/en-US/docs/Web/API/HTMLElement/tabIndex" title="/en-US/docs/Web/API/HTMLElement/tabIndex">tabIndex</a></code> 属性的使用。使用这个属性是很有必要的,这可以确保原生组件将永远不会获得焦点,而且还可以确保当用户用户使用键盘和鼠标时,我们的自定义组件能够获得焦点。</p> + +<p>做完上面这些后,我们就完成了!下面是结果:</p> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">Live example</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{EmbedLiveSample("Change_states",120,130, "", "/Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_4")}}</td> + </tr> + <tr> + <td style="text-align: center;"><a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_4" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_4">Check out the source code</a></td> + </tr> + </tbody> +</table> + +<p>但是等等,我们真的做完了嘛?</p> + +<h2 id="使其具有可访问性">使其具有可访问性</h2> + +<p>我们构建了一个能够生效的东西,尽管这离一个特性齐全的选择框还差得远,但是它效果不错。但是我们已经完成的事情只不过是摆弄DOM。这个组件并没有真正的语义,即使它看起来像一个选择框,但是从浏览器的角度来看并不是,所以辅助技术并不能明白这是一个选择框。简单来说,这个全新的选择框并不具备可访问性!</p> + +<p>幸运的是,有一种解决方案叫做 <a href="/en-US/docs/Accessibility/ARIA" title="/en-US/docs/Accessibility/ARIA">ARIA</a>。ARIA代表"无障碍富互联网应用"。这是一个专为我们现在做的事情设计的<a href="http://www.w3.org/TR/wai-aria/" rel="external" title="http://www.w3.org/TR/wai-aria/"> W3C 规范</a>:使网络应用和自定义组件易于访问,它本质上是一组用来拓展 HTML 的属性集,以便我们能够更好的描述角色,状态和属性,就像我们刚才设计的元素是是它试图传递的原生元素一样。使用这些属性非常简单,所以让我们来试试看。</p> + +<h3 id="role_属性"> <code>role</code> 属性</h3> + +<p><a href="/en-US/docs/Accessibility/ARIA" title="/en-US/docs/Accessibility/ARIA">ARIA</a> 使用的关键属性是 <a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques"><code>role</code></a> 属性。<a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques"><code>role</code></a> 属性接受一个值,该值定义了一个元素的用途。每一个 role 定义了它自己的需求和行为。在我们的例子中,我们会使用 <code><a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_listbox_role" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_listbox_role">listbox</a></code> 这一 role。这是一个 "合成角色",表示具有该role的元素应该有子元素,每个子元素都有特定的角色。(在这个案例中,至少有一个具有<code>option</code> 角色的子元素)。</p> + +<p>同样值得注意的是,ARIA定义了默认应用于标准 HTML 标记的角色。例如,{{HTMLElement("table")}} 元素与角色 <code>grid</code> 相匹配,而 {{HTMLElement("ul")}} 元素与角色 <code>list</code> 相匹配。由于我们使用了一个 {{HTMLElement("ul")}} 元素,我们想要确保我们组件的 <code>listbox</code> 角色能替代 {{HTMLElement("ul")}} 元素的<code>list</code> 角色。为此,我们会使用角色 <code>presentation</code>。这个角色被设计成让我们来表示一个元素没有特殊的含义,并且仅仅用于提供信息。我们会将其应用到{{HTMLElement("ul")}} 元素上。</p> + +<p>为了支持 <code><a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_listbox_role" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_listbox_role">listbox</a></code> 角色,我们只需要将我们 HTML 改成这样:</p> + +<pre class="brush: html"><!-- 我们把role="listbox" 属性添加到我们的顶部元素 --> +<div class="select" role="listbox"> + <span class="value">Cherry</span> + <!-- 我们也把 role="presentation" 添加到ul元素中 --> + <ul class="optList" role="presentation"> + <!-- 然后把role="option" 属性添加到所有li元素里 --> + <li role="option" class="option">Cherry</li> + <li role="option" class="option">Lemon</li> + <li role="option" class="option">Banana</li> + <li role="option" class="option">Strawberry</li> + <li role="option" class="option">Apple</li> + </ul> +</div></pre> + +<div class="note"> +<p><strong>注意:</strong>只有当你想要为不支持 <a href="/en-US/docs/CSS/Attribute_selectors" title="/en-US/docs/CSS/Attribute_selectors">CSS 属性选择器的</a>旧浏览器提供支持时,才有必要同时包含 <code>role</code> 属性和一个<code>class</code> 属性。</p> +</div> + +<h3 id="aria-selected_属性"> <code>aria-selected</code> 属性</h3> + +<p>仅仅使用 <a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques"><code>role</code></a> 属性是不够的。 <a href="/en-US/docs/Accessibility/ARIA" title="/en-US/docs/Accessibility/ARIA">ARIA</a> 还提供了许多状态和属性的内部特征。你能更好更充分的利用它们,你的组件就会能够被辅助技术更好的理解。在我们的例子中,我们会把使用限制在一个属性上:<code>aria-selected</code>。</p> + +<p><code>aria-selected</code> 属性被用来标记当前被选中的选项;这可以让辅助技术告知用户当前的选项是什么。我们会通过 JavaScript 动态地使用该属性,每当用户选择一个选项时标记选中的选项。为了达到这一目的,我们需要修正我们的 <code>updateValue()</code> 函数:</p> + +<pre class="brush: js">function updateValue(select, index) { + var nativeWidget = select.previousElementSibling; + var value = select.querySelector('.value'); + var optionList = select.querySelectorAll('.option'); + + // 我们确保所有的选项都没有被选中 + optionList.forEach(function (other) { + other.setAttribute('aria-selected', 'false'); + }); + + // 我们确保选定的选项被选中了 + optionList[index].setAttribute('aria-selected', 'true'); + + nativeWidget.selectedIndex = index; + value.innerHTML = optionList[index].innerHTML; + highlightOption(select, optionList[index]); +};</pre> + +<p>这是经过所有的改变之后的最终结果。 ( 藉由 <a href="http://www.nvda-project.org/" rel="external" title="http://www.nvda-project.org/">NVDA</a> or <a href="http://www.apple.com/accessibility/voiceover/" rel="external" title="http://www.apple.com/accessibility/voiceover/">VoiceOver</a> 这样的辅助技术尝试它,你会对此有更好的体会):</p> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">在线示例</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{EmbedLiveSample("Change_states",120,130, "", "/Learn/HTML/Forms/How_to_build_custom_form_widgets/Example_5")}}</td> + </tr> + <tr> + <td style="text-align: center;"><a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_5" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets/Example_5">Check out the final source code</a></td> + </tr> + </tbody> +</table> + +<h2 id="总结">总结</h2> + +<p>我们已经了解了所有和构建一个自定义表单组件相关的基础知识,但是如你所见做这件事非常繁琐,并且通常情况下依赖第三方库,而不是自己从头写起会更容易 ,也更好(当然,除非你的目的就是构建一个这样的库)。</p> + +<p>这儿有一些库,在你编写自己的之前应该了解一下:</p> + +<ul> + <li><a href="http://jqueryui.com/" rel="external" title="http://jqueryui.com/">jQuery UI</a></li> + <li><a href="https://github.com/marghoobsuleman/ms-Dropdown" rel="external" title="https://github.com/marghoobsuleman/ms-Dropdown">msDropDown</a></li> + <li><a href="http://www.emblematiq.com/lab/niceforms/" rel="external" title="http://www.emblematiq.com/lab/niceforms/">Nice Forms</a></li> + <li><a href="https://www.google.fr/search?q=HTML+custom+form+controls&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:fr:official&client=firefox-a" rel="external" title="https://www.google.fr/search?q=HTML+custom+form+controls&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:fr:official&client=firefox-a">And many more…</a></li> +</ul> + +<p>如果你想更进一步, 本例中的代码需要一些改进,才能变得更加通用和可重用。这是一个你可以尝试去做的练习。这里有两个提示可以帮到你:我们所有函数的第一个参数是相同的,这意味着这些函数需要相同的上下文。构建一个对象来共享那些上下文是更聪明的做法。还有,你需要让它的特性适用性更好;也就是说,它要能在一系列对Web标准的兼容性不同的浏览器上工作良好。祝愉快!</p> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/Form_validation", "Learn/HTML/Forms/Sending_forms_through_JavaScript", "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> diff --git a/files/zh-cn/learn/html/forms/how_to_structure_an_html_form/index.html b/files/zh-cn/learn/html/forms/how_to_structure_an_html_form/index.html new file mode 100644 index 0000000000..eda4b201da --- /dev/null +++ b/files/zh-cn/learn/html/forms/how_to_structure_an_html_form/index.html @@ -0,0 +1,290 @@ +--- +title: 如何构造HTML表单 +slug: Learn/HTML/Forms/How_to_structure_an_HTML_form +translation_of: Learn/Forms/How_to_structure_a_web_form +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Forms/Your_first_HTML_form", "Learn/HTML/Forms/The_native_form_widgets", "Learn/HTML/Forms")}}</div> + +<p class="summary">有了基础知识,我们现在更详细地了解了用于为表单的不同部分提供结构和意义的元素。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提条件:</th> + <td>基本的计算机能力, 和基本的 <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML">对HTML的理解</a>。</td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>要理解如何构造HTML表单并赋予它们语义,以便它们是可用的和可访问的。</td> + </tr> + </tbody> +</table> + +<p>HTML表单的灵活性使它们成为HTML中最复杂的结构之一;您可以使用专用的表单元素和属性构建任何类型的基本表单。在构建HTML表单时使用正确的结构将有助于确保表单可用性和可访问性。</p> + +<h2 id="<form>_元素"> <form> 元素</h2> + +<p> {{HTMLElement("form")}} 元素按照一定的格式定义了表单和确定表单行为的属性。当您想要创建一个HTML表单时,都必须从这个元素开始,然后把所有内容都放在里面。许多辅助技术或浏览器插件可以发现{{HTMLElement("form")}}元素并实现特殊的钩子,使它们更易于使用。 </p> + +<p>我们早在之前的文章中就遇见过它了。</p> + +<div class="note"><strong>注意:</strong> 严格禁止在一个表单内嵌套另一个表单。嵌套会使表单的行为不可预知,而这取决于正在使用的浏览器。</div> + +<p>请注意,在{{HTMLElement("form")}}元素之外使用表单小部件是可以的,但是如果您这样做了,那么表单小部件与任何表单都没有任何关系。这样的小部件可以在表单之外使用,但是您应该对于这些小部件有特别的计划,因为它们自己什么也不做。您将不得不使用JavaScript定制他们的行为。</p> + +<div class="note"> +<p><strong>注意</strong>: HTML5在HTML表单元素中引入<code>form</code>属性。它让您显式地将元素与表单绑定在一起,即使元素不在{{ HTMLElement("form") }}中。不幸的是,就目前而言,跨浏览器对这个特性的实现还不足以使用。</p> +</div> + +<h2 id="<fieldset>_和_<legend>_元素"> <fieldset> 和 <legend> 元素</h2> + +<p>{{HTMLElement("fieldset")}}元素是一种方便的用于创建具有相同目的的小部件组的方式,出于样式和语义目的。 你可以在<code><fieldset></code>开口标签后加上一个 {{HTMLElement("legend")}}元素来给{{HTMLElement("fieldset")}} 标上标签。 {{HTMLElement("legend")}}的文本内容正式地描述了{{HTMLElement("fieldset")}}里所含有部件的用途。</p> + +<p>许多辅助技术将使用{{HTMLElement("legend")}} 元素,就好像它是相应的 {{HTMLElement("fieldset")}} 元素里每个部件的标签的一部分。例如,在说出每个小部件的标签之前,像<a href="http://www.freedomscientific.com/products/fs/jaws-product-page.asp" rel="external" title="http://www.freedomscientific.com/products/fs/jaws-product-page.asp">Jaws</a>或<a href="http://www.nvda-project.org/" rel="external" title="http://www.nvda-project.org/">NVDA</a>这样的屏幕阅读器会朗读出legend的内容。</p> + +<p>这里有一个小例子:</p> + +<pre class="brush:html;"><form> + <fieldset> + <legend>Fruit juice size</legend> + <p> + <input type="radio" name="size" id="size_1" value="small"> + <label for="size_1">Small</label> + </p> + <p> + <input type="radio" name="size" id="size_2" value="medium"> + <label for="size_2">Medium</label> + </p> + <p> + <input type="radio" name="size" id="size_3" value="large"> + <label for="size_3">Large</label> + </p> + </fieldset> +</form></pre> + +<div class="note"> +<p><strong>注意</strong>: 你可以在 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/fieldset-legend.html">fieldset-legend.html</a> (你也可以看<a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/fieldset-legend.html">预览版</a>) 看到该例。</p> +</div> + +<p>当阅读上述表格时,屏幕阅读器将会读第一个小部件“Fruit juice size small”,“Fruit juice size medium”为第二个,“Fruit juice size large”为第三个。</p> + +<p>本例中的用例是最重要的。每当您有一组单选按钮时,您应该将它们嵌套在{{HTMLElement("fieldset")}}元素中。还有其他用例,一般来说,{{HTMLElement("fieldset")}}元素也可以用来对表单进行分段。理想情况下,长表单应该在拆分为多个页面,但是如果表单很长,却必须在单个页面上,那么将以不同的关联关系划分的分段,分别放在不同的fieldset里,可以提高可用性。</p> + +<p>因为它对辅助技术的影响, {{HTMLElement("fieldset")}} 元素是构建可访问表单的关键元素之一。无论如何,你有责任不去滥用它。如果可能,每次构建表单时,尝试侦听<a href="https://www.nvaccess.org/download/" title="屏幕阅读器">屏幕阅读器</a>如何解释它。如果听起来很奇怪,试着改进表单结构。</p> + +<h2 id="<label>_元素"> <label> 元素</h2> + +<p>正如我们在前一篇文章中看到的, {{HTMLElement("label")}} 元素是为HTML表单小部件定义标签的正式方法。如果你想构建可访问的表单,这是最重要的元素——当实现的恰当时,屏幕阅读器会连同有关的说明和表单元素的标签一起朗读。以我们在上一篇文章中看到的例子为例:</p> + +<pre class="brush: html"><label for="name">Name:</label> <input type="text" id="name" name="user_name"></pre> + +<p><code><label></code> 标签与 <code><input></code> 通过他们各自的<code>for</code> 属性和 <code>id</code> 属性正确相关联(label的for属性和它对应的小部件的id属性),这样,屏幕阅读器会读出诸如“Name, edit text”之类的东西。</p> + +<p>如果标签没有正确设置,屏幕阅读器只会读出“Edit text blank”之类的东西,这样会没什么帮助。</p> + +<p>注意,一个小部件可以嵌套在它的{{HTMLElement("label")}}元素中,就像这样:</p> + +<pre class="brush: html"><label for="name"> + Name: <input type="text" id="name" name="user_name"> +</label></pre> + +<p>尽管可以这样做,但人们认为设置<code>for</code>属性才是最好的做法,因为一些辅助技术不理解标签和小部件之间的隐式关系。</p> + +<h3 id="标签也可点击!">标签也可点击!</h3> + +<p>正确设置标签的另一个好处是可以在所有浏览器中单击标签来激活相应的小部件。这对于像文本输入这样的例子很有用,这样你可以通过点击标签,和点击输入区效果一样,来聚焦于它,这对于单选按钮和复选框尤其有用——这种控件的可点击区域可能非常小,设置标签来使它们可点击区域变大是非常有用的。</p> + +<p>举个例子:</p> + +<pre class="brush:html;"><form> + <p> + <label for="taste_1">I like cherry</label> + <input type="checkbox" id="taste_1" name="taste_cherry" value="1"> + </p> + <p> + <label for="taste_2">I like banana</label> + <input type="checkbox" id="taste_2" name="taste_banana" value="2"> + </p> +</form></pre> + +<div class="note"> +<p><strong>注意</strong>: 你可以在 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/checkbox-label.html">checkbox-label.html</a> (你也可以看<a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/checkbox-label.html">预览版</a>) 看到该例。</p> +</div> + +<h3 id="多个标签">多个标签</h3> + +<p>严格地说,您可以在一个小部件上放置多个标签,但是这不是一个好主意,因为一些辅助技术可能难以处理它们。在多个标签的情况下,您应该将一个小部件和它的标签嵌套在一个{{HTMLElement("label")}}元素中。</p> + +<p>让我们考虑下面这个例子:</p> + +<pre class="brush: html"><p>Required fields are followed by <abbr title="required">*</abbr>.</p> + +<!--这样写:--> +<div> + <label for="username">Name:</label> + <input type="text" name="username"> + <label for="username"><abbr title="required">*</abbr></label> +</div> + +<!--但是这样写会更好:--> +<div> + <label for="username"> + <span>Name:</span> + <input id="username" type="text" name="username"> + <abbr title="required">*</abbr> + </label> +</div> + +<!--但最好的可能是这样:--> +<div> + <label for="username">Name: <abbr title="required">*</abbr></label> + <input id="username" type="text" name="username"> +</div></pre> + +<p>顶部的段落定义了所需元素的规则。它必须在开始时确保像屏幕阅读器这样的辅助技术在用户找到必需的元素之前显示或念出它们。这样,他们就知道星号表达的是什么意思了。根据屏幕阅读器的设置,屏幕阅读器会把星号读为“star”或“required”,取决于屏幕阅读器的设置——不管怎样,要念出来的都会在第一段清楚的呈现出来。</p> + +<ul> + <li>在第一个例子中,标签根本没有和<code>input</code>一起被念出来——读出来的只是“edit the blank”,和单独被念出的标签。多个<code><label></code>元素会使屏幕阅读器迷惑。</li> + <li>在第二个例子中,事情变得清晰一点了——标签和输入一起,读出的是“name star name edit text”,但标签仍然是单独读出的。这还是有点令人困惑,但这次还是稍微好一点了,因为<code>input</code>和<code>label</code>联系起来了。</li> + <li>第三个例子是最好的——标签是一起读出的,标签和输入读出的是“name star edit text”。</li> +</ul> + +<div class="note"> +<p><strong>注意</strong>:你可能会得到一些不同的结果,这取决于你的屏幕阅读器。这是在VoiceOver上测试的(NVDA的行为也类似)。我们也乐于听听你的试验结果。</p> +</div> + +<div class="note"> +<p><strong>注意</strong>: 你可以在 GitHub 上看到 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/required-labels.html">required-labels.html</a> (你也可以看<a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/required-labels.html">预览版</a>)。不要运行2个或3个未注释版本的示例—— 如果您有多个标签和多个输入相同的ID,那么屏幕阅读器肯定会感到困惑!</p> +</div> + +<h2 id="用于表单的通用HTML结构">用于表单的通用HTML结构</h2> + +<p>除了特定于HTML表单的结构之外,还应该记住表单同样是HTML。这意味着您可以使用HTML的所有强大功能来构造一个HTML表单。</p> + +<p>正如您在示例中可以看到的,用{{HTMLElement("div")}}元素包装标签和它的小部件是很常见的做法。{{HTMLElement("p")}}元素也经常被使用,HTML列表也是如此(后者在构造多个复选框或单选按钮时最为常见)。</p> + +<p>除了{{HTMLElement("fieldset")}}元素之外,使用HTML标题(例如,{{htmlelement("h1")}}、{{htmlelement("h2")}})和分段(如{{htmlelement("section")}})来构造一个复杂的表单也是一种常见的做法。</p> + +<p>最重要的是,你要找到一种你觉得很舒服的风格去码代码,而且它也能带来可访问的、可用的形式。</p> + +<p>它包含了从功能上划分开并分别包含在{{htmlelement("section")}}元素中的部分,以及一个{{htmlelement("fieldset")}}来包含单选按钮。</p> + +<h3 id="自主学习构建一个表单结构">自主学习:构建一个表单结构</h3> + +<p>让我们把这些想法付诸实践,建立一个稍微复杂一点的表单结构——一个支付表单。这个表单将包含许多您可能还不了解的小部件类型—现在不要担心这个;在下一篇文章(<a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">原生表单小部件</a>)中,您将了解它们是如何工作的。现在,当您遵循下面的指令时,请仔细阅读这些描述,并开始理解我们使用的包装器元素是如何构造表单的,以及为什么这么做。</p> + +<ol> + <li>在开始之前,在计算机上的一个新目录中,创建一个<a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">空白模板文件</a>和<a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/payment-form.css">我们的支付表单的CSS样式</a>的本地副本。</li> + <li>首先,通过添加下面这行代码到你的HTML{{htmlelement("head")}}使你的HTML应用CSS。 + <pre class="brush: html"><link href="payment-form.css" rel="stylesheet"></pre> + </li> + <li>接下来,通过添加外部{{htmlelement("form")}}元素来开始一张表单: + <pre class="brush: html"><form> + +</form></pre> + </li> + <li>在 <code><form></code> 标签内,以添加一个标题和段落开始,告诉用户必需的字段是如何标记的: + <pre class="brush: html"><h1>Payment form</h1> +<p>Required fields are followed by <strong><abbr title="required">*</abbr></strong>.</p></pre> + </li> + <li>接下来,我们将在表单中添加一个更大的代码段,在我们之前的代码下面。在这里,您将看到,我们正在将联系人信息字段包装在一个单独的{{htmlelement("section")}}元素中。此外,我们有一组两个单选按钮,每个单选按钮都放在自己的列表中({{htmlelement("li")}}))元素。最后,我们有两个标准文本{{htmlelement("input")}}和它们相关的{{htmlelement("label")}}元素,每个元素包含在{{htmlelement("p")}}中,加上输入密码的密码输入。现在将这些代码添加到您的表单中: + <pre><section> + <h2>Contact information</h2> + <fieldset> + <legend>Title</legend> + <ul> + <li> + <label for="title_1"> + <input type="radio" id="title_1" name="title" value="K" > + King + </label> + </li> + <li> + <label for="title_2"> + <input type="radio" id="title_2" name="title" value="Q"> + Queen + </label> + </li> + <li> + <label for="title_3"> + <input type="radio" id="title_3" name="title" value="J"> + Joker + </label> + </li> + </ul> + </fieldset> + <p> + <label for="name"> + <span>Name: </span> + <strong><abbr title="required">*</abbr></strong> + </label> + <input type="text" id="name" name="username"> + </p> + <p> + <label for="mail"> + <span>E-mail: </span> + <strong><abbr title="required">*</abbr></strong> + </label> + <input type="email" id="mail" name="usermail"> + </p> + <p> + <label for="pwd"> + <span>Password: </span> + <strong><abbr title="required">*</abbr></strong> + </label> + <input type="password" id="pwd" name="password"> + </p> +</section></pre> + </li> + <li>现在,我们将转到表单的第二个<code><section></code>——支付信息。在这里,我们有三个不同的小部件以及它们的标签,每个都包含在一个<code><p></code>中。第一个是选择信用卡类型的下拉菜单({{htmlelement("select")}})。第二个是输入一个信用卡号的类型编号的 <code><input></code> 元素。最后一个是输入<code>date</code>类型的<code><input></code> 元素,用来输入卡片的过期日期(这将在支持的浏览器中出现一个日期选择器小部件,并在非支持的浏览器中回退到普通的文本输入)。同样,在之前的代码后面输入以下内容: + <pre class="brush: html"><section> + <h2>Payment information</h2> + <p> + <label for="card"> + <span>Card type:</span> + </label> + <select id="card" name="usercard"> + <option value="visa">Visa</option> + <option value="mc">Mastercard</option> + <option value="amex">American Express</option> + </select> + </p> + <p> + <label for="number"> + <span>Card number:</span> + <strong><abbr title="required">*</abbr></strong> + </label> + <input type="number" id="number" name="cardnumber"> + </p> + <p> + <label for="date"> + <span>Expiration date:</span> + <strong><abbr title="required">*</abbr></strong> + <em>formatted as mm/yy</em> + </label> + <input type="date" id="date" name="expiration"> + </p> +</section></pre> + </li> + <li>我们要添加的最后一个部分要简单得多,它只包含了一个<code>submit</code>类型的 {{htmlelement("button")}} ,用于提交表单数据。现在把这个添加到你的表单的底部: + <pre class="brush: html"><p> <button type="submit">Validate the payment</button> </p></pre> + </li> +</ol> + +<p>您可以在下面看到已完成的表单 (你可以在Github上看到<a href="https://github.com/mdn/learning-area/blob/master/html/forms/html-form-structure/payment-form.html">源码</a>和<a href="https://mdn.github.io/learning-area/html/forms/html-form-structure/payment-form.html">预览版</a>):</p> + +<p>{{EmbedLiveSample("A_payment_form","100%",620, "", "Learn/HTML/Forms/How_to_structure_an_HTML_form/Example")}}</p> + +<h2 id="总结">总结</h2> + +<p>现在,您已经具备了正确地构造HTML表单所需的所有知识;下一篇文章将深入介绍各种不同类型的表单小部件,您将希望从用户那里收集信息。</p> + +<h2 id="另见">另见</h2> + +<ul> + <li><a href="http://www.alistapart.com/articles/sensibleforms/" rel="external" title="http://www.alistapart.com/articles/sensibleforms/">A List Apart: <em>Sensible Forms: A Form Usability Checklist</em></a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/Your_first_HTML_form", "Learn/HTML/Forms/The_native_form_widgets", "Learn/HTML/Forms")}}</p> diff --git a/files/zh-cn/learn/html/forms/html_forms_in_legacy_browsers/index.html b/files/zh-cn/learn/html/forms/html_forms_in_legacy_browsers/index.html new file mode 100644 index 0000000000..d6045e0d70 --- /dev/null +++ b/files/zh-cn/learn/html/forms/html_forms_in_legacy_browsers/index.html @@ -0,0 +1,215 @@ +--- +title: 旧式浏览器中的HTML 表单 +slug: Learn/HTML/Forms/HTML_forms_in_legacy_browsers +translation_of: Learn/Forms/HTML_forms_in_legacy_browsers +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/Sending_forms_through_JavaScript", "Learn/HTML/Forms/Styling_HTML_forms", "Learn/HTML/Forms")}}</div> + +<p class="summary">所有 web 开发者很快就会(有时候是痛苦地)发现网络是一个令人不快的地方。我们碰到的最恶毒的诅咒是旧式浏览器。好吧,让我们承认吧,当我们提到 “旧式浏览器” 时,脑海中出现就是 老版本的 Internet Explorer ……但是,这远远不是全部。只发布一年的 Firefox 比如 <a href="http://www.mozilla.org/en-US/firefox/organizations/" title="http://www.mozilla.org/en-US/firefox/organizations/">the ESR version</a> 也是旧式浏览器。那么,在移动世界呢?当浏览器和 OS(操作系统) 都不能更新时?是的,有非常多老版本的 Android 手机或 iPhone 没有更新到最新的浏览器。它们同样是旧式浏览器。</p> + +<p>可悲的是,处理这些传统浏览器的问题是工作的一部分。幸运的是,有一些技巧可以帮助您解决旧式浏览器导致的大约80%的问题。</p> + +<h2 id="了解这些问题">了解这些问题</h2> + +<p>实际上,最重要的事情是阅读那些浏览器的文档,并尝试理解通用的(解决)模式。例如,在许多情况下,HTML表单是否支持CSS是最大的问题。这是正确的开始,只需要检查你想用的元素或接口是否支持CSS即可。MDN有一个关于包含HTML中可用的元素、属性或API的兼容表单可查。 此外,仍有其他一些非常有用的资源:</p> + +<h3 id="浏览器厂商的文档">浏览器厂商的文档</h3> + +<ul> + <li>Mozilla: 直接查看MDN即可</li> + <li>Microsoft: <a href="http://msdn.microsoft.com/en-us/library/ff410218%28v=vs.85%29.aspx" rel="external" title="http://msdn.microsoft.com/en-us/library/ff410218%28v=vs.85%29.aspx">Internet Explorer Standards Support Documentation</a></li> + <li>WebKit: 由于有多个版本的引擎,稍微有点棘手. + <ul> + <li><a href="https://www.webkit.org/blog/" rel="external" title="https://www.webkit.org/blog/">The WebKit blog</a> 和 <a href="http://planet.webkit.org/" rel="external" title="http://planet.webkit.org/">Planet WebKit</a> 聚合了Webki核心开发者的最佳文章.</li> + <li><a href="https://www.chromestatus.com/features" title="http://www.chromium.org/developers/web-platform-status">Chrome platform status site</a> 也十分重要</li> + <li>同样重要的是 <a href="https://developer.apple.com/technologies/safari/" rel="external" title="https://developer.apple.com/technologies/safari/">the Apple web site.</a></li> + </ul> + </li> +</ul> + +<h3 id="独立文档">独立文档</h3> + +<ul> + <li><a href="http://caniuse.com" rel="external" title="http://caniuse.com">Can I Use</a> 有关于是否支持最新技术的信息.</li> + <li><a href="http://www.quirksmode.org" rel="external" title="http://www.quirksmode.org">Quirks Mode</a> 是关于浏览器兼容性的精彩资源. <a href="http://www.quirksmode.org/mobile/" rel="external" title="http://www.quirksmode.org/mobile/">mobile部分</a>是当前最好的内容之一.</li> + <li><a href="http://positioniseverything.net/" rel="external" title="http://positioniseverything.net/">Position Is Everything</a> 关于旧式浏览器渲染bug以及解决办法(如果有)的最佳资源.</li> + <li><a href="http://mobilehtml5.org" rel="external" title="http://mobilehtml5.org">Mobile HTML5</a> 有关于大量手机浏览器的兼容性信息,而不仅仅是是前五名(包括诺基亚,亚马逊和黑莓).</li> +</ul> + +<h2 id="让事情变得更简单">让事情变得更简单</h2> + +<p>由于<a href="/en-US/docs/HTML/Forms" title="/en-US/docs/HTML/Forms">HTML forms</a> 包含复杂的交互,所以有一条法则: <a href="http://en.wikipedia.org/wiki/KISS_principle" rel="external" title="http://en.wikipedia.org/wiki/KISS_principle">keep it as simple as possible</a>。很多时候,我们想让表单更美观或想使用更高级的技术,然而,构建高效的HTML表单不只是设计和技术问题。记得花时间读一下这篇文章t <a href="http://www.uxforthemasses.com/forms-usability/" rel="external" title="http://www.uxforthemasses.com/forms-usability/">forms usability on UX For The Masses</a>.</p> + +<h3 id="优雅地降级(Graceful_degradation)是web开发者最好的朋友">优雅地降级(Graceful degradation)是web开发者最好的朋友</h3> + +<p><a href="http://www.sitepoint.com/progressive-enhancement-graceful-degradation-choice/" rel="external" title="http://www.sitepoint.com/progressive-enhancement-graceful-degradation-choice/">Graceful degradation and progressive enhancement</a> 是一个开发模式,它允许你通过同时支持多种浏览器来构建优秀内容。当你为现代浏览器构建内容时,你想确保它能在旧式浏览器中以某种方式工作,这就是优雅地降级(graceful degradation).</p> + +<p>让我们看一些关于HTML表单的例子:</p> + +<h4 id="HTML_input_类型">HTML input 类型</h4> + +<p>HTML5引入的新input类型十分酷,因为他们的降级(degrade)是高度可预测的。如果一个浏览器不能理解 {{HTMLElement("input")}}元素的 {{htmlattrxref("type","input")}} 属性, 它将会后退到<code>text</code>一样的行为。</p> + +<pre class="brush: html"><label for="myColor"> + Pick a color + <input type="color" id="myColor" name="color"> +</label></pre> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">Chrome 24</th> + <th scope="col" style="text-align: center;">Firefox 18</th> + </tr> + </thead> + <tbody> + <tr> + <th style="text-align: center;"><img alt="Screen shot of the color input on Chrome for Mac OSX" src="/files/4575/color-fallback-chrome.png" style="height: 35px; width: 139px;"></th> + <th style="text-align: center;"><img alt="Screen shot of the color input on Firefox for Mac OSX" src="/files/4577/color-fallback-firefox.png" style="height: 30px; width: 245px;"></th> + </tr> + </tbody> +</table> + +<h4 id="CSS_属性选择器">CSS 属性选择器</h4> + +<p><a href="/en-US/docs/CSS/Attribute_selectors" title="/en-US/docs/CSS/Attribute_selectors">CSS属性选择器 </a> 在 <a href="/en-US/docs/HTML/Forms" title="/en-US/docs/HTML/Forms">HTML Forms</a> 中十分有用,然而旧式浏览器不支持. 在那种情形下,一般会习惯性使用等价的class:</p> + +<pre class="brush: html"><input type="number" class="number"></pre> + +<pre class="brush: css">input[type=number] { + /* 这在一些浏览器中是不能执行的 */ +} + +input.number { + /* 可以在任何浏览器中执行 */ +}</pre> + +<p>注意下面的写法没有用(由于它是重复的),在某些浏览器中会失败:</p> + +<pre class="brush: css">input[type=number], +input.number { + /* 在某些浏览器中,这可能会失败,因为如果他们不理解其中任何一个选择器,则跳过整个规则 */ +}</pre> + +<h4 id="表单按钮">表单按钮</h4> + +<p>有两种定义HTML表单按钮的方式:</p> + +<ul> + <li>{{HTMLElement("input")}} 元素使用{{htmlattrxref("type","input")}} 属性并设置其值为<code>button</code>, <code>submit</code>, <code>reset</code> or <code>image</code></li> + <li>{{HTMLElement("button")}} 元素</li> +</ul> + +<p>如果你想通过元素选择器在按钮上应用CSS的话,采用 {{HTMLElement("input")}} 元素的方式会让事情变得稍微有点复杂:</p> + +<pre class="brush: html"><input type="button" class="button" value="click me"></pre> + +<pre class="brush: css">input { + /* 此规则关闭了input元素定义的按钮的默认渲染样式 */ + border: 1px solid #CCC; +} + +input.button { + /* 这条规则不会恢复默认渲染*/ + border: none; +} + +input.button { + /* 这条也不会(恢复)! 实际上在浏览器中没有标准方式实现这一目标 */ + border: auto; +}</pre> + +<p>{{HTMLElement("button")}} 元素有两个问题令人困扰:</p> + +<ul> + <li>在某些旧版本的IE浏览器中有bug。当用户点击按钮时,它不是发送{{htmlattrxref("value","button")}}属性中的内容,而是发送 {{HTMLElement("button")}} 的开闭标签之间的HTML内容. 如果我们想发送值时,这是一个问题,例如发送的处理数据依赖于用户点击不同的按钮时.</li> + <li>一些旧浏览器不使用<code>submit</code> 作为 {{htmlattrxref("type","button")}} 属性的默认值, 所以建议总是在{{HTMLElement("button")}} 元素上设置设置 {{htmlattrxref("type","button")}} 属性.</li> +</ul> + +<pre class="brush: html"><!-- 某些情形下,点击按钮将发送 "<em>Do A</em>" 而不是值"A" --> +<button type="submit" name="IWantTo" value="A"> + <em>Do A</em> +</button></pre> + +<p>给予你的工程限制来选择上述任一种解决方案。</p> + +<h3 id="让我们过一遍CSS">让我们过一遍CSS</h3> + +<p>HTML表单和旧式浏览器最大的问题是CSS的兼容性。正如你可以从这篇文章 <a href="/en-US/docs/Property_compatibility_table_for_form_widgets" title="/en-US/docs/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a> 中看到的复杂性, 它非常的困难。即使仍然可以对文本元素(如大小、字体颜色等)进行一些调整,但那样做会有副作用。最好的办法还是不要美化HTML表单小组件。但你仍然可以将样式应用到表单周围的项目上。如果你是一个专业人士,并且你的客户需要那么做,在这种情况下,你可以研究一些硬技能,如 <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">rebuilding widgets with JavaScript</a>。但在那种情况下,最好还是毫不犹豫的<a href="http://www.smashingmagazine.com/2011/11/03/but-the-client-wants-ie-6-support/" rel="external" title="http://www.smashingmagazine.com/2011/11/03/but-the-client-wants-ie-6-support/">让客户收回这些愚蠢的决定</a>。</p> + +<h2 id="功能检测和模拟(polyfills)">功能检测和模拟(polyfills)</h2> + +<p>尽管JavaScript在现代浏览中是非常棒的技术,但在旧式浏览器中可能存在很多的问题。</p> + +<h3 id="Unobtrusive_JavaScript">Unobtrusive JavaScript</h3> + +<p>API的兼容性是最大的问题。由于这个原因,与"不引人注意的(unobtrusive)" JavaScript一起工作被认为是最佳实践(译者注:此处意思是说没有/忽略JS或JS出了问题也能工作)。这个开发模式定义了两个需求:</p> + +<ul> + <li>结构和行为之间的严格隔离</li> + <li>如果代码出错,内容和基本功能必须保持可访问和可用状态</li> +</ul> + +<p><a href="http://docs.webplatform.org/wiki/concepts/programming/the_principles_of_unobtrusive_javascript" rel="external" title="http://docs.webplatform.org/wiki/concepts/programming/the_principles_of_unobtrusive_javascript">The principles of unobtrusive JavaScript</a> (最早是由Peter-Paul Koch为 Dev.Opera.com 所撰写,现在已转移到 Docs.WebPlatform.org) 同样阐述了上述观点。</p> + +<h3 id="Modernizr_库">Modernizr 库</h3> + +<p>有很多情形,好的"polyfill"能通过提供缺少的API以提供帮助。一个 <a href="http://remysharp.com/2010/10/08/what-is-a-polyfill/" rel="external" title="http://remysharp.com/2010/10/08/what-is-a-polyfill/">polyfill</a> 是一些JavaScript(脚本) 用于填补旧式浏览器中的功能缺失。虽然它们可以用来改进对任何功能的支持,并且使用它们Nederland风险小于CSS和HTML,然而,JS仍然会在很多情况下不工作(网络问题,脚本冲突等)。但是对于JavaScript,如果你总是记住和unobetructive的Javascript一起工作,不适用polyfill也没什么大不了。</p> + +<p>最好的polyfill缺失API的方式是使用<a href="http://modernizr.com" rel="external" title="http://modernizr.com">Modernizr</a> 库以及它的子项目 <a href="http://yepnopejs.com" rel="external" title="http://yepnopejs.com">YepNope</a>. Modernizr 库允许您测试功能可用性,以便采取相应的行动。YepNope 是一个条件加载库。</p> + +<p>下面是一个例子:</p> + +<pre class="brush: js">Modernizr.load({ + // 这会测试您的浏览器是否支持HTML5表单验证API + test : Modernizr.formvalidation, + + // 如果浏览器不支持它,则会加载以下polyfill + nope : form-validation-API-polyfill.js, + + // 无论如何,你的核心App文件依赖于该API被加载 + both : app.js, + + // 一旦加载了这两个文件,就会调用该函数来初始化应用程序 + complete : function () { + app.init(); + } +});</pre> + +<p>Modernizr 团队按照惯例维护着<a href="https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills" rel="external" title="https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills">a list of great polyfills</a>。仅仅按需使用即可。</p> + +<div class="note"> +<p><strong>Note:</strong> Modernizr还有其他很棒的功能可以帮助您处理unobstructive的JavaScript和优雅的降级技术。请阅读 <a href="http://modernizr.com/docs/" rel="external" title="http://modernizr.com/docs/">Modernizr documentation</a>.</p> +</div> + +<h3 id="注意性能">注意性能</h3> + +<p>尽管像Modernizr这样的脚本对性能非常敏感,但加载200千字节的polyfill仍然会影响程序的性能。这对旧式浏览器来说尤其重要,这些浏览器有处理速度非常慢的JavaScript引擎,让polyfills的执行对于用户来说变得很痛苦。性能本身就是一个主题,但旧式浏览器对它非常敏感:基本上,它们速度慢,需要的poliyfill越多,它们需要处理的JavaScript越多。与现代浏览器相比,它们承受双重负担。使用旧版浏览器测试你的代码,了解它们的实际表现。有时,放弃某些功能会带来更好的用户体验,而不是在所有浏览器中具有完全相同的功能。作为最后提醒,总是优先考虑用户。</p> + +<h2 id="总结">总结</h2> + +<p>正如你所看到的,处理旧式浏览器不仅仅是表单问题。而是一整套技术;但是掌握所有这些技术超出了本文的范围。</p> + +<p>如果你阅读了<a href="/en-US/docs/HTML/Forms" title="/en-US/docs/HTML/Forms">HTML Forms guide</a>中的所有文章,你应该可以放心的使用表单了。如果你想探索新技术,请帮助<a href="/en-US/docs/Project:How_to_help" title="/en-US/docs/Project:How_to_help">improve the guide</a>.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/Sending_forms_through_JavaScript", "Learn/HTML/Forms/Styling_HTML_forms", "Learn/HTML/Forms")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Forms/Your_first_HTML_form">Your first HTML form</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">How to structure an HTML form</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">The native form widgets</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">Sending form data</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Form data validation</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li> + <li>旧式浏览器中的HTML表单使用</li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Styling HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Advanced styling for HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li> +</ul> + +<p> </p> diff --git a/files/zh-cn/learn/html/forms/index.html b/files/zh-cn/learn/html/forms/index.html new file mode 100644 index 0000000000..ad51eafa35 --- /dev/null +++ b/files/zh-cn/learn/html/forms/index.html @@ -0,0 +1,77 @@ +--- +title: HTML表单指南 +slug: Learn/HTML/Forms +tags: + - Forms + - HTML + - NeedsTranslation + - TopicStub +translation_of: Learn/Forms +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">这个模块提供了一系列帮助您掌握HTML表单的文章。HTML表单是与用户交互的强大工具;然而,由于历史和技术上的原因,如何充分发挥它们的潜力并不总是显而易见的。在本指南中,我们将介绍HTML表单的所有方面,从结构到样式,从数据处理到自定义小部件。</p> + +<h2 id="预备知识">预备知识</h2> + +<p>在开始这个模块之前,您至少应该完成我们<a href="/zh-CN/docs/Learn/HTML/Introduction_to_HTML">对HTML的介绍</a>。此时此刻,您应该会发现{{anch("基本指南")}}很容易理解,并且能够使用我们的<a href="/zh-CN/docs/Learn/HTML/Forms/The_native_form_widgets">原生表单小部件</a>指南。</p> + +<p>但是模块的其余部分更高级一些,很容易将表单小部件放在页面上,但是如果不使用高级表单特性、CSS和JavaScript,就不能对它们做太多的工作。因此,在您查看其他部分之前,我们建议您先离开,先学习一些<a href="/zh-CN/docs/Learn/CSS">CSS</a>和<a href="/zh-CN/docs/Learn/JavaScript">JavaScript</a>。</p> + +<div class="note"> +<p><strong>注意:</strong>如果您正在使用一个不能让您创建自己的文件的计算机/平板电脑/其它设备,那么您可以尝试(大多数)在线编码程序中的代码示例,例如<a href="http://jsbin.com/">JSBin</a>或<a href="https://thimble.mozilla.org/">Thimble</a>。</p> +</div> + +<h2 id="基本指南">基本指南</h2> + +<dl> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/Your_first_HTML_form">你的第一个HTML表单</a></dt> + <dd>本系列的第一篇文章提供了您第一次创建HTML表单的经验,包括设计一个简单表单,使用正确的HTML元素实现它,通过CSS添加一些非常简单的样式,以及如何将数据发送到服务器。</dd> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">如何构造HTML表单</a></dt> + <dd>有了基础知识,我们现在更详细地了解了用于为表单的不同部分提供结构和意义的元素。</dd> +</dl> + +<h2 id="什么表单小部件可用">什么表单小部件可用?</h2> + +<dl> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/The_native_form_widgets">原生表单小部件</a></dt> + <dd>现在,我们详细研究了不同表单部件的功能,查看了哪些选项可用于收集不同类型的数据。</dd> +</dl> + +<h2 id="验证和提交表单数据">验证和提交表单数据</h2> + +<dl> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">发送表单数据</a></dt> + <dd>本文讨论当用户提交一个表单时,会发生什么情况——表单数据的去向以及当表单数据到达指定位置时我们如何处理?我们还研究了与发送表单数据相关的一些安全问题。</dd> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/Form_validation">表单数据验证</a></dt> + <dd>发送数据还不够,我们还需要确保数据用户填写表单的格式是正确的,我们需要成功地处理它,而且它不会破坏我们的应用程序。我们还希望帮助用户正确填写表单,在使用应用程序时不要感到沮丧。表单验证帮助我们实现这些目标,本文将告诉您需要了解的内容。</dd> +</dl> + +<h2 id="高级指南">高级指南</h2> + +<dl> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">如何构建自定表单小组件</a></dt> + <dd>在某些情况下,原生表单部件无法提供您需要的东西,例如,由于样式或功能。在这种情况下,您可能需要使用原生HTML构建自己的表单小部件。本文将说明您是如何做到这一点的,以及在实际案例研究中需要注意的事项。</dd> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">通过JavaScript发送表单</a></dt> + <dd>本文将讨论如何使用表单来组装HTTP请求,并通过定制的JavaScript发送它,而不是标准的表单提交。它还研究了为什么要这么做,以及这样做的意义。(请参阅使用FormData对象。)</dd> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">遗留浏览器中的HTML表单</a></dt> + <dd>文章覆盖特性检测等。这应该被重定向到跨浏览器测试模块,因为相同的东西在那里被更好地覆盖。</dd> +</dl> + +<h2 id="表单样式指南">表单样式指南</h2> + +<dl> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/Styling_HTML_forms">HTML表单样式</a></dt> + <dd>本文介绍了使用CSS的样式表单,包括您可能需要了解的基本样式任务的所有基础知识。</dd> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">高级HTML表单样式</a></dt> + <dd>在这里,我们将看到一些更高级的表单样式技术,这些技术需要在处理一些更难以风格的元素时使用。</dd> + <dt><a href="/zh-CN/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">表单部件的属性兼容性表</a></dt> + <dd>这最后一篇文章提供了一个方便的参考,允许您查看哪些CSS属性与哪些表单元素是兼容的。</dd> +</dl> + +<h2 id="另见">另见</h2> + +<ul> + <li><a href="/zh-CN/docs/Web/HTML/Element#Forms">HTML forms element reference</a></li> + <li><a href="/zh-CN/docs/Web/HTML/Element/input">HTML <input> types reference</a></li> +</ul> diff --git a/files/zh-cn/learn/html/forms/property_compatibility_table_for_form_widgets/index.html b/files/zh-cn/learn/html/forms/property_compatibility_table_for_form_widgets/index.html new file mode 100644 index 0000000000..31f8075f5b --- /dev/null +++ b/files/zh-cn/learn/html/forms/property_compatibility_table_for_form_widgets/index.html @@ -0,0 +1,1988 @@ +--- +title: 表单组件兼容性列表 +slug: Learn/HTML/Forms/Property_compatibility_table_for_form_widgets +translation_of: Learn/Forms/Property_compatibility_table_for_form_controls +--- +<div>{{learnsidebar}}{{PreviousMenu("Learn/HTML/Forms/Advanced_styling_for_HTML_forms", "Learn/HTML/Forms")}}</div> + +<p class="summary">下面的兼容性表格尝试总结 HTML 表单的 CSS 支持状况。由于 CSS 和 HTML 表单的复杂性,不能把这些表格当作完善的参考。但是,它们可以让你很好地洞察什么能做什么不能做,这将会对你学习使用有很好地帮助。</p> + +<h2 id="如何阅读表格">如何阅读表格</h2> + +<h3 id="值">值</h3> + +<p>对于每个属性,有四种可能地取值:</p> + +<dl> + <dt>YES</dt> + <dd>此属性具有相当一致的跨浏览器支持。在某些极端情况下,你可能仍然会面临奇怪的副作用。</dd> + <dt>PARTIAL</dt> + <dd>尽管这个属性会生效,你还是会经常面对奇怪的副作用和不一致性。你应该尽力避免这些属性,除非你已经深知那些副作用。</dd> + <dt>NO</dt> + <dd>此属性就是不工作或者表现得非常不一致,所以并不可靠。</dd> + <dt>N.A.</dt> + <dd>此属性对这种类型的组件没有意义。</dd> +</dl> + +<h3 id="渲染">渲染</h3> + +<p>对于每个属性有两种可能的渲染方式:</p> + +<dl> + <dt>N (Normal)</dt> + <dd>表示这个属性会像设置的那样应用。</dd> + <dt>T (Tweaked)</dt> + <dd>表示这个属性需要通过下列的额外规则来使用:</dd> +</dl> + +<pre class="brush: css">* { +/* This turn off the native look and feel on WebKit based browsers */ + -webkit-appearance: none; + +/* This turn off the native look and feel on Gecko based browsers */ + -moz-appearance: none; + +/* This turn off the native look and feel on several different browsers + including Opera, Internet Explorer and Firefox */ + background: none; +}</pre> + +<h2 id="兼容性表格">兼容性表格</h2> + +<h3 id="Global_behaviors">Global behaviors</h3> + +<p>对许多浏览器来说,许多行为在全局范围内都是通用的:</p> + +<dl> + <dt>{{cssxref("border")}}, {{cssxref("background")}}, {{cssxref("border-radius")}}, {{cssxref("height")}}</dt> + <dd>任意属性可能影响组件部分或全部的原生外观。小心使用。</dd> + <dt>{{cssxref("line-height")}}</dt> + <dd>不同浏览器支持不同,避免使用</dd> + <dt>{{cssxref("text-decoration")}}</dt> + <dd>Opera表单不支持</dd> + <dt>{{cssxref("text-overflow")}}</dt> + <dd>Opera, Safari, IE9 表单不支持</dd> + <dt>{{cssxref("text-shadow")}}</dt> + <dd>Opera 和 IE9 不支持</dd> +</dl> + +<h3 id="Text_fields">Text fields</h3> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1][2]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li>WebKit 浏览器 (主要在 Mac OSX and iOS 上) 的搜索域使用原生的样式和行为。因此,需要使用 <code>-webkit-appearance:none</code> 才能将这个属性应用到搜索域上。</li> + <li>在 Windows 7, Internet Explorer 9 不会应用到边框上,除非 <code>background:none</code> 已应用。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1][2]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li>WebKit 浏览器 (主要在 Mac OSX and iOS 上) 的搜索域使用原生的样式和行为。因此,需要使用 <code>-webkit-appearance:none</code> 才能将这个属性应用到搜索域上。</li> + <li>在 Windows 7, Internet Explorer 9 不会应用到边框上,除非 <code>background:none</code> 已应用。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1][2]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li>WebKit 浏览器 (主要在 Mac OSX and iOS 上) 的搜索域使用原生的样式和行为。因此,需要使用 <code>-webkit-appearance:none</code> 才能将这个属性应用到搜索域上。</li> + <li>在 Windows 7, Internet Explorer 9 不会应用到边框上,除非 <code>background:none</code> 已应用。</li> + </ol> + </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}<sup>[1]</sup></th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li>如果 {{cssxref("border-color")}} 属性没有设置,一些基于 WebKit 的浏览器会将 {{cssxref("color")}} 属性应用到边框上,颜色和 {{HTMLElement("textarea")}} 的字体颜色一样。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td>查看有关 {{cssxref("line-height")}} 的注释</td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td>查看有关 Opera 的注释</td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>IE9 只在 {{HTMLElement("textarea")}} 上支持这个属性,而 Opera 只在单行文本域中支持。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li>WebKit 浏览器 (主要在 Mac OSX and iOS 上) 的搜索域使用原生的样式和行为。因此,需要使用 <code>-webkit-appearance:none</code> 才能将这个属性应用到搜索域上。</li> + <li>在 Windows 7上, Internet Explorer 9 不会应用到边框上,除非 <code>background:none</code> 已应用。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1][2]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li>WebKit 浏览器 (主要在 Mac OSX and iOS 上) 的搜索域使用原生的样式和行为。因此,需要使用 <code>-webkit-appearance:none</code> 才能将这个属性应用到搜索域上。</li> + <li>在 Windows 7上, Internet Explorer 9 不会应用到边框上,除非 <code>background:none</code> 已应用。</li> + <li>在 Opera 上,只有当边框明确设定时 {{cssxref("border-radius")}} 属性才会应用</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>IE9 不支持这个属性</li> + </ol> + </td> + </tr> + </tbody> +</table> + +<h3 id="Buttons">Buttons</h3> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li>这个属性不能应用于 Mac OSX or iOS 上基于 WebKit 的浏览器。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li>这个属性不能应用于 Mac OSX or iOS 上基于 WebKit 的浏览器。</li> + </ol> + </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td>查看{{cssxref("line-height")}} 的注意事项。</td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes<sup>[1]</sup></td> + <td> + <ol> + <li>在 Opera 上,只有当边框明确设定时 {{cssxref("border-radius")}} 属性才会应用</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>IE9 不支持这个属性</li> + </ol> + </td> + </tr> + </tbody> +</table> + +<h3 id="Number">Number</h3> + +<p>在实现了 <code>number</code> 组件的浏览器上,并没有一种标准的方式改变数字组件的样式,值得注意的是 Safari 上的数字输入框不在这个范围内。</p> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>在 Opera 上,数字选择器缩小时,可能会隐藏域中内容。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>在 Opera 上,数字选择器缩小时,可能会隐藏域中内容。</li> + </ol> + </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td>查看{{cssxref("line-height")}} 的注意事项。</td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td colspan="1" rowspan="3"> + <p>支持,但浏览器之间的不一致性太多,所以并不可靠。</p> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + </tr> + </tbody> +</table> + +<h3 id="Check_boxes_and_radio_buttons">Check boxes and radio buttons</h3> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td> + <ol> + <li>一些浏览器会添加额外的边缘,另一些会拉伸组件。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td> + <ol> + <li>一些浏览器会添加额外的边缘,另一些会拉伸组件。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + </tbody> +</table> + +<h3 id="Select_boxes_(single_line)">Select boxes (single line)</h3> + +<p>Firefox 不提供任何方式改变 {{HTMLElement("select")}} 元素的下箭头。</p> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>这个属性在 {{HTMLElement("select")}} 元素上一切正常,但不能用于 {{HTMLElement("option")}} 或者 {{HTMLElement("optgroup")}} 元素。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[2]</sup></td> + <td> + <ol> + <li>属性可以应用,但 Mac OSX 上浏览器之间的以不一致的方向显示,所以并不可靠。</li> + <li>这个属性在 {{HTMLElement("select")}} 元素上一切正常,但不能用于 {{HTMLElement("option")}} 或者 {{HTMLElement("optgroup")}} 元素。</li> + </ol> + </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>在 Mac OSX 上, 基于 WebKit 的浏览器 不支持将这个属性用于原生组件。它们和 Opera, 在 {{HTMLElement("option")}} 和 {{HTMLElement("optgroup")}} 元素上根本不支持这个属性。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>在 Mac OSX 上, 基于 WebKit 的浏览器 不支持将这个属性用于原生组件。它们和 Opera, 在 {{HTMLElement("option")}} 和 {{HTMLElement("optgroup")}} 元素上根本不支持这个属性。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>IE9 不支持将这个属性用于 {{HTMLElement("select")}}, {{HTMLElement("option")}}, 和 {{HTMLElement("optgroup")}} 元素;Mac OSX 上基于 WebKit 的浏览器不支持将这个属性应用于 {{HTMLElement("option")}} 和 {{HTMLElement("optgroup")}} 元素。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td> + <ol> + <li>Windows 7 上的 IE9 和 Mac OSX 上基于 WebKit 的浏览器,不支持这个组件上的这个属性。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>只有 Firefox 提供了对这个属性的完全支持。Opera 根本不支持这个属性,而其他浏览器只提供了对 {{HTMLElement("select")}} 元素的支持。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1][2]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1][2]</sup></td> + <td> + <ol> + <li>大部分浏览器仅仅支持将这个属性用于 {{HTMLElement("select")}} 元素。</li> + <li>IE9 不支持这个属性</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1][2]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1][2]</sup></td> + <td> + <ol> + <li>大部分浏览器仅仅支持将这个属性用于 {{HTMLElement("select")}} 元素。</li> + <li>IE9 不支持这个属性</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>大部分浏览器仅仅支持将这个属性用于 {{HTMLElement("select")}} 元素。</li> + </ol> + </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td colspan="1" rowspan="3"> + <ol> + <li>大部分浏览器仅仅支持将这个属性用于 {{HTMLElement("select")}} 元素。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + </tr> + </tbody> +</table> + +<h3 id="Select_boxes_(multiline)">Select boxes (multiline)</h3> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>Opera 在 {{HTMLElement("select")}} 元素上 不支持 {{cssxref("padding-top")}} 和 {{cssxref("padding-bottom")}} 。</li> + </ol> + </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td>查看{{cssxref("line-height")}} 的注意事项。</td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>IE9 在 {{HTMLElement("select")}}, {{HTMLElement("option")}}, 和{{HTMLElement("optgroup")}} 元素上不支持这个属性;Mac OSX 上基于 WebKit 的浏览器在 {{HTMLElement("option")}} 和{{HTMLElement("optgroup")}} 元素上不支持这个属性。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td> + <ol> + <li>Windows 7 上的 IE9 和 Mac OSX 上基于 WebKit 的浏览器,不支持这个组件上的这个属性。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td> + <ol> + <li>只被 Firefox and IE9+ 支持。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>大部分浏览器仅仅支持将这个属性用于 {{HTMLElement("select")}} 元素。</li> + </ol> + </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes<sup>[1]</sup></td> + <td> + <ol> + <li>在 Opera 上,只有当边框明确设定时 {{cssxref("border-radius")}} 属性才会应用</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>IE9 不支持这个属性</li> + </ol> + </td> + </tr> + </tbody> +</table> + +<h3 id="Datalist">Datalist</h3> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + </tbody> +</table> + +<h3 id="File_picker">File picker</h3> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td> + <ol> + <li>支持,但浏览器之间的不一致性太多,所以并不可靠。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>许多浏览器将这个属性应用到选择按钮上。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>它表现的或多或少的像一个组件左侧的边缘。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td> + <ol> + <li>支持,但浏览器之间的不一致性太多,所以并不可靠。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>IE9 不支持这个属性</li> + </ol> + </td> + </tr> + </tbody> +</table> + +<h3 id="Date_pickers">Date pickers</h3> + +<p>许多属性都支持但是浏览器之间的不一致性太多,所以并不可靠。</p> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td> </td> + </tr> + </tbody> +</table> + +<h3 id="Color_pickers">Color pickers</h3> + +<p>There is currently not enough implementation to get realiable behaviors.</p> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li>Opera 将它像一个选择组件一样,以同样的限制处理。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li>Opera 将它像一个选择组件一样,以同样的限制处理。</li> + </ol> + </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td colspan="1" rowspan="3"> + <ol> + <li>支持,但浏览器之间的不一致性太多,所以并不可靠。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + </tr> + </tbody> +</table> + +<h3 id="Meters_and_progress">Meters and progress</h3> + +<p>There is currently not enough implementation to get realiable behaviors.</p> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>当 {{cssxref("padding")}} 属性应用于一个 tweaked 元素时,Chrome 会隐藏 {{HTMLElement("progress")}} 和{{HTMLElement("meter")}} 元素。</li> + </ol> + </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td colspan="1" rowspan="3"> + <ol> + <li>支持,但浏览器之间的不一致性太多,所以并不可靠。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + </tr> + </tbody> +</table> + +<h3 id="Range">Range</h3> + +<p>There is no standard way to change the style of the range grip and Opera has no way to tweak the default rendering of the range widget.</p> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td> + <ol> + <li>Chrome 和 Opera 在组件周围添加了一些额外的空白,而 Windows 7 上的 Opera 则拉伸范围选择器的滑块。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> + <ol> + <li> {{cssxref("padding")}} 属性被运用,但是没有任何的视觉效果。</li> + </ol> + </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td colspan="1" rowspan="3"> + <ol> + <li>支持,但浏览器之间的不一致性太多,所以并不可靠。</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 153, 153); vertical-align: top;">No<sup>[1]</sup></td> + </tr> + </tbody> +</table> + +<h3 id="Image_buttons">Image buttons</h3> + +<table> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col" style="text-align: center;">N</th> + <th scope="col" style="text-align: center;">T</th> + <th scope="col">Note</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" scope="col"><em>CSS box model</em></th> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("width")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("height")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("border")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("margin")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="vertical-align: top;">{{cssxref("padding")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Text and font</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("color")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("font")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("letter-spacing")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-align")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-decoration")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-indent")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-overflow")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-shadow")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("text-transform")}}</th> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td style="text-align: center; vertical-align: top;">N.A.</td> + <td> </td> + </tr> + </tbody> + <tbody> + <tr> + <th colspan="4" scope="col"><em>Border and background</em></th> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("background")}}</th> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td style="text-align: center; background-color: rgb(204, 255, 102); vertical-align: top;">Yes</td> + <td colspan="1"> </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("border-radius")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td colspan="1"> + <ol> + <li>IE9 不支持这个属性</li> + </ol> + </td> + </tr> + <tr> + <th scope="row" style="white-space: nowrap; vertical-align: top;">{{cssxref("box-shadow")}}</th> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td style="text-align: center; background-color: rgb(255, 255, 102); vertical-align: top;">Partial<sup>[1]</sup></td> + <td colspan="1"> + <ol> + <li>IE9 不支持这个属性</li> + </ol> + </td> + </tr> + </tbody> +</table> + +<p>{{PreviousMenu("Learn/HTML/Forms/Advanced_styling_for_HTML_forms", "Learn/HTML/Forms")}}</p> + +<p> </p> + +<h2 id="在本单元中">在本单元中</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Forms/Your_first_HTML_form">Your first HTML form</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">How to structure an HTML form</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets">The native form widgets</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">Sending form data</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Form_validation">Form data validation</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML forms in legacy browsers</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Styling_HTML_forms">Styling HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Advanced styling for HTML forms</a></li> + <li><a href="/en-US/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets</a></li> +</ul> + +<p> </p> diff --git a/files/zh-cn/learn/html/forms/sending_and_retrieving_form_data/index.html b/files/zh-cn/learn/html/forms/sending_and_retrieving_form_data/index.html new file mode 100644 index 0000000000..ed3a4ef0ef --- /dev/null +++ b/files/zh-cn/learn/html/forms/sending_and_retrieving_form_data/index.html @@ -0,0 +1,369 @@ +--- +title: 发送表单数据 +slug: Learn/HTML/Forms/Sending_and_retrieving_form_data +tags: + - HTML + - HTTP + - Web + - request + - 安全 + - 表单 +translation_of: Learn/Forms/Sending_and_retrieving_form_data +--- +<p>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/The_native_form_widgets", "Learn/HTML/Forms/Form_validation", "Learn/HTML/Forms")}}</p> + +<p class="summary">本文将讨论当用户提交表单时发生了什么——数据去了哪,以及当它到达时该如何处理?我们还研究了与发送表单数据相关的一些安全问题。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">预备知识:</th> + <td> + <p>基本计算机素养,对<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML的理解</a>,对<a href="/en-US/docs/Web/HTTP/Basics_of_HTTP">HTTP</a> 和<a href="/en-US/docs/Learn/Server-side/First_steps">服务器端编程</a>的基础知识。</p> + </td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>了解表单数据提交时发生了什么,包括服务器上如何处理数据的基本概念。</td> + </tr> + </tbody> +</table> + +<h2 id="数据都去哪儿了?">数据都去哪儿了?</h2> + +<p>在这里,我们将讨论在提交表单时数据会发生什么。</p> + +<h3 id="客户端服务器体系结构">客户端/服务器体系结构</h3> + +<p>web基于非常基本的客户端/服务器体系结构,可以总结如下:客户端(通常是web浏览器)向服务器发送请求(大多数情况下是<a href="http://httpd.apache.org/" rel="external" title="http://httpd.apache.org/">Apache</a>、<a href="http://nginx.com/" rel="external" title="http://nginx.com/">Nginx</a>、<a href="http://www.iis.net/" rel="external" title="http://www.iis.net/">IIS</a>、<a href="http://tomcat.apache.org/" rel="external" title="http://tomcat.apache.org/">Tomcat</a>等web服务器),使用<a href="/en-US/docs/HTTP" title="/en-US/docs/HTTP">HTTP 协议</a>。服务器使用相同的协议来回答请求。</p> + +<p><img alt="A basic schema of the Web client/server architecture" src="/files/4291/client-server.png" style="display: block; height: 141px; margin: 0px auto; width: 400px;"></p> + +<p>在客户端,HTML表单只不过是一种方便的用户友好的方式,可以配置HTTP请求将数据发送到服务器。这使用户能够提供在HTTP请求中传递的信息。</p> + +<div class="note"> +<p><strong>注意:</strong>为了更好地了解客户端—服务器架构是如何工作的,请阅读我们的<a href="/en-US/docs/Learn/Server-side/First_steps">服务器端网站编程的第一个步骤</a>模块。</p> +</div> + +<h3 id="在客户端定义如何发送数据">在客户端:定义如何发送数据</h3> + +<p>{{HTMLElement("form")}}元素定义了如何发送数据。它的所有属性都是为了让您配置当用户点击提交按钮时发送的请求。两个最重要的属性是{{htmlattrxref("action","form")}}和{{htmlattrxref("method","form")}}。</p> + +<h4 id="htmlattrxref(actionform)_属性"> {{htmlattrxref("action","form")}} 属性</h4> + +<p>这个属性定义了发送数据要去的位置。它的值必须是一个有效的URL。如果没有提供此属性,则数据将被发送到包含这个表单的页面的URL。</p> + +<p>在这个例子中,数据被发送到一个绝对URL —— <code>http://foo.com</code>:</p> + +<pre class="brush: html"><form action="http://foo.com"></pre> + +<p class="brush: html">这里,我们使用相对URL——数据被发送到服务器上的不同URL</p> + +<pre class="brush: html"><form action="/somewhere_else"> +</pre> + +<p class="brush: html">在没有属性的情况下,像下面一样,{{HTMLElement("form")}}数据被发送到表单出现的相同页面上:</p> + +<pre class="brush: html"><form></pre> + +<p class="brush: html">许多较老的页面使用下面的符号表示数据应该被发送到包含表单的相同页面;这是必需的,因为直到HTML5{{htmlattrxref("action", "form")}}属性都需要该符号。现在,这不再需要了。</p> + +<pre class="brush: html"><form action="#"></pre> + +<div class="note"> +<p><strong>注意:</strong>可以指定使用HTTPS(安全HTTP)协议的URL。当您这样做时,数据将与请求的其余部分一起加密,即使表单本身是托管在使用HTTP访问的不安全页面上。另一方面,如果表单是在安全页面上托管的,但是您指定了一个不安全的HTTP URL,它带有{{htmlattrxref("action","form")}}属性,所有的浏览器都会在每次尝试发送数据时向用户显示一个安全警告,因为数据不会被加密。</p> +</div> + +<h4 id="htmlattrxref(methodform)属性"> {{htmlattrxref("method","form")}}属性</h4> + +<p>该属性定义了如何发送数据。<a href="/en-US/docs/HTTP">HTTP协议</a>提供了几种执行请求的方法;HTML表单数据可以通过许多不同的方法进行数据传输,其中最常见的是<code>GET</code>方法和<code>POST</code>方法。</p> + +<p>为了理解这两种方法之间的区别,让我们回过头来看看HTTP是如何工作的。<br> + 每当您想要访问Web上的资源时,浏览器都会向URL发送一个请求。<br> + HTTP请求由两个部分组成:一个包含关于浏览器功能的全局元数据集的头部,和一个包含服务器处理特定请求所需信息的主体。</p> + +<h5 id="GET_方法">GET 方法</h5> + +<p><code>GET</code>方法是浏览器使用的方法,请求服务器返回给定的资源:“嘿,服务器,我想要得到这个资源。”在这种情况下,浏览器发送一个空的主体。由于主体是空的,如果使用该方法发送一个表单,那么发送到服务器的数据将被追加到URL。</p> + +<p>考虑下面这个表单:</p> + +<pre class="brush: html"><form action="http://foo.com" method="get"> + <div> + <label for="say">What greeting do you want to say?</label> + <input name="say" id="say" value="Hi"> + </div> + <div> + <label for="to">Who do you want to say it to?</label> + <input name="to" id="to" value="Mom"> + </div> + <div> + <button>Send my greetings</button> + </div> +</form></pre> + +<p>由于已经使用了<code>GET</code>方法,当你提交表单的时候,您将看到<code>www.foo.com/?say=Hi&to=Mom</code>在浏览器地址栏里。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14685/url-parameters.png" style="display: block; margin: 0 auto;">数据作为一系列的名称/值对被附加到URL。在URL web地址结束之后,我们得到一个问号(<code>?</code>),后面跟着由一个与符号(<code>&</code>)互相分隔开的名称/值对。在本例中,我们将两个数据传递给服务器。</p> + +<ul> + <li><code>say</code>, 它有一个 <code>Hi</code>的值。</li> + <li><code>to</code>, 它有一个 <code>Mom</code>的值。</li> +</ul> + +<p>HTTP请求如下:</p> + +<pre>GET /?say=Hi&to=Mom HTTP/2.0 +Host: foo.com</pre> + +<div class="note"> +<p><strong>注意:</strong>你可以在GitHub 上看到本例子——见 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/get-method.html">get-method.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/sending-form-data/get-method.html">预览版</a>).</p> +</div> + +<h5 id="POST_方法">POST 方法</h5> + +<p><code>POST</code>方法略有不同。这是浏览器在询问响应时使用与服务器通信的方法,该响应考虑了HTTP请求正文中提供的数据:“嘿,服务器,看一下这些数据,然后给我回一个适当的结果。”如果使用该方法发送表单,则将数据追加到HTTP请求的主体中。</p> + +<p>让我们来看一个例子,这是我们在上面的<code>GET</code>部分中所看到的相同的形式,但是使用{{htmlattrxref("method","form")}}属性设置为<code>post</code>。</p> + +<pre class="brush: html"><form action="http://foo.com" method="post"> + <div> + <label for="say">What greeting do you want to say?</label> + <input name="say" id="say" value="Hi"> + </div> + <div> + <label for="to">Who do you want to say it to?</label> + <input name="to" id="to" value="Mom"> + </div> + <div> + <button>Send my greetings</button> + </div> +</form></pre> + +<p>当使用<code>POST</code>方法提交表单时,没有数据会附加到URL,HTTP请求看起来是这样的,而请求主体中包含的数据是这样的:</p> + +<pre>POST / HTTP/2.0 +Host: foo.com +Content-Type: application/x-www-form-urlencoded +Content-Length: 13 + +say=Hi&to=Mom</pre> + +<p><code>Content-Length</code>数据头表示主体的大小,<code>Content-Type</code>数据头表示发送到服务器的资源类型。稍后我们将讨论这些标头。</p> + +<div class="note"> +<p><strong>注意:</strong>你可以在 GitHub 上看到本例—— 见 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/post-method.html">post-method.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/sending-form-data/post-method.html">预览版</a>).</p> +</div> + +<h4 id="查看HTTP请求">查看HTTP请求</h4> + +<p>HTTP请求永远不会显示给用户(如果您想要看到它们,您需要使用诸如<a href="/en-US/docs/Tools/Network_Monitor">Firefox Network Monitor</a>或<a href="https://developers.google.com/chrome-developer-tools/" title="https://developers.google.com/chrome-developer-tools/">Chrome Developer Tools</a>之类的工具)。例如,您的表单数据将显示在Chrome网络选项卡中:</p> + +<ol> + <li>按下 F12</li> + <li>选择 "Network"</li> + <li>选择 "All"</li> + <li>在 "Name" 标签页选择 "foo.com"</li> + <li>选择 "Headers"</li> +</ol> + +<p>你可以获得表单数据,像下图显示的那样</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14691/network-monitor.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>唯一显示给用户的是被调用的URL。正如我们上面提到的,使用<code>GET</code>请求用户将在他们的URL栏中看到数据,但是使用<code>POST</code>请求用户将不会看到。这一点很重要,有两个原因:</p> + +<ol> + <li>如果您需要发送一个密码(或其他敏感数据),永远不要使用<code>GET</code>方法否则数据会在URL栏中显示,这将非常不安全。</li> + <li>如果您需要发送大量的数据,那么<code>POST</code>方法是首选的,因为一些浏览器限制了URL的大小。此外,许多服务器限制它们接受的URL的长度。</li> +</ol> + +<h3 id="在服务器端检索数据">在服务器端:检索数据</h3> + +<p>无论选择哪种HTTP方法,服务器都会接收一个字符串并解析,以便将数据作为键/值对序列获取。您访问这个序列的方式取决于您使用的开发平台以及您可能使用的任何特定框架。您使用的技术也决定了如何处理密钥副本;通常,最近收到的密钥的值是优先的。</p> + +<h4 id="例如:原始PHP">例如:原始PHP</h4> + +<p><a href="http://php.net/">PHP</a>提供了一些全局对象来访问数据。假设您已经使用了<code>POST</code>方法,那么下面的示例将获取数据并将其显示给用户。当然,你对数据的处理取决于你自己。您可以显示它,将它存储到数据库中,通过电子邮件发送它,或者以其他方式处理它。</p> + +<pre class="brush: php"><?php + // The global $_POST variable allows you to access the data sent with the POST method by name + // To access the data sent with the GET method, you can use $_GET + $say = htmlspecialchars($_POST['say']); + $to = htmlspecialchars($_POST['to']); + + echo $say, ' ', $to; +?></pre> + +<p>这个例子显示了一个带有我们发送的数据的页面。您可以在我们的示例<a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/php-example.html">php-example.html</a>中看到这一点——该文件包含与我们之前看到的相同的示例表单,它使用了<code>post</code>的<code>method</code>和<code>php-example.php</code>的<code>action</code>。当提交时,它将表单数据发送到<a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/php-example.php">php-example.php</a>,其中包含了上述代码块中所见的php代码。当执行此代码时,浏览器中的输出是<code>Hi Mom</code>。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14693/php-result.png" style="display: block; margin: 0 auto;"></p> + +<div class="note"> +<p><strong>注意:</strong>当您将本例加载到本地浏览器中时,这个示例将无法工作---浏览器无法解析PHP代码,因此当提交表单时,浏览器只会为您提供下载PHP文件。为了让它生效,您需要通过某种类型的PHP服务器运行这个示例。本地PHP测试的好选择有<a href="https://www.mamp.info/en/downloads/">MAMP</a>(Mac和Windows)和<a href="http://ampps.com/download">AMPPS</a>(Mac、Windows、Linux)。</p> +</div> + +<h4 id="例子:_Python">例子: Python</h4> + +<p>这个例子展示了如何使用Python完成同样的事情——在web页面上显示提交的数据。<br> + 这将使用<a href="http://flask.pocoo.org/">Flask framework</a>来呈现模板、处理表单数据提交等(参见<a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/python-example.py">python-example.py</a>)。</p> + +<pre>from flask import Flask, render_template, request +app = Flask(__name__) + +@app.route('/', methods=['GET', 'POST']) +def form(): + return render_template('form.html') + +@app.route('/hello', methods=['GET', 'POST']) +def hello(): + return render_template('greeting.html', say=request.form['say'], to=request.form['to']) + +if __name__ == "__main__": + app.run()</pre> + +<p>以上代码中引用的两个模板如下:</p> + +<ul> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/templates/form.html">form.html</a>: 与我们在{{anch("The POST method")}}小节中看到的相同的表单,但是将<code>action</code>设置为<code>\{{ url_for('hello') }}</code>。(这是一个<a href="http://jinja.pocoo.org/docs/2.9/">Jinja2</a>模板,它基本上是HTML,但是可以包含对运行包含在花括号中的web服务器的Python代码的调用。<code>url_for('hello')</code>基本上是在“提交表单时重定向到<code>/hello</code>”。</li> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/forms/sending-form-data/templates/greeting.html">greeting.html</a>: 这个模板只包含一行,用于呈现渲染时传递给它的两个数据块。<br> + 这是通过前面所见的<code>hello()</code>函数完成的,该函数在<code>/hello</code>URL被导向时运行。</li> +</ul> + +<div class="note"> +<p><strong>注意:</strong>同样,如果您只是尝试将其直接加载到浏览器中,那么这段代码将无法工作。Python的工作方式与PHP略有不同——要在本地运行此代码,您需要<a href="/en-US/docs/Learn/Server-side/Django/development_environment#Installing_Python_3">安装Python/pip</a>,然后使用<code>pip3 install flask</code>安装Flask。此时,您应该能够使用<code>python3 python-example.py</code>来运行这个示例,然后在浏览器中导航到<code>localhost:5000</code>。</p> +</div> + +<h4 id="其他语言和框架">其他语言和框架</h4> + +<p>还有许多其他的服务器端技术可以用于表单处理,包括<a href="/en-US/docs/" title="/en-US/docs/">Perl</a>、<a href="/en-US/docs/" title="/en-US/docs/">Java</a>、 <a href="http://www.microsoft.com/net" title="http://www.microsoft.com/net">.Net</a>、<a href="/en-US/docs/" title="/en-US/docs/">Ruby</a>等。只挑你最喜欢的用就好。话虽如此,但值得注意的是,直接使用这些技术并不常见,因为这可能很棘手。更常见的是使用许多优秀的框架,这些框架使处理表单变得更容易,例如:</p> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django" rel="external">Django</a> for Python (比<a href="http://flask.pocoo.org/">Flask</a>要重量级一些,但是有更多的工具和选项。)</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs">Express</a> for Node.js</li> + <li><a href="https://laravel.com/">Laravel</a> for PHP</li> + <li><a href="https://rubyonrails.org/" rel="external">Ruby On Rails</a> for Ruby</li> + <li><a href="https://phoenixframework.org/">Phoenix</a> for Elixir</li> +</ul> + +<p>要注意的是,即使使用这些框架,使用表单也不一定很容易。但这比从头开始编写所有功能要简单得多,而且会节省很多时间。</p> + +<div class="note"> +<p><strong>注意:</strong>向您介绍任何服务器端语言或框架超出了本文的范围。如果你想要学习这些它们,上面的链接会给你一些帮助。</p> +</div> + +<h2 id="特殊案例发送文件">特殊案例:发送文件</h2> + +<p>用HTML表单发送文件是一个特殊的例子。文件是二进制数据——或者被认为是这样的——而所有其他数据都是文本数据。由于HTTP是一种文本协议,所以处理二进制数据有特殊的要求。</p> + +<h3 id="htmlattrxref(enctypeform)_属性">{{htmlattrxref("enctype","form")}} 属性</h3> + +<p>该属性允许您指定在提交表单时所生成的请求中的<code>Content-Type</code>的HTTP数据头的值。这个数据头非常重要,因为它告诉服务器正在发送什么样的数据。默认情况下,它的值是<code>application/x-www-form-urlencoded</code>。它的意思是:“这是已编码为URL参数的表单数据。”</p> + +<p>如果你想要发送文件,你需要额外的三个步骤:</p> + +<ul> + <li>将{{htmlattrxref("method","form")}}属性设置为<code>POST</code>,因为文件内容不能放入URL参数中。</li> + <li>将{{htmlattrxref("enctype","form")}}的值设置为<code>multipart/form-data</code>,因为数据将被分成多个部分,每个文件单独占用一个部分,表单正文中包含的文本数据(如果文本也输入到表单中)占用一个部分。</li> + <li>包含一个或多个<a href="/en-US/docs/Learn/HTML/Forms/The_native_form_widgets#File_picker">File picker</a>小部件,允许用户选择将要上传的文件。</li> +</ul> + +<p>例如:</p> + +<pre class="brush: html"><form method="post" enctype="multipart/form-data"> + <div> + <label for="file">Choose a file</label> + <input type="file" id="file" name="myFile"> + </div> + <div> + <button>Send the file</button> + </div> +</form></pre> + +<div class="note"> +<p><strong>注意:</strong>一些浏览器支持{{HTMLElement("input")}}的{{htmlattrxref("multiple","input")}}属性,它允许只用一个 <code><input></code> 元素选择一个以上的文件上传。服务器如何处理这些文件取决于服务器上使用的技术。如前所述,使用框架将使您的生活更轻松。</p> +</div> + +<div class="warning"> +<p><strong>警告:</strong>为了防止滥用,许多服务器配置了文件和HTTP请求的大小限制。在发送文件之前,先检查服务器管理员的权限是很重要的。</p> +</div> + +<h2 id="常见的安全问题">常见的安全问题</h2> + +<p>每次向服务器发送数据时,都需要考虑安全性。到目前为止,HTML表单是最常见的攻击路径(可能发生攻击的地方)。这些问题从来都不是来自HTML表单本身,它们来自于服务器如何处理数据。</p> + +<p>根据你所做的事情,你会遇到一些非常有名的安全问题:</p> + +<h3 id="XSS_和_CSRF">XSS 和 CSRF</h3> + +<p>跨站脚本(XSS)和跨站点请求伪造(CSRF)是常见的攻击类型,它们发生在当您将用户发送的数据显示给这个用户或另一个用户时。</p> + +<p>XSS允许攻击者将客户端脚本注入到其他用户查看的Web页面中。攻击者可以使用跨站点脚本攻击的漏洞来绕过诸如<a href="/en-US/docs/JavaScript/Same_origin_policy_for_JavaScript">同源策略</a>之类的访问控制。这些攻击的影响可能从一个小麻烦到一个重大的安全风险。</p> + +<p>CSRF攻击类似于XSS攻击,因为它们以相同的方式开始攻击——向Web页面中注入客户端脚本——但它们的目标是不同的。CSRF攻击者试图将权限升级到特权用户(比如站点管理员)的级别,以执行他们不应该执行的操作(例如,将数据发送给一个不受信任的用户)。</p> + +<p>XSS攻击利用用户对web站点的信任,而CSRF攻击则利用网站对其用户的信任。</p> + +<p>为了防止这些攻击,您应该始终检查用户发送给服务器的数据(如果需要显示),尽量不要显示用户提供的HTML内容。相反,您应该对用户提供的数据进行处理,这样您就不会逐字地显示它。当今市场上几乎所有的框架都实现了一个最小的过滤器,它可以从任何用户发送的数据中删除HTML{{HTMLElement("script")}}、{{HTMLElement("iframe")}} 和{{HTMLElement("object")}} 元素。这有助于降低风险,但并不一定会消除风险。</p> + +<h3 id="SQL注入">SQL注入</h3> + +<p>SQL 注入是一种试图在目标web站点使用的数据库上执行操作的攻击类型。这通常包括发送一个SQL请求,希望服务器能够执行它(通常发生在应用服务器试图存储由用户发送的数据时)。这实际上是<a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project">攻击网站的主要途径之一</a>。 </p> + +<p>其后果可能是可怕的,从数据丢失到通过使用特权升级控制整个网站基础设施的攻击。这是一个非常严重的威胁,您永远不应该存储用户发送的数据,而不执行一些清理工作(例如,在php/mysql基础设施上使用<code><a href="http://www.php.net/manual/en/function.mysql-real-escape-string.php" rel="external" title="http://www.php.net/manual/en/function.mysql-real-escape-string.php">mysql_real_escape_string()</a></code>。</p> + +<h3 id="HTTP数据头注入和电子邮件注入">HTTP数据头注入和电子邮件注入</h3> + +<p>这种类型的攻击出现在当您的应用程序基于表单上用户的数据输入构建HTTP头部或电子邮件时。这些不会直接损害您的服务器或影响您的用户,但它们会引发一个更深入的问题,例如会话劫持或网络钓鱼攻击。</p> + +<p>这些攻击大多是无声的,并且可以将您的服务器变成<a href="http://en.wikipedia.org/wiki/Zombie_(computer_science)">僵尸</a>。</p> + +<h3 id="偏执永远不要相信你的用户">偏执:永远不要相信你的用户</h3> + +<p>那么,你如何应对这些威胁呢?这是一个远远超出本指南的主题,不过有一些规则需要牢记。最重要的原则是:永远不要相信你的用户,包括你自己;即使是一个值得信赖的用户也可能被劫持。</p> + +<p>所有到达服务器的数据都必须经过检查和消毒。总是这样。没有例外。</p> + +<ul> + <li>远离有潜在危险的字符转义。应该如何谨慎使用的特定字符取决于所使用的数据的上下文和所使用的服务器平台,但是所有的服务器端语言都有相应的功能。</li> + <li>限制输入的数据量,只允许有必要的数据。</li> + <li>沙箱上传文件(将它们存储在不同的服务器上,只允许通过不同的子域访问文件,或者通过完全不同的域名访问文件更好)。</li> +</ul> + +<p>如果你遵循这三条规则,你应该避免很多问题,但是如果你想要得到一个有能力的第三方执行的安全检查,这是一个好主意。不要以为你已经看到了所有可能的问题。</p> + +<div class="note"> +<p><strong>注意:</strong>我们的<a href="/en-US/docs/Learn/Server-side">服务器端</a>学习主题的<a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">网站安全性文章</a>更详细地讨论了上述威胁和潜在的解决方案。</p> +</div> + +<h2 id="结论">结论</h2> + +<p>如您所见,发送表单数据很容易,但要确保应用程序的安全性是很棘手的。请记住,前端开发人员不是应该定义数据安全模型的人。是的,我们将看到,<a href="/en-US/docs/HTML/Forms/Data_form_validation">执行客户端数据验证</a>是可能的,但是服务器不能信任这种验证,因为它无法真正知道客户端到底发生了什么。</p> + +<h2 id="相关链接">相关链接</h2> + +<p>如果您想了解更多关于保护web应用程序的信息,您可以深入了解这些资源:</p> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/First_steps">Server-side website programming first steps</a></li> + <li><a href="https://www.owasp.org/index.php/Main_Page" rel="external" title="https://www.owasp.org/index.php/Main_Page">The Open Web Application Security Project (OWASP)</a></li> + <li><a href="http://shiflett.org/" rel="external" title="http://shiflett.org/">Chris Shiflett's blog about PHP Security</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/The_native_form_widgets", "Learn/HTML/Forms/Form_validation", "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> diff --git a/files/zh-cn/learn/html/forms/sending_forms_through_javascript/index.html b/files/zh-cn/learn/html/forms/sending_forms_through_javascript/index.html new file mode 100644 index 0000000000..8489ff2243 --- /dev/null +++ b/files/zh-cn/learn/html/forms/sending_forms_through_javascript/index.html @@ -0,0 +1,439 @@ +--- +title: 使用 JavaScript 发送表单 +slug: Learn/HTML/Forms/Sending_forms_through_JavaScript +tags: + - HTML + - HTML表单 + - JavaScript + - Web 表单 + - 示例 + - 表单 + - 高级 +translation_of: Learn/Forms/Sending_forms_through_JavaScript +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/HTML/Forms/How_to_build_custom_form_widgets", "Learn/HTML/Forms/HTML_forms_in_legacy_browsers", "Learn/HTML/Forms")}}</div> + +<p class="summary">正如在<a href="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data">前面的文章</a>中讲到的,HTML 表单可以声明式地发送一个 HTTP 请求。 但也可以通过 JavaScript 来为表单准备用于发送的 HTTP 请求。 本文探讨如何做到这一点。</p> + +<h2 id="表单不总是表单">表单不总是表单</h2> + +<p>在<a href="/en-US/docs/Open_Web_apps_and_Web_standards">开放式Web应用程序</a>中,使用 <a href="https://developer.mozilla.org/en-US/docs/HTML/Forms">HTML form</a> 而不是文字表单让人们来填写变得越来越普遍了 — 越来越多的开发人员正致力于控制传输数据。</p> + +<h3 id="获得整体界面的控制">获得整体界面的控制</h3> + +<p>标准的 HTML 表单提交会加载数据要发送到的URL,这意味着浏览器窗口以整页加载进行导航。 可以通过隐藏闪烁和网络滞后来避免整页加载以提供更平滑的体验。</p> + +<p>许多现代用户界面只使用HTML表单来收集用户的输入。 当用户尝试发送数据时,应用程序将在后台采取控制并且异步地传输数据,只更新UI中需要更改的部分。</p> + +<p>异步地发送任何数据被称为 <a href="/zh-CN/docs/AJAX" title="/zh-CN/docs/AJAX">AJAX</a>,它代表 "Asynchronous JavaScript And XML"。</p> + +<h3 id="表单提交和_AJAX_请求之间的区别">表单提交和 AJAX 请求之间的区别?</h3> + +<p>AJAX 技术主要依靠 {{domxref("XMLHttpRequest")}} (XHR) DOM 对象。它可以构造 HTTP 请求、发送它们,并获取请求结果。</p> + +<div class="note"> +<p><strong>注意:</strong> 老旧的 AJAX 技术可能不依赖 {{domxref("XMLHttpRequest")}}。例如 <a href="http://en.wikipedia.org/wiki/JSONP" rel="external">JSONP</a> 加 <a href="https://developer.mozilla.org/en-US/docs/Core_JavaScript_1.5_Reference:Global_Functions:eval"><code>eval()</code></a> 函数。这也行得通,但是有严重的安全问题,不推荐使用它。使用它的唯一原因是为了不支持 {{domxref("XMLHttpRequest")}} 或 <a href="https://developer.mozilla.org/en-US/docs/JSON">JSON</a>的过时浏览器;但是那些浏览器实在是太古老了!<strong>避免使用这种技术。</strong></p> +</div> + +<p>创建之初, {{domxref("XMLHttpRequest")}} 被设计用来将 <a href="/zh-CN/docs/XML" title="/zh-CN/docs/XML">XML</a> 作为传输数据的格式获取和发送。不过,如今 JSON 已经取代了 XML,而且要常用的多,无论这是不是一件好事。</p> + +<p>但是 XML 和 JSON 都不适合对表单数据请求编码。 表单数据(<code>application/x-www-form-urlencoded</code>)由 URL编码的键/值对列表组成。为了传输二进制数据,HTTP请求被重新整合成<code>multipart/form-data</code>形式。</p> + +<p>如果您控制前端(在浏览器中执行的代码)和后端(在服务器上执行的代码),则可以发送JSON / XML并根据需要处理它们。</p> + +<p>但是,如果你想使用第三方服务,没有那么简单。 有些服务只接受表单数据。 也有使用表单数据更简单的情况。 如果数据是键/值对,或是原始二进制数据,以现有的后端工具不需要额外的代码就可以处理它。</p> + +<p>那么如何发送这样的数据呢?</p> + +<h2 id="发送表单数据">发送表单数据</h2> + +<p>一共有三种方式来发送表单数据:包括两种传统的方法和一种利用 {{domxref("XMLHttpRequest/FormData","formData")}}对象的新方法.让我们仔细看一下:</p> + +<h3 id="构建_XMLHttpRequest">构建 XMLHttpRequest</h3> + +<p>{{domxref("XMLHttpRequest")}} 是进行 HTTP 请求的最安全和最可靠的方式。 要使用{{domxref("XMLHttpRequest")}}发送表单数据,请通过对其进行URL编码来准备数据,并遵守表单数据请求的具体细节。</p> + +<div class="note"> +<p><strong>备注:</strong>如果想要了解更多关于 <code>XMLHttpRequest</code> 的知识,你可能会对两篇文章感兴趣:<a href="/zh-CN/docs/AJAX/Getting_Started" title="/zh-CN/docs/AJAX/Getting_Started">An introductory article to AJAX</a> 和更高级点的<a href="/zh-CN/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest" title="/zh-CN/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest">using XMLHttpRequest</a>.</p> +</div> + +<p>让我们重建之前的这个例子:</p> + +<pre class="brush: html"><button type="button" onclick="sendData({test:'ok'})">点击我!</button></pre> + +<p>正如你所看到的,HTML实际上没什么改变。 不过,JavaScript变得截然不同了:</p> + +<pre class="brush: js">function sendData(data) { + var XHR = new XMLHttpRequest(); + var urlEncodedData = ""; + var urlEncodedDataPairs = []; + var name; + + // 将数据对象转换为URL编码的键/值对数组。 + for(name in data) { + urlEncodedDataPairs.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name])); + } + + // 将配对合并为单个字符串,并将所有%编码的空格替换为 + // “+”字符;匹配浏览器表单提交的行为。 + urlEncodedData = urlEncodedDataPairs.join('&').replace(/%20/g, '+'); + + // 定义成功数据提交时发生的情况 + XHR.addEventListener('load', function(event) { + alert('耶! 已发送数据并加载响应。'); + }); + + // 定义错误提示 + XHR.addEventListener('error', function(event) { + alert('哎呀!出问题了。'); + }); + + // 建立我们的请求 + XHR.open('POST', 'https://example.com/cors.php'); + + // 为表单数据POST请求添加所需的HTTP头 + XHR.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + + // 最后,发送我们的数据。 + XHR.send(urlEncodedData); +}</pre> + +<p>在线演示:</p> + +<p>{{EmbedLiveSample("手动构建XMLHttpRequest", "100%", 50)}}</p> + +<div class="note"> +<p><strong>注:</strong> 当你想要往第三方网站传输数据时,使用{{domxref("XMLHttpRequest")}}会受到同源策略的影响。如果你需要执行跨域请求,你需要熟悉一下<a href="/zh-CN/docs/HTTP/Access_control_CORS" title="/zh-CN/docs/HTTP/Access_control_CORS">CORS和HTTP访问控制</a>.</p> +</div> + +<h3 id="使用_XMLHttpRequest_和_the_FormData_object(表单数据对象)">使用 XMLHttpRequest 和 the FormData object(表单数据对象)</h3> + +<p>手动建立一个 HTTP 请求非常困难。 幸运的是,最近的 <a href="http://www.w3.org/TR/XMLHttpRequest/">XMLHttpRequest 规范</a>提供了一种方便简单的方法 — 利用{{domxref("XMLHttpRequest/FormData","FormData")}}对象来处理表单数据请求。</p> + +<p>{{domxref("XMLHttpRequest/FormData","FormData")}} 对象可以用来构建用于传输的表单数据,或是获取表单元素中的数据来管理它的发送方式。 请注意,{{domxref("XMLHttpRequest/FormData","FormData")}} 对象是“只写”的,这意味着您可以更改它们,但不能检索其内容。</p> + +<p>使用这个对象在<a href="/en-US/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects">Using FormData Objects</a>中有详细的介绍,不过这里有两个例子:</p> + +<h4 id="使用一个独立的_FormData_对象">使用一个独立的 FormData 对象</h4> + +<pre class="brush: html"><button type="button" onclick="sendData({test:'ok'})">点我!</button></pre> + +<p>你应该会觉得那个HTML示例很熟悉。</p> + +<pre class="brush: js">function sendData(data) { + var XHR = new XMLHttpRequest(); + var FD = new FormData(); + + // 把我们的数据添加到这个FormData对象中 + for(name in data) { + FD.append(name, data[name]); + } + + // 定义数据成功发送并返回后执行的操作 + XHR.addEventListener('load', function(event) { + alert('Yeah! 已发送数据并加载响应。'); + }); + + // 定义发生错误时执行的操作 + XHR.addEventListener('error', function(event) { + alert('Oops! 出错了。'); + }); + + // 设置请求地址和方法 + XHR.open('POST', 'https://example.com/cors.php'); + + // 发送这个formData对象,HTTP请求头会自动设置 + XHR.send(FD); +}</pre> + +<p>在线演示:</p> + +<p>{{EmbedLiveSample("向FormData对象中手动添加数据", "100%", 50)}}</p> + +<h4 id="使用绑定到表单元素上的_FormData">使用绑定到表单元素上的 FormData</h4> + +<p>你也可以把一个 <code>FormData</code> 对象绑定到一个 {{HTMLElement("form")}} 元素上。这会创建一个代表表单中包含元素的 <code>FormData</code> 。</p> + +<p>这段HTML是典型的情况:</p> + +<pre class="brush: html"><form id="myForm"> + <label for="myName">告诉我你的名字:</label> + <input id="myName" name="name" value="John"> + <input type="submit" value="提交"> +</form></pre> + +<p>但是 JavaScript 接管了这个表单:</p> + +<pre class="brush: js">window.addEventListener("load", function () { + function sendData() { + var XHR = new XMLHttpRequest(); + + // 我们把这个 FormData 和表单元素绑定在一起。 + var FD = new FormData(form); + + // 我们定义了数据成功发送时会发生的事。 + XHR.addEventListener("load", function(event) { + alert(event.target.responseText); + }); + + // 我们定义了失败的情形下会发生的事 + XHR.addEventListener("error", function(event) { + alert('哎呀!出了一些问题。'); + }); + + // 我们设置了我们的请求 + XHR.open("POST", "https://example.com/cors.php"); + + // 发送的数据是由用户在表单中提供的 + XHR.send(FD); + } + + // 我们需要获取表单元素 + var form = document.getElementById("myForm"); + + // ...然后接管表单的提交事件 + form.addEventListener("submit", function (event) { + event.preventDefault(); + + sendData(); + }); +});</pre> + +<p>在线演示:</p> + +<p>{{EmbedLiveSample("使用绑定到表单元素上的_FormData", "100%", 50)}}</p> + +<p>你甚至可以通过使用表单的{{domxref("HTMLFormElement.elements", "elements")}} 属性来更多的参与此过程,来得到一个包含表单里所有数据元素的列表,并且逐一手动管理他们。想了解更多,请参阅这里的例子:{{SectionOnPage("/en-US/docs/Web/API/HTMLFormElement.elements", "Accessing the element list's contents")}}</p> + +<h3 id="在隐藏的iframe中构建DOM">在隐藏的iframe中构建DOM</h3> + +<p>最古老的异步发送表单数据方法是用 DOM API 构建表单,然后将其数据发送到隐藏的 {{HTMLElement("iframe")}}。 要获得提交的结果,请获取{{HTMLElement("iframe")}}的内容。</p> + +<div class="warning"> +<p><strong>警告:</strong><strong>不要使用这项技术。</strong>有第三方服务的安全风险,因为它会使你暴露在 <a href="http://en.wikipedia.org/wiki/Cross-site_scripting" rel="external">脚本注入攻击</a> 中. 如果你使用 HTTPS,它会影响 <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Same_origin_policy_for_JavaScript">同源策略</a>, 这可以使 {{HTMLElement("iframe")}} 内容无法访问。然而,该方法可能是你需要支持很古老的浏览器的唯一选择。</p> +</div> + +<p>下面是个简单的例子:</p> + +<pre class="brush: html"><button onclick="sendData({test:'ok'})">点击我!</button></pre> + +<p>所有操作都在下面这段脚本里:</p> + +<pre class="brush: js">// 首先创建一个用来发送数据的iframe. +var iframe = document.createElement("iframe"); +iframe.name = "myTarget"; + +// 然后,将iframe附加到主文档 +window.addEventListener("load", function () { + iframe.style.display = "none"; + document.body.appendChild(iframe); +}); + +// 下面这个函数是真正用来发送数据的. +// 它只有一个参数,一个由键值对填充的对象. +function sendData(data) { + var name, + form = document.createElement("form"), + node = document.createElement("input"); + + // 定义响应时发生的事件 + iframe.addEventListener("load", function () { + alert("Yeah! Data sent."); + }); + + form.action = "http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi"; + form.target = iframe.name; + + for(name in data) { + node.name = name; + node.value = data[name].toString(); + form.appendChild(node.cloneNode()); + } + + // 表单元素需要附加到主文档中,才可以被发送。 + form.style.display = "none"; + document.body.appendChild(form); + + form.submit(); + + // 表单提交后,就可以删除这个表单,不影响下次的数据发送。 + document.body.removeChild(form); +}</pre> + +<p>在线演示:</p> + +<p>{{EmbedLiveSample("在DOM中构建一个隐藏的iframe", "100%", 50)}}</p> + +<h2 id="处理二进制数据">处理二进制数据</h2> + +<p>如果你使用一个含有 <code><input type="file"></code> 组件的表格的 {{domxref("XMLHttpRequest/FormData","FormData")}} 对象,传给代码的数据会被自动处理。但是要手动发送二进制数据的话,还有额外的工作要做。</p> + +<p>在现代网络上,二进制数据有很多来源:例如{{domxref("FileReader")}} API、{{domxref("HTMLCanvasElement","Canvas")}} API、<a href="/zh-CN/docs/WebRTC/navigator.getUserMedia" title="/zh-CN/docs/WebRTC/navigator.getUserMedia">WebRTC</a> API,等等。不幸的是,一些过时的浏览器无法访问二进制数据,或是需要非常复杂的工作环境。这些遗留问题已经超出了本文的涵盖范围。如果你想了解更多关于 <code>FileReader</code> API的知识,参阅:<a href="/zh-CN/docs/Using_files_from_web_applications" title="/zh-CN/docs/Using_files_from_web_applications">如何在web应用程序中使用文件</a>。</p> + +<p>在 {{domxref("XMLHttpRequest/FormData","formData")}} 的帮助下,发送二进制数据非常简单,使用 <code>append()</code> 方法就可以了。如果你必须手动进行,那确实会有一些棘手。</p> + +<p>在下面的例子中,我们使用了{{domxref("FileReader")}} API来访问二进制数据,然后手动构建多重表单数据请求:</p> + +<pre class="brush: html"><form id="myForm"> + <p> + <label for="i1">文本数据:</label> + <input id="i1" name="myText" value="一些文本数据"> + </p> + <p> + <label for="i2">文件数据:</label> + <input id="i2" name="myFile" type="file"> + </p> + <button>提交!</button> +</form></pre> + +<p>如你所见,这个 HTML 只是一个标准的 <code><form></code>。没有什么神奇的事情发生。“魔法”都在 JavaScript 里:</p> + +<pre class="brush: js">// 因为我们想获取 DOM 节点, +// 我们在页面加载时初始化我们的脚本. +window.addEventListener('load', function () { + + // 这些变量用于存储表单数据 + var text = document.getElementById("i1"); + var file = { + dom : document.getElementById("i2"), + binary : null + }; + + // 使用 FileReader API 获取文件内容 + var reader = new FileReader(); + + // 因为 FileReader 是异步的, 会在完成读取文件时存储结果 + reader.addEventListener("load", function () { + file.binary = reader.result; + }); + + // 页面加载时, 如果一个文件已经被选择, 那么读取该文件. + if(file.dom.files[0]) { + reader.readAsBinaryString(file.dom.files[0]); + } + + // 如果没有被选择,一旦用户选择了它,就读取文件。 + file.dom.addEventListener("change", function () { + if(reader.readyState === FileReader.LOADING) { + reader.abort(); + } + + reader.readAsBinaryString(file.dom.files[0]); + }); + + // 发送数据是我们需要的主要功能 + function sendData() { + // 如果存在被选择的文件,等待它读取完成 + // 如果没有, 延迟函数的执行 + if(!file.binary && file.dom.files.length > 0) { + setTimeout(sendData, 10); + return; + } + + // 要构建我们的多重表单数据请求, + // 我们需要一个XMLHttpRequest 实例 + var XHR = new XMLHttpRequest(); + + // 我们需要一个分隔符来定义请求的每一部分。 + var boundary = "blob"; + + // 将我们的主体请求存储于一个字符串中 + var data = ""; + + // 所以,如果用户已经选择了一个文件 + if (file.dom.files[0]) { + // 在请求体中开始新的一部分 + data += "--" + boundary + "\r\n"; + + // 把它描述成表单数据 + data += 'content-disposition: form-data; ' + // 定义表单数据的名称 + + 'name="' + file.dom.name + '"; ' + // 提供文件的真实名字 + + 'filename="' + file.dom.files[0].name + '"\r\n'; + // 和文件的MIME类型 + data += 'Content-Type: ' + file.dom.files[0].type + '\r\n'; + + // 元数据和数据之间有一条空行。 + data += '\r\n'; + + // 将二进制数据添加到主体请求中 + data += file.binary + '\r\n'; + } + + // 文本数据更简单一些 + // 在主体请求中开始一个新的部分 + data += "--" + boundary + "\r\n"; + + // 声明它是表单数据,并命名它 + data += 'content-disposition: form-data; name="' + text.name + '"\r\n'; + // 元数据和数据之间有一条空行。 + data += '\r\n'; + + // 添加文本数据到主体请求中 + data += text.value + "\r\n"; + + // 一旦完成,“关闭”主体请求 + data += "--" + boundary + "--"; + + // 定义成功提交数据执行的语句 + XHR.addEventListener('load', function(event) { + alert('✌!数据已发送且响应已加载。'); + }); + + // 定义发生错误时做的事 + XHR.addEventListener('error', function(event) { + alert('哎呀!出现了一些问题。'); + }); + + // 建立请求 + XHR.open('POST', 'https://example.com/cors.php'); + + // 添加需要的HTTP头部来处理多重表单数据POST请求 + XHR.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary); + + // 最后,发送数据。 + XHR.send(data); + } + + // 访问表单… + var form = document.getElementById("myForm"); + + // …接管提交事件 + form.addEventListener('submit', function (event) { + event.preventDefault(); + sendData(); + }); +});</pre> + +<p>在线演示:</p> + +<p>{{EmbedLiveSample("发送二进制数据", "100%", 150)}}</p> + +<h2 id="总结">总结</h2> + +<p>取决于不同的浏览器,通过 JavaScript 发送数据可能会很简单,也可能会很困难。{{domxref("XMLHttpRequest/FormData","FormData")}} 对象是通用的答案, 所以请毫不犹豫的在旧浏览器上通过polyfill使用它:</p> + +<ul> + <li>此<a href="https://gist.github.com/3120320" rel="external"> gist</a> 通过 {{domxref("Using_web_workers","Web Workers")}} polyfill 了 <code>FormData</code>。</li> + <li><a href="https://github.com/francois2metz/html5-formdata" rel="external">HTML5-formdata</a> 试图 polyfill <code>FormData</code> 对象, 但是它需要 <a href="http://www.w3.org/TR/FileAPI/" rel="external">File API</a></li> + <li>这个 <a href="https://github.com/jimmywarting/FormData">polyfill</a> 提供了 FormData 所有的大部分新方法(entries, keys, values, 以及对 <code>for...of</code> 的支持)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/How_to_build_custom_form_widgets", "Learn/HTML/Forms/HTML_forms_in_legacy_browsers", "Learn/HTML/Forms")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/Your_first_HTML_form">Your first HTML form</a></li> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">How to structure an HTML form</a></li> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/The_native_form_widgets">The native form widgets</a></li> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">Sending form data</a></li> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/Form_validation">Form data validation</a></li> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a></li> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript">Sending forms through JavaScript</a></li> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers">HTML forms in legacy browsers</a></li> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/Styling_HTML_forms">Styling HTML forms</a></li> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms">Advanced styling for HTML forms</a></li> + <li><a href="/zh-CN/docs/Learn/HTML/Forms/Property_compatibility_table_for_form_widgets">Property compatibility table for form widgets </a></li> +</ul> diff --git a/files/zh-cn/learn/html/forms/styling_html_forms/index.html b/files/zh-cn/learn/html/forms/styling_html_forms/index.html new file mode 100644 index 0000000000..26b94e94e8 --- /dev/null +++ b/files/zh-cn/learn/html/forms/styling_html_forms/index.html @@ -0,0 +1,388 @@ +--- +title: 样式化 HTML 表单 +slug: Learn/HTML/Forms/Styling_HTML_forms +tags: + - CSS + - Web + - 例子 + - 指导 + - 样式 + - 表单 +translation_of: Learn/Forms/Styling_web_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"><form> + <input type="search"> +</form> +</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 <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"><fieldset> + <legend>Hi!</legend> + <h1>Hello</h1> +</fieldset></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"><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></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: " >>>"; +} + +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" title="http://necolas.github.com/normalize.css">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> diff --git a/files/zh-cn/learn/html/forms/the_native_form_widgets/index.html b/files/zh-cn/learn/html/forms/the_native_form_widgets/index.html new file mode 100644 index 0000000000..8ef67a2f7a --- /dev/null +++ b/files/zh-cn/learn/html/forms/the_native_form_widgets/index.html @@ -0,0 +1,683 @@ +--- +title: 原生表单部件 +slug: Learn/HTML/Forms/The_native_form_widgets +translation_of: Learn/Forms/Basic_native_form_controls +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Forms/How_to_structure_an_HTML_form", "Learn/HTML/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms")}}</div> + +<p class="summary">现在,我们将详细研究不同表单部件的功能,查看了哪些选项可用于收集不同类型的数据。这个指南有些详尽,涵盖了所有可用的原生表单小部件。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">预备知识:</th> + <td>计算机基础知识和对于<a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML的基本理解</a>。</td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>要了解在浏览器中可以使用什么类型的原生表单小部件来收集数据,以及如何使用HTML实现它们。</td> + </tr> + </tbody> +</table> + +<p>这里我们将关注浏览器内置的表单部件,但是因为HTML表单仍然相当有限并且实现的特性在不同的浏览器中可能是相当不同的,web开发人员有时会建立自己的表单部件——关于这个的更多想法,参见本模块后面的<a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets">如何构建自定义表单部件</a>。</p> + +<div class="note"> +<p><strong>译者注:</strong>widget在本页面中被统一翻译为部件,但在其他地方可能也被译为组件。</p> +</div> + +<div class="note"> +<p><strong>注意:</strong>本文中讨论的大多数特性都在浏览器中得到了广泛的支持;我们会注意到例外的情况。如果您想要更准确的细节,您应该参考我们的<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element#Forms">HTML表单元素参考</a>,特别是我们的广泛的 <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input"><input></a>类型参考。</p> +</div> + +<h2 id="通用属性">通用属性</h2> + +<p>大部分用来定义表单小部件的元素都有一些他们自己的属性。然而,在所有表单元素中都有一组通用属性,它们可以对这些小部件进行控制。下面是这些通用属性的列表:</p> + +<table> + <thead> + <tr> + <th scope="col">属性名称</th> + <th scope="col">默认值</th> + <th scope="col">描述</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>autofocus</code></td> + <td>(<em>false</em>)</td> + <td>这个布尔属性允许您指定当页面加载时元素应该自动具有输入焦点,除非用户覆盖它,例如通过键入不同的控件。文档中只有一个与表单相关的元素可以指定这个属性。</td> + </tr> + <tr> + <td><code>disabled</code></td> + <td>(<em>false</em>)</td> + <td> + <p>这个布尔属性表示用户不能与元素交互。如果没有指定这个属性,元素将从包含它的元素继承设置,例如{{HTMLElement("fieldset")}};如果没有包含在设定了<code>disabled</code>属性的元素里,那么这个元素就是可用的。</p> + </td> + </tr> + <tr> + <td><code>form</code></td> + <td></td> + <td> + <p>小部件与之相关联的表单元素。属性值必需是同个文档中的{{HTMLElement("form")}} 元素的 <code>id</code>属性。理论上,它允许您在{{HTMLElement("form")}}元素之外设置一个表单小部件。然而,在实践中,没有任何支持该特性的浏览器。</p> + </td> + </tr> + <tr> + <td><code>name</code></td> + <td></td> + <td>元素的名称;这是跟表单数据一起提交的。</td> + </tr> + <tr> + <td><code>value</code></td> + <td></td> + <td>元素的初始值。</td> + </tr> + </tbody> +</table> + +<h2 id="文本输入框">文本输入框</h2> + +<p>文本输入框 {{htmlelement("input")}} 是最基本的表单小部件。 这是一种非常方便的方式,可以让用户输入任何类型的数据。但是,一些文本字段可以专门用于满足特定的需求。我们已经看到了几个简单的例子。</p> + +<div class="note"> +<p><strong>注意</strong>: HTML表单文本字段是简单的纯文本输入控件。 这意味着您不能使用它们执行<a href="https://developer.mozilla.org/en-US/docs/Rich-Text_Editing_in_Mozilla">富文本编辑</a>(粗体、斜体等)。你遇到的所有富文本编辑器(rich text editors)都是使用HTML、CSS和JavaScript所创建的自定义小部件。</p> +</div> + +<p>所有文本框都有一些通用规范:</p> + +<ul> + <li>它们可以被标记为 {{htmlattrxref("readonly","input")}} (用户不能修改输入值)甚至是 {{htmlattrxref("disabled","input")}} (输入值永远不会与表单数据的其余部分一起发送)。</li> + <li>它们可以有一个 {{htmlattrxref("placeholder","input")}}; 这是文本输入框中出现的文本,用来简略描述输入框的目的。</li> + <li>它们可以被限制在{{htmlattrxref("size","input")}} (框的物理尺寸) 和 {{htmlattrxref("maxlength","input")}} (可以输入的最大字符数)。</li> + <li>如果浏览器支持的话,他们可以从<a href="/en-US/docs/HTML/Element/input#attr-spellcheck">拼写检查</a>中获益。</li> +</ul> + +<div class="note"> +<p><strong>注意:</strong> {{htmlelement("input")}}元素是如此特别因为它几乎可以是任何东西。通过简单设置 <code>type</code> 属性,它可以彻底的改变,它用于创建大多数类型的表单小部件,包括单行文本字段、没有文本输入的控件、时间和日期控件和按钮。 然而,也有一些例外,比如用来多行输入的 {{htmlelement("textarea")}}。阅读这篇文章时,要注意这些。</p> +</div> + +<h3 id="单行文本框">单行文本框</h3> + +<p>使用{{htmlattrxref("type","input")}}属性值被设置为<code>text</code> 的{{HTMLElement("input")}}元素创建一个单行文本框(同样的,如果你不提供{{htmlattrxref("type","input")}}属性,<code>text</code> 是默认值)。在你指定的{{htmlattrxref("type","input")}}属性的值在浏览器中是未知的情况下(比如你指定 <code>type="date"</code>,但是浏览器不支持原生日期选择器),属性值<code>text</code>也是备用值。</p> + +<div class="note"> +<p><strong>注意:</strong> 你可以在Github上的 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/single-line-text-fields.html">single-line-text-fields.html</a>找到所有单行文本框类型。(你也可以直接看<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/single-line-text-fields.html">预览版</a>)。</p> +</div> + +<p>这是一个基本的单行文本框示例:</p> + +<pre class="brush: html notranslate"><input type="text" id="comment" name="comment" value="I'm a text field"></pre> + +<p>单行文本框只有一个真正的约束:如果您输入带有换行符的文本,浏览器会在发送数据之前删除这些换行符。</p> + +<p><img alt="Screenshots of single line text fields on several platforms." src="/files/4273/all-single-line-text-field.png" style="height: 235px; width: 655px;"></p> + +<p>HTML5通过为{{htmlattrxref("type","input")}}属性增加特殊值增强了基本单行文本框。这些值仍然将{{HTMLElement("input")}}元素转换为单行文本框,但它们为字段添加了一些额外的约束和特性。</p> + +<h4 id="E-mail_地址框">E-mail 地址框</h4> + +<p>该类型的框将 {{htmlattrxref("type","input")}}属性设置为 <code>email</code> 值:</p> + +<pre class="brush: html notranslate"><input type="email" id="email" name="email" multiple></pre> + +<p>当使用 <code>type</code>时, 用户需要在框中输入有效的电子邮件地址;任何其他内容都会导致浏览器在提交表单时显示错误。注意,这是客户端错误验证,由浏览器执行:</p> + +<p><img alt="An invalid email input showing the message Please enter an email address." src="https://mdn.mozillademos.org/files/14781/email-invalid.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>通过包括{{htmlattrxref("multiple","input")}}属性,它还可以让用户将多个电子邮件地址输入相同的输入(以逗号分隔)。</p> + +<p>在一些设备上(特别是在移动设备上),可能会出现一个不同的虚拟键盘,更适合输入电子邮件地址。</p> + +<div class="note"> +<p><strong>注意</strong>: 您可以在<a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Form_validation">表单数据验证</a>文中找到关于表单验证的更多信息。</p> +</div> + +<h4 id="密码框">密码框</h4> + +<p>通过设置{{htmlattrxref("type","input")}} 属性值为<code>password</code>来设置该类型框:</p> + +<pre class="brush: html notranslate"><input type="password" id="pwd" name="pwd"></pre> + +<p>它不会为输入的文本添加任何特殊的约束,但是它会模糊输入到字段中的值(例如,用点或小行星),这样它就不能被其他人读取。</p> + +<p>请记住,这只是一个用户界面特性;除非你安全地提交你的表单,否则它会以明文发送,这不利于安全——恶意的一方可能会截获你的数据,窃取你的密码、信用卡信息,或者你提交的其他任何东西。保护用户不受此影响的最佳方式是在安全连接上托管任何涉及表单的页面(例如:https://……地址),使得数据在发送之前就已加密。</p> + +<p>现代浏览器认识到在不安全的连接上发送表单数据所带来的安全影响,并且已经实现了警告,以阻止用户使用不安全的表单。有关Firefox实现的更多信息,请参见<a href="/en-US/docs/Web/Security/Insecure_passwords">不安全的密码</a>。</p> + +<h4 id="搜索框">搜索框</h4> + +<p>通过设置 {{htmlattrxref("type","input")}}属性值为 <code>search</code> 来设置该类型框:</p> + +<pre class="brush: html notranslate"><input type="search" id="search" name="search"></pre> + +<p>文本框和搜索框之间的主要区别是浏览器的样式——通常,搜索框是渲染成圆角的,并且/可能给定一个“x”来清除输入的值。然而,还有另外一个值得注意的特性:它们的值可以被自动保存用来在同一站点上的多个页面上自动补全。</p> + +<p><img alt="Screenshots of search fields on several platforms." src="/files/4269/all-search-field.png" style="height: 235px; width: 655px;"></p> + +<h4 id="电话号码栏:">电话号码栏:</h4> + +<p>通过 {{htmlattrxref("type","input")}}属性的 <code>tel</code> 值设置该类型框:</p> + +<pre class="brush: html notranslate"><input type="tel" id="tel" name="tel"></pre> + +<p>由于世界范围内各种各样的电话号码格式,这种类型的字段不会对用户输入的值执行任何限制(包括字母,等等)。这主要是在语义上的区分,尽管在一些设备上(特别是在移动设备上),可能会出现一个不同的虚拟键盘,更适合输入电话号码。</p> + +<h4 id="URL_栏">URL 栏</h4> + +<p>通过{{htmlattrxref("type","input")}}属性的<code>url</code> 值设置该类型框:</p> + +<pre class="brush: html notranslate"><input type="url" id="url" name="url"></pre> + +<p>它为字段添加了特殊的验证约束,如果输入无效的url,浏览器就会报告错误。</p> + +<div class="note"><strong>注意:</strong>URL格式良好并不一定意味着它引用了一个实际存在的位置。</div> + +<div class="note"> +<p><strong>注意:</strong>有特殊约束并出错了的输入框可以防止表单被发送;此外,还可以将它们设置为使错误更清晰。我们将在<a href="/en-US/docs/HTML/Forms/Data_form_validation">数据表单验证</a>中详细讨论这个问题。</p> +</div> + +<h3 id="多行文本框">多行文本框</h3> + +<p>多行文本框专指使用 {{HTMLElement("textarea")}}元素,而不是使用{{HTMLElement("input")}} 元素。</p> + +<pre class="brush: html notranslate"><textarea cols="30" rows="10"></textarea></pre> + +<p>textarea和常规的单行文本字段之间的主要区别是,允许用户输入包含硬换行符(即按回车)的文本。</p> + +<p><img alt="Screenshots of multi-lines text fields on several platforms." src="/files/4271/all-multi-lines-text-field.png" style="height: 330px; width: 745px;"></p> + +<div class="note"> +<p><strong>注意:</strong>你可以在Github上的<a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/multi-line-text-field.html">multi-line-text-field.html</a>看到本例(你也可以看<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/multi-line-text-field.html">预览版</a>)。注意到在大多数浏览器中,文本区域在右下角有一个拖放操作,允许用户调整它的大小。这种调整能力可以通过使用<a href="/en-US/docs/Learn/CSS">CSS</a>设置文本区域的{{cssxref("resize")}}性质为 <code>none</code> 来关闭。</p> +</div> + +<p>{{htmlelement("textarea")}} 还接受了一些额外的属性,以控制它在几行代码中呈现的效果 (除此以外还有其他几个):</p> + +<p><strong style="font-style: inherit; font-weight: 700;">{{HTMLElement("textarea")}} 元素属性</strong></p> + +<table> + <thead> + <tr> + <th scope="col">属性名</th> + <th scope="col">默认值</th> + <th scope="col">描述</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("cols","textarea")}}</td> + <td><code>20</code></td> + <td>文本控件的可见宽度,平均字符宽度。</td> + </tr> + <tr> + <td>{{htmlattrxref("rows","textarea")}}</td> + <td></td> + <td>控制的可见文本行数。</td> + </tr> + <tr> + <td>{{htmlattrxref("wrap","textarea")}}</td> + <td><code>soft</code></td> + <td>表示控件是如何包装文本的。可能的值:<code>hard</code> 或 <code>soft</code></td> + </tr> + </tbody> +</table> + +<p>注意,{{HTMLElement("textarea")}}元素与{{HTMLElement("input")}}元素的编写略有不同。{{HTMLElement("input")}}元素是一个空元素,这意味着它不能包含任何子元素。另一方面,{{HTMLElement("textarea")}}元素是一个常规元素,可以包含文本内容的子元素。</p> + +<p>这里有两个关键点需要注意:</p> + +<ul> + <li>如果您想为{{HTMLElement("input")}}元素定义一个默认值,那么您必须使用<code>value</code>属性;另一方面,对于{{HTMLElement("textarea")}}元素,只需要将默认的文本放在起始标记和{{HTMLElement("textarea")}}的结束标记之间。</li> + <li>因为它的本质, {{HTMLElement("textarea")}}元素只接受文本内容;这意味着将任何HTML内容放入{{HTMLElement("textarea")}}中都呈现为纯文本内容。</li> +</ul> + +<h2 id="下拉内容">下拉内容</h2> + +<p>下拉窗口小部件是一种简单的方法,可以让用户选择众多选项中的一个,而不需要占用用户界面的太多空间。HTML有两种类型的下拉内容:<strong>select box</strong>和<strong>autocomplete box</strong>。在这两种情况下,交互都是相同的——一旦控件被激活,浏览器就会显示用户可以选择的值列表。</p> + +<div class="note"> +<p><strong>注意:</strong>你可以在Github上的<a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/drop-down-content.html">drop-down-content.html</a>看到本例(你也可以看<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/drop-down-content.html">预览版</a>)。</p> +</div> + +<h3 id="选择框">选择框</h3> + +<p>一个选择框是用{{HTMLElement("select")}}元素创建的,其中有一个或多个{{HTMLElement("option")}}元素作为子元素,每个元素都指定了其中一个可能的值。</p> + +<pre class="brush: html notranslate"><select id="simple" name="simple"> + <option>Banana</option> + <option>Cherry</option> + <option>Lemon</option> +</select></pre> + +<p>如果需要,可以使用{{htmlattrxref("selected","option")}}属性在所需的{{HTMLElement("option")}}元素上设置选择框的默认值---在页面加载时会默认选择该选项。{{HTMLElement("option")}}元素也可以嵌套在{{HTMLElement("optgroup")}}元素中,以创建视觉关联的组值:</p> + +<pre class="brush: html notranslate"><select id="groups" name="groups"> + <optgroup label="fruits"> + <option>Banana</option> + <option selected>Cherry</option> + <option>Lemon</option> + </optgroup> + <optgroup label="vegetables"> + <option>Carrot</option> + <option>Eggplant</option> + <option>Potato</option> + </optgroup> +</select></pre> + +<p><img alt="Screenshots of single line select box on several platforms." src="/files/4517/all-select.png" style="height: 636px; width: 887px;"></p> + +<p>如果一个{{HTMLElement("option")}}元素设置了<code>value</code>属性,那么当提交表单时该属性的值就会被发送。如果忽略了<code>value</code>属性,则使用{{HTMLElement("option")}}元素的内容作为选择框的值。</p> + +<p>在{{HTMLElement("optgroup")}}元素中,<code>label</code>属性显示在值之前,但即使它看起来有点像一个选项,它也不是可选的。</p> + +<h3 id="多选选择框">多选选择框</h3> + +<p>默认情况下,选择框只允许用户选择一个值。通过将{{htmlattrxref("multiple","select")}}属性添加到{{HTMLElement("select")}}元素,您可以允许用户通过操作系统提供的默认机制来选择几个值。 (如, 同时按下 <kbd>Cmd</kbd>/<kbd>Ctrl</kbd> 并点击多个值).</p> + +<p>注意:在多个选项选择框的情况下,选择框不再显示值为下拉内容——相反,它们都显示在一个列表中。</p> + +<pre class="brush: html notranslate"><select multiple id="multi" name="multi"> + <option>Banana</option> + <option>Cherry</option> + <option>Lemon</option> +</select></pre> + +<p><img alt="Screenshots of multi-lines select box on several platforms." src="/files/4559/all-multi-lines-select.png" style="height: 531px; width: 734px;"></p> + +<div class="note"><strong>注意:</strong>所有支持 {{HTMLElement("select")}} 元素的浏览器也支持 {{htmlattrxref("multiple","select")}} 。</div> + +<h3 id="自动补全输入框">自动补全输入框</h3> + +<p>您可以使用{{HTMLElement("datalist")}}元素来为表单小部件提供建议的、自动完成的值,并使用一些{{HTMLElement("option")}}子元素来指定要显示的值。</p> + +<p>然后使用{{htmlattrxref("list","input")}}属性将数据列表绑定到一个文本框(通常是一个 <code><input></code> 元素)。</p> + +<p>一旦数据列表与表单小部件相关联,它的选项用于自动完成用户输入的文本;通常,这是作为一个下拉框提供给用户的,匹配在输入框中输入了的内容。</p> + +<pre class="brush: html notranslate"><label for="myFruit">What's your favorite fruit?</label> +<input type="text" name="myFruit" id="myFruit" list="mySuggestion"> +<datalist id="mySuggestion"> + <option>Apple</option> + <option>Banana</option> + <option>Blackberry</option> + <option>Blueberry</option> + <option>Lemon</option> + <option>Lychee</option> + <option>Peach</option> + <option>Pear</option> +</datalist></pre> + +<div class="note"><strong>注意:</strong> 根据<a href="http://www.w3.org/TR/html5/common-input-element-attributes.html#attr-input-list">HTML规范</a>,{{htmlattrxref("list","input")}} 属性和{{HTMLElement("datalist")}}元素元素可以用于任何需要用户输入的小部件。但是,除了文本控件外(例如颜色或日期),还不清楚它会如何工作,不同的浏览器在不同的情况下会有不同的表现。正因为如此,除了文本字段以外,要小心使用这个特性。</div> + +<div><img alt="Screenshots of datalist on several platforms." src="/files/4593/all-datalist.png" style="height: 329px; width: 437px;"></div> + +<div></div> + +<h4 id="数据列表支持和后备">数据列表支持和后备</h4> + +<p>{{HTMLElement("datalist")}}元素是HTML表单的最新补充,因此浏览器的支持比我们之前看到的要少一些。最值得注意的是,它在版本小于10的IE中不受支持,同时在版本小于12的Safari中不受支持。</p> + +<p>为了处理这个问题,这里有一个小技巧,可以为这些浏览器提供一个不错的备用:</p> + +<pre class="brush:html; notranslate"><label for="myFruit">What is your favorite fruit? (With fallback)</label> +<input type="text" id="myFruit" name="fruit" list="fruitList"> + +<datalist id="fruitList"> + <label for="suggestion">or pick a fruit</label> + <select id="suggestion" name="altFruit"> + <option>Apple</option> + <option>Banana</option> + <option>Blackberry</option> + <option>Blueberry</option> + <option>Lemon</option> + <option>Lychee</option> + <option>Peach</option> + <option>Pear</option> + </select> +</datalist> +</pre> + +<p>支持{{HTMLElement("datalist")}}元素的浏览器将忽略所有不是{{HTMLElement("option")}}元素的元素,并按照预期工作。另一方面,不支持{{HTMLElement("datalist")}}元素的浏览器将显示标签和选择框。当然,还有其他方法可以处理对{{HTMLElement("datalist")}}元素支持的不足,但这是最简单的(其他方法往往需要JavaScript)。</p> + +<table> + <tbody> + <tr> + <th scope="row">Safari 6</th> + <td><img alt="Screenshot of the datalist element fallback with Safari on Mac OS" src="/files/4583/datalist-safari.png" style="height: 32px; width: 495px;"></td> + </tr> + <tr> + <th scope="row">Firefox 18</th> + <td><img alt="Screenshot of the datalist element with Firefox on Mac OS" src="/files/4581/datalist-firefox-macos.png" style="height: 102px; width: 353px;"></td> + </tr> + </tbody> +</table> + +<h2 id="可选中项">可选中项</h2> + +<p>可选中项是可以通过单击它们来更改状态的小部件。有两种可选中项:复选框和单选按钮。两者都使用{{htmlattrxref("checked","input")}}属性,以指示该部件的默认状态: "选中"或"未选中"。</p> + +<p>值得注意的是,这些小部件与其他表单小部件不一样。对于大多数表单部件,一旦表单提交,所有具有{{htmlattrxref("name","input")}}属性的小部件都会被发送,即使没有任何值被填。对于可选中项,只有在勾选时才发送它们的值。如果他们没有被勾选,就不会发送任何东西,甚至连他们的名字也没有。</p> + +<div class="note"> +<p><strong>注意</strong>: 你可以在Github上看到 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/checkable-items.html">checkable-items.html</a> (你也可以看<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/checkable-items.html">预览版</a>)。</p> +</div> + +<p>为了获得最大的可用性和可访问性,建议您在{{htmlelement("fieldset")}}中包围每个相关项目的列表,并使用{{htmlelement("legend")}}提供对列表的全面描述。每个单独的{{htmlelement("label")}}/{{htmlelement("input")}}元素都应该包含在它自己的列表项中(或者类似的)。正如在示例中显示的。</p> + +<p>您还需要为这些类型的输入提供<code>value</code>属性,如果您想让它们具有意义——如果没有提供任何值,则复选框和单选按钮被赋予一个 <code>on</code>值。</p> + +<h3 id="复选框">复选框</h3> + +<p>使用{{htmlattrxref("type","input")}}属性值为<code>checkbox</code>的 {{HTMLElement("input")}}元素来创建一个复选框。</p> + +<pre class="brush: html notranslate"><input type="checkbox" checked id="carrots" name="carrots" value="carrots"> +</pre> + +<p>包含<code>checked</code>属性使复选框在页面加载时自动被选中。</p> + +<p><img alt="Screenshots of check boxes on several platforms." src="/files/4595/all-checkbox.png" style="height: 198px; width: 352px;"></p> + +<h3 id="单选按钮">单选按钮</h3> + +<p>使用{{htmlattrxref("type","input")}}属性值为<code>radio</code>的 {{HTMLElement("input")}}元素来创建一个单选按钮。</p> + +<pre class="brush: html notranslate"><input type="radio" checked id="soup" name="meal"></pre> + +<p>几个单选按钮可以连接在一起。如果它们的{{htmlattrxref("name","input")}}属性共享相同的值,那么它们将被认为属于同一组的按钮。同一组中只有一个按钮可以同时被选;这意味着当其中一个被选中时,所有其他的都将自动未选中。如果没有选中任何一个,那么整个单选按钮池就被认为处于未知状态,并且没有以表单的形式发送任何值。</p> + +<pre class="brush: html notranslate"><fieldset> + <legend>What is your favorite meal?</legend> + <ul> + <li> + <label for="soup">Soup</label> + <input type="radio" checked id="soup" name="meal" value="soup"> + </li> + <li> + <label for="curry">Curry</label> + <input type="radio" id="curry" name="meal" value="curry"> + </li> + <li> + <label for="pizza">Pizza</label> + <input type="radio" id="pizza" name="meal" value="pizza"> + </li> + </ul> +</fieldset></pre> + +<p><img alt="Screenshots of radio buttons on several platforms." src="/files/4597/all-radio.png" style="height: 198px; width: 352px;"></p> + +<h2 id="按钮">按钮</h2> + +<p>在HTML表单中,有三种按钮:</p> + +<dl> + <dt>Submit</dt> + <dd>将表单数据发送到服务器。对于{{HTMLElement("button")}} 元素, 省略 <code>type</code> 属性 (或是一个无效的 <code>type</code> 值) 的结果就是一个提交按钮.</dd> + <dt>Reset</dt> + <dd>将所有表单小部件重新设置为它们的默认值。</dd> + <dt>Anonymous</dt> + <dd>没有自动生效的按钮,但是可以使用JavaScript代码进行定制。</dd> +</dl> + +<div class="note"> +<p><strong>注意</strong>: 你可以在Github上看到<a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/button-examples.html">button-examples.html</a> (你也可以看<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/button-examples.html">预览版</a>)。</p> +</div> + +<p>使用 {{HTMLElement("button")}}元素或者{{HTMLElement("input")}}元素来创建一个按钮。{{htmlattrxref("type","input")}}属性的值指定显示什么类型的按钮。</p> + +<h3 id="submit">submit</h3> + +<pre class="brush: html notranslate"><button type="submit"> + This a <br><strong>submit button</strong> +</button> + +<input type="submit" value="This is a submit button"></pre> + +<h3 id="reset">reset</h3> + +<pre class="brush: html notranslate"><button type="reset"> + This a <br><strong>reset button</strong> +</button> + +<input type="reset" value="This is a reset button"></pre> + +<h3 id="button">button</h3> + +<pre class="brush: html notranslate"><button type="button"> + This an <br><strong>anonymous button</strong> +</button> + +<input type="button" value="This is an anonymous button"></pre> + +<p>不管您使用的是{{HTMLElement("button")}}元素还是{{HTMLElement("input")}}元素,按钮的行为都是一样的。然而,有一些显著的不同之处:</p> + +<ul> + <li>从示例中可以看到,{{HTMLElement("button")}}元素允许您在它们的标签中使用HTML内容,这些内容被插入到打开和关闭<code><button></code> 标签中。另一方面,{{HTMLElement("input")}}元素是空元素;它们的标签插入在<code>value</code>属性中,因此只接受纯文本内容。</li> + <li>使用{{HTMLElement("button")}}元素,可以有一个不同于按钮标签的值(通过设置<code>value</code>中的属性值)。这在IE 8之前的版本中是不可靠的。</li> +</ul> + +<p><img alt="Screenshots of buttons on several platforms." src="/files/4599/all-buttons.png" style="height: 235px; width: 464px;"></p> + +<p>从技术上讲,使用{{HTMLElement("button")}}元素或{{HTMLElement("input")}}元素定义的按钮几乎没有区别。唯一值得注意的区别是按钮本身的标签。在{{HTMLElement("input")}}元素中,标签只能是字符数据,而在{{HTMLElement("button")}}元素中,标签可以是HTML,因此可以相应地进行样式化。</p> + +<h2 id="高级表单部件">高级表单部件</h2> + +<p>在本节中,我们将介绍那些让用户输入复杂或不寻常数据的小部件。这包括精确的或近似的数字,日期和时间,或颜色。</p> + +<div class="note"> +<p><strong>注意</strong>: 你可以在Github上看到<a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/advanced-examples.html">advanced-examples.html</a> (你也可以看<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/advanced-examples.html">预览版</a>)。</p> +</div> + +<h3 id="数字">数字</h3> + +<p>用于数字的小部件是用{{htmlattrxref("type","input")}}属性设置为<code>number</code>{{HTMLElement("input")}}的元素创建的。这个控件看起来像一个文本框,但是只允许浮点数,并且通常提供一些按钮来增加或减少小部件的值。</p> + +<p>也可以:</p> + +<ul> + <li>通过设置{{htmlattrxref("min","input")}}和{{htmlattrxref("max","input")}}属性来约束该值。</li> + <li>通过设置{{htmlattrxref("step","input")}}属性来指定增加和减少按钮更改小部件的步进值大小。</li> +</ul> + +<h4 id="例子">例子</h4> + +<pre class="brush: html notranslate"><input type="number" name="age" id="age" min="1" max="10" step="2"></pre> + +<p>这将创建一个数字小部件,其值被限制为1到10之间的任何值,而其增加和减少按钮的步进值将更改为2。</p> + +<p>在10以下的Internet Explorer版本中不支持<code>number</code> 输入。</p> + +<h3 id="滑块">滑块</h3> + +<p>另一种选择数字的方法是使用滑块。从视觉上讲,滑块没有文本字段准确,因此它们被用来选择一个确切值并不重要的数字。</p> + +<p>滑块是通过把{{HTMLElement("input")}}元素的{{htmlattrxref("type","input")}}属性值设置为<code>range</code>来创建的。正确配置滑块是很重要的;为了达到这个目的,我们强烈建议您设置{{htmlattrxref("min","input")}}、{{htmlattrxref("max","input")}}和{{htmlattrxref("step","input")}}属性。</p> + +<h4 id="例子_2">例子</h4> + +<pre class="brush: html notranslate"><input type="range" name="beans" id="beans" min="0" max="500" step="10"></pre> + +<p>这个例子创建了一个滑块,它可能的值在0到500之间,而它的递增/递减按钮以+10和-10来改变值。</p> + +<p>滑块的一个问题是,它们不提供任何形式的视觉反馈,以了解当前的值是什么。您需要使用JavaScript来添加这一点,但这相对来说比较容易。在本例中,我们添加了一个空的{{htmlelement("span")}}元素,其中我们将写入滑块的当前值,并随着更改实时更新它。</p> + +<pre class="brush: html notranslate"><label for="beans">How many beans can you eat?</label> +<input type="range" name="beans" id="beans" min="0" max="500" step="10"> +<span class="beancount"></span></pre> + +<p>可以使用一些简单的JavaScript实现</p> + +<pre class="brush: js notranslate">var beans = document.querySelector('#beans'); +var count = document.querySelector('.beancount'); + +count.textContent = beans.value; + +beans.oninput = function() { + count.textContent = beans.value; +}</pre> + +<p>这里我们将对范围输入值和span的引用存储在两个变量里,然后我们立即将span的<code><a href="/en-US/docs/Web/API/Node/textContent">textContent</a></code>设置为输入的当前<code>value</code>。最后,我们设置了一个<code>oninput</code>事件处理程序,以便每次移动范围滑块时,都会将span <code>textContent</code>更新为新的输入值。</p> + +<p>在10以下的Internet Explorer版本中不支持<code>range</code> 。</p> + +<h3 id="日期时间选择器">日期时间选择器</h3> + +<p>对于web开发人员来说,收集日期和时间值一直是一场噩梦。HTML5通过提供一种特殊的控制来处理这种特殊的数据,从而带来了一些增强。</p> + +<p>使用{{HTMLElement("input")}}元素和一个适当的值的{{htmlattrxref("type","input")}}属性来创建日期和时间控制,这取决于您是否希望收集日期、时间或两者都。</p> + +<h4 id="本地时间"><code>本地时间</code></h4> + +<p>这将创建一个小部件来显示和选择一个日期,但是没有任何特定的时区信息。</p> + +<pre class="brush: html notranslate"><input type="datetime-local" name="datetime" id="datetime"></pre> + +<h4 id="月"><code>月</code></h4> + +<p>这就创建了一个小部件来显示和挑选一个月。</p> + +<pre class="brush: html notranslate"><input type="month" name="month" id="month"></pre> + +<h4 id="时间"><font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: #eeeeee;">时间</span></font></h4> + +<p>这将创建一个小部件来显示并选择一个时间值。</p> + +<pre class="brush: html notranslate"><input type="time" name="time" id="time"></pre> + +<h4 id="星期"><code>星期</code></h4> + +<p>这将创建一个小部件来显示并挑选一个星期号和它的年份。</p> + +<pre class="brush: html notranslate"><input type="week" name="week" id="week"></pre> + +<p>所有日期和时间控制都可以使用{{htmlattrxref("min","input")}}和{{htmlattrxref("max","input")}}属性来约束。</p> + +<pre class="brush: html notranslate"><label for="myDate">When are you available this summer?</label> +<input type="date" name="myDate" min="2013-06-01" max="2013-08-31" id="myDate"></pre> + +<p>警告——日期和时间窗口小部件仍然很不受支持。目前,Chrome、Edge和Opera都支持它们,但IE浏览器没有支持,Firefox和Safari对这些都没有太大的支持。</p> + +<h3 id="拾色器">拾色器</h3> + +<p>颜色总是有点难处理。有很多方式来表达它们:RGB值(十进制或十六进制)、HSL值、关键字等等。颜色小部件允许用户在文本和可视的方式中选择颜色。</p> + +<p>一个颜色小部件是使用{{htmlattrxref("type","input")}}属性设置为值<code>color</code>{{HTMLElement("input")}}的元素创建的。</p> + +<pre class="brush: html notranslate"><input type="color" name="color" id="color"></pre> + +<p>警告——并不是所有浏览器都支持拾色器。IE中没有支持,Safari目前也不支持它。其他主要的浏览器都支持它。</p> + +<h2 id="其他小部件">其他小部件</h2> + +<p>还有一些其他的小部件由于它们非常特殊的行为而不能很容易地分类,但是它们仍然非常有用。</p> + +<div class="note"> +<p><strong>注意</strong>: 你可以在Github上看到<a href="https://github.com/mdn/learning-area/blob/master/html/forms/native-form-widgets/other-examples.html">other-examples.html</a>(你也可以看<a href="https://mdn.github.io/learning-area/html/forms/native-form-widgets/other-examples.html">预览版</a>)。</p> +</div> + +<h3 id="文件选择器">文件选择器</h3> + +<p>HTML表单能够将文件发送到服务器;在<a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">发送和检索表单数据</a>的文章中详细描述了这个特定的操作。文件选择器小部件是用户如何选择一个或多个文件来发送的。</p> + +<p>要创建一个文件选择器小部件,您可以使用{{HTMLElement("input")}}元素,将它的{{htmlattrxref("type","input")}}属性设置为<code>file</code>。被接受的文件类型可以使用{{htmlattrxref("accept","input")}}属性来约束。此外,如果您想让用户选择多个文件,那么可以通过添加{{htmlattrxref("multiple","input")}}属性来实现。</p> + +<h4 id="例子_3">例子</h4> + +<p>在本例中,创建一个文件选择器,请求图形图像文件。在本例中,允许用户选择多个文件。</p> + +<pre class="brush: html notranslate"><input type="file" name="file" id="file" accept="image/*" multiple></pre> + +<h3 id="隐藏内容">隐藏内容</h3> + +<p>有时候,由于为了方便技术原因,有些数据是用表单发送的,但不显示给用户。要做到这一点,您可以在表单中添加一个不可见的元素。要做到这一点,需要使用{{HTMLElement("input")}}将它的{{htmlattrxref("type","input")}}属性设置为<code>hidden</code>值。</p> + +<p>如果您创建了这样一个元素,就需要设置它的<code>name</code>和<code>value</code>属性:</p> + +<pre class="brush: html notranslate"><input type="hidden" id="timestamp" name="timestamp" value="1286705410"></pre> + +<h3 id="图像按钮">图像按钮</h3> + +<p>图像按钮控件是一个与{{HTMLElement("img")}}元素完全相同的元素,除了当用户点击它时,它的行为就像一个提交按钮(见上面)。</p> + +<p>图像按钮是使用{{htmlattrxref("type","input")}}属性值设置为<code>image</code>{{HTMLElement("input")}}的元素创建的。这个元素支持与{{HTMLElement("img")}}元素相同的属性,和其他表单按钮支持的所有属性。</p> + +<pre class="brush: html notranslate"><input type="image" alt="Click me!" src="my-img.png" width="80" height="30" /></pre> + +<p>如果使用图像按钮来提交表单,这个小部件不会提交它的值;相反,提交的是在图像上单击处的X和Y坐标(坐标是相对于图像的,这意味着图像的左上角表示坐标0,0),坐标被发送为两个键/值对:</p> + +<ul> + <li>X值键是{{htmlattrxref("name","input")}}属性的值,后面是字符串“.x”。</li> + <li>Y值键是{{htmlattrxref("name","input")}}属性的值,后面是字符串“.y”。</li> +</ul> + +<p>例如,当您点击这个小部件的图像时,您将被发送到一个URL,如下所显示的</p> + +<pre class="notranslate">http://foo.com?pos.x=123&pos.y=456</pre> + +<p>这是构建“热图”的一种非常方便的方式。如何发送和检索这些值在<a href="/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">发送和检索表单数据</a>文章中详细说明。</p> + +<h3 id="仪表和进度条">仪表和进度条</h3> + +<p>仪表和进度条是数值的可视化表示。</p> + +<h4 id="进度条">进度条</h4> + +<p>一个进度条表示一个值,它会随着时间的变化而变化到最大的值,这个值由{{htmlattrxref("max","progress")}}属性指定。这样的一个bar是使用{{ HTMLElement("progress")}}元素创建的。</p> + +<pre class="brush: html notranslate"><progress max="100" value="75">75/100</progress></pre> + +<p>这是为了实现任何需要进度报告的内容,例如下载的总文件的百分比,或者问卷中填写的问题的数量。</p> + +<p>{{HTMLElement("progress")}}元素中的内容用于不支持该元素的浏览器的回退,以及辅助技术对其朗读。</p> + +<h4 id="仪表">仪表</h4> + +<p>一个仪表表示一个固定值,这个值由一个{{htmlattrxref("min","meter")}}和一个{{htmlattrxref("max","meter")}}值所界定。这个值是作为一个条形显示的,并且为了知道这个工具条是什么样子的,我们将这个值与其他一些设置值进行比较</p> + +<ul> + <li> {{htmlattrxref("low","meter")}} 和 {{htmlattrxref("high","meter")}} 值范围划分为三个部分: + <ul> + <li>该范围的较低部分是在{{htmlattrxref("min","meter")}}和{{htmlattrxref("low","meter")}}值(包括那些值)之间。</li> + <li>该范围的中间部分是在{{htmlattrxref("low","meter")}}和{{htmlattrxref("high","meter")}}值之间(不包括那些值)。</li> + <li>该范围的较高部分是在{{htmlattrxref("high","meter")}}和{{htmlattrxref("max","meter")}}值(包括那些值)之间。</li> + </ul> + </li> + <li>{{htmlattrxref("optimum","meter")}}值定义了{{HTMLElement("meter")}}元素的最优值。在与htmlattrxref(“low”、“meter”)和{{htmlattrxref("high","meter")}}值的联合中,它定义了该范围的哪个部分是优先的: + <ul> + <li>如果{{htmlattrxref("optimum","meter")}}值在较低的范围内,则较低的范围被认为是首选项,中等范围被认为是一般的,而较高的范围被认为是最坏的部分。</li> + <li>如果{{htmlattrxref("optimum","meter")}}值在该范围的中等部分,则较低的范围被认为是一个一般的,中等范围被认为是优先的部分,而较高的范围也被认为是平均值。</li> + <li>如果{{htmlattrxref("optimum","meter")}}值在较高的范围内,则较低的范围被认为是最坏的部分,中等范围被认为是一般的部分,较高的范围被认为是优先的部分。</li> + </ul> + </li> +</ul> + +<p>所有实现{{HTMLElement("meter")}}元素的浏览器都使用这些值来改变米尺的颜色。</p> + +<ul> + <li>如果当前值位于该范围的优先部分,则该条是绿色的。</li> + <li>如果当前值位于该范围的平均部分,则该条是黄色的。</li> + <li>如果当前值处于最糟糕的范围,则该条是红色的。</li> +</ul> + +<p>这样的一个工具栏是使用{{HTMLElement("meter")}}元素创建的。这是用于实现任何类型的仪表,例如一个显示磁盘上使用的总空间的条,当它开始满时,它会变成红色。</p> + +<pre class="brush: html notranslate"><meter min="0" max="100" value="75" low="33" high="66" optimum="50">75</meter></pre> + +<p>{{HTMLElement("meter")}}元素中的内容是不支持该元素的浏览器的回退,以及辅助技术对其发出的声音。</p> + +<p>对进度条和仪表的支持是相当不错的,在Internet Explorer中没有支持,但是其他浏览器都可以很好的支持它。</p> + +<h2 id="总结">总结</h2> + +<p>正如您在上面看到的,有许多不同类型的可用表单元素——您不需要一次性记住所有细节,可以随时返回本文查看详细信息。</p> + +<h2 id="另见">另见</h2> + +<p>要深入了解不同的表单小部件,您需要了解一些有用的外部资源:</p> + +<ul> + <li><a href="http://wufoo.com/html5/" rel="external" title="http://wufoo.com/html5/">The Current State of HTML5 Forms</a> by Wufoo</li> + <li><a href="http://www.quirksmode.org/html5/inputs.html" rel="external" title="http://www.quirksmode.org/html5/inputs.html">HTML5 Tests - inputs</a> on Quirksmode (also <a href="http://www.quirksmode.org/html5/inputs_mobile.html" rel="external" title="http://www.quirksmode.org/html5/inputs_mobile.html">available for mobile</a> browsers)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Forms/How_to_structure_an_HTML_form", "Learn/HTML/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms")}}</p> diff --git a/files/zh-cn/learn/html/forms/your_first_html_form/index.html b/files/zh-cn/learn/html/forms/your_first_html_form/index.html new file mode 100644 index 0000000000..5b0adc1480 --- /dev/null +++ b/files/zh-cn/learn/html/forms/your_first_html_form/index.html @@ -0,0 +1,266 @@ +--- +title: 创建我的第一个表单 +slug: Learn/HTML/Forms/Your_first_HTML_form +translation_of: Learn/Forms/Your_first_form +--- +<p>{{LearnSidebar}}{{NextMenu("Learn/HTML/Forms/How_to_structure_an_HTML_form", "Learn/HTML/Forms")}}</p> + +<p class="summary">本系列的第一篇文章提供了您第一次创建HTML表单的经验,包括设计一个简单表单,使用正确的HTML元素实现它,通过CSS添加一些非常简单的样式,以及如何将数据发送到服务器。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">预备知识:</th> + <td> + <p>基本计算机素养和<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">对HTML的基本理解</a>。</p> + </td> + </tr> + <tr> + <th scope="row">目标:</th> + <td>为了熟悉HTML表单是什么,它们被用来做什么,如何设计它们,以及简单情况下需要的基本HTML元素。</td> + </tr> + </tbody> +</table> + +<h2 id="HTML表单是什么?">HTML表单是什么?</h2> + +<p>HTML表单是用户和web站点或应用程序之间交互的主要内容之一。它们允许用户将数据发送到web站点。大多数情况下,数据被发送到web服务器,但是web页面也可以自己拦截它并使用它。</p> + +<p>HTML表单是由一个或多个小部件组成的。这些小部件可以是文本字段(单行或多行)、选择框、按钮、复选框或单选按钮。大多数情况下,这些小部件与描述其目的的标签配对——正确实现的标签能够清楚地指示视力正常的用户和盲人用户输入表单所需的内容。</p> + +<p>HTML表单和常规HTML文档的主要区别在于,大多数情况下,表单收集的数据被发送到web服务器。在这种情况下,您需要设置一个web服务器来接收和处理数据。如何设置这样的服务器超出了本文的范围,但是如果您想了解更多,请参阅模块后面的<a href="/zh-CN/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">发送表单数据</a>。</p> + +<h2 id="设计表单">设计表单</h2> + +<p>在开始编写代码之前,最好先退一步,花点时间考虑一下您的表单。设计一个快速的模型将帮助您定义您想要询问用户的正确的数据集。从用户体验(UX)的角度来看,要记住:表单越大,失去用户的风险就越大。保持简单,保持专注:只要求必要的数据。在构建站点或应用程序时,设计表单是非常重要的一步。这超出了本文的范围,涵盖了表单的用户体验,但是如果您想深入了解这个主题,您应该阅读下面的文章:</p> + +<ul> + <li>杂志<Smashing Magazine>中有<a href="http://uxdesign.smashingmagazine.com/tag/forms/">很好的关于表单用户体验的文章</a>,或许其中最重要的应该是他们的<a href="http://uxdesign.smashingmagazine.com/2011/11/08/extensive-guide-web-form-usability/" rel="external" title="http://uxdesign.smashingmagazine.com/2011/11/08/extensive-guide-web-form-usability/">Extensive Guide To Web Form Usability</a>.</li> + <li>UXMatters 也是一个非常有思想的资源,从基本的<a href="http://www.uxmatters.com/mt/archives/2012/05/7-basic-best-practices-for-buttons.php" rel="拓展" title="http://www.uxmatters.com/mt/archives/2012/05/7-basic-best-practices-for-buttons.php">最佳实践</a>到复杂的问题如<a href="https://www.uxmatters.com/mt/archives/2010/03/pagination-in-web-forms-evaluating-the-effectiveness-of-web-forms.php">多页表单</a>,都有很好的建议。</li> +</ul> + +<p>在本文中,我们将构建一个简单的联系人表单。让我们做一个粗略的草图。</p> + +<p><img alt="The form to build, roughly sketch" src="/files/4579/form-sketch-low.jpg" style="border-style: solid; border-width: 1px; height: 352px; width: 400px;"></p> + +<p>我们的表单将包含三个文本字段和一个按钮。我们向用户询问他们的姓名、电子邮件和他们想要发送的信息。点击这个按钮将把他们的数据发送到一个web服务器。</p> + +<h2 id="主动学习使用HTML实现我们的表单">主动学习:使用HTML实现我们的表单</h2> + +<p>好了,现在我们准备进入HTML代码并对表单进行编码。为了构建我们的联系人表单,我们将使用以下HTML元素:{{HTMLElement("form")}}, {{HTMLElement("label")}}, {{HTMLElement("input")}}, {{HTMLElement("textarea")}}, and {{HTMLElement("button")}}.</p> + +<p>在进一步讨论之前,先创建一个<a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">简单HTML模板</a>的本地副本—您将在这里输入您的表单HTML。</p> + +<h3 id="HTMLElementform_元素">{{HTMLElement("form")}} 元素</h3> + +<p>所有HTML表单都以一个{{HTMLElement("form")}}元素开始:</p> + +<pre class="brush:html; notranslate"><form action="/my-handling-form-page" method="post"> + +</form></pre> + +<p>这个元素正式定义了一个表单。就像{{HTMLElement("div")}}元素或{{HTMLElement("p")}}元素,它是一个容器元素,但它也支持一些特定的属性来配置表单的行为方式。它的所有属性都是可选的,但实践中最好至少要设置<code>action</code>属性和<code>method</code>属性。</p> + +<ul> + <li><code>action</code> 属性定义了在提交表单时,应该把所收集的数据送给谁(/那个模块)(URL)去处理。.</li> + <li> <code>method</code> 属性定义了发送数据的HTTP方法(它可以是“get”或“post”).</li> +</ul> + +<div class="note"> +<p><strong>注意:</strong>如果您想深入了解这些属性是如何工作的,那么将在<a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">发送表单数据</a>文章中详细说明。</p> +</div> + +<p>现在,将上面的{{htmlelement("form")}} 元素添加到您的HTML主体中</p> + +<h3 id="HTMLelementlabel_HTMLelementinput_和_HTMLelementtextarea_元素">{{HTMLelement("label")}}, {{HTMLelement("input")}} 和 {{HTMLelement("textarea")}} 元素</h3> + +<p>我们的联系人表单非常简单,包含三个文本字段,每个字段都有一个标签。该名称的输入字段将是一个基本的单行文本字段,电子邮件的输入字段将是一个只接受电子邮件地址的单行文本字段,而消息的输入字段将是一个基本的多行文本字段。</p> + +<p>就HTML代码而言,我们需要如下的东西来实现这些表单小部件:</p> + +<pre class="brush:html; notranslate"><form action="/my-handling-form-page" method="post"> +<code> <div> + <label for="name">Name:</label> + <input type="text" id="name"> + </div> + <div> + <label for="mail">E-mail:</label> + <input type="email" id="mail"> + </div> + <div> + <label for="msg">Message:</label> + <textarea id="msg"></textarea> + </div> +</form></code></pre> + +<p>更新您的表单代码,使其看起来像上面的代码。</p> + +<p>使用{{HTMLElement("div")}} 元素可以使我们更加方便地构造我们自己的代码,并且更容易样式化(参见本文后面的文章)。注意在所有{{HTMLElement("label")}}元素上使用<code>for</code>属性;它是将标签链接到表单小部件的一种正规方式。这个属性引用对应的小部件的<code>id</code>。这样做有一些好处。最明显的一个好处是允许用户单击标签以激活相应的小部件。如果您想更好地理解这个属性的其他好处,您可以找到<a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/How_to_structure_an_HTML_form">如何构造HTML表单的详细信息</a>。</p> + +<p>在 {{HTMLElement("input")}}元素中,最重要的属性是<code>type</code> 属性。这个属性非常重要,因为它定义了{{HTMLElement("input")}}属性的行为方式。它可以从根本上改变元素,所以要注意它。稍后您将在<a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Forms/The_native_form_widgets">原生表单控件</a>文章中找到更多关于此的内容。</p> + +<ul> + <li>在我们的简单示例中,我们使用值 <code>text</code> 作为第一个输入——这个属性的默认值。它表示一个基本的单行文本字段,接受任何类型的文本输入。</li> + <li>对于第二个输入,我们使用值<code>email</code>,它定义了一个只接受格式正确的电子邮件地址的单行文本字段。这会将一个基本的文本字段转换为一种“智能”字段,该字段将对用户输入的数据进行一些检查。在稍后的表单数据验证文章中,您将了解到更多关于<a href="https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Forms/Data_form_validation">表单验证</a>的信息。</li> +</ul> + +<p>最后但同样重要的是,要注意<code><input></code> 和 <code><textarea></textarea></code>的语法。这是HTML的一个奇怪之处。 <code><input></code> 标签是一个空元素,这意味着它不需要关闭标签。相反, {{HTMLElement("textarea")}}不是一个空元素,因此必须使用适当的结束标记来关闭它。这对HTML表单的特定特性有影响:定义默认值的方式。要定义{{HTMLElement("input")}}的默认值,你必须使用<code>value</code> 属性,如下所示:</p> + +<pre class="html notranslate"><input type="text" value="by default this element is filled with this text" /></pre> + +<p>相反,如果您想定义{{HTMLElement("textarea")}}的默认值,您只需在{{HTMLElement("textarea")}}元素的开始和结束标记之间放置默认值,就像这样:</p> + +<pre class="html notranslate"><textarea>by default this element is filled with this text</textarea></pre> + +<h3 id="HTMLelementbutton_元素">{{HTMLelement("button")}} 元素</h3> + +<p>我们的表格已经快准备好了,我们只需要再添加一个按钮,让用户在填写完表单后发送他们的数据。这是通过使用 {{HTMLelement("button")}} 元素完成的。在 <code></form>这个结束</code>标签上方添加以下内容:</p> + +<pre class="brush:html; notranslate"><div class="button"> + <button type="submit">Send your message</button> +</div> +</pre> + +<p>您会看到{{htmlelement("button")}}元素也接受一个 <code>type</code>属性,它接受<code>submit</code>, <code>reset</code>或者 <code>button</code> 三个值中的任一个。</p> + +<ul> + <li>单击 <code>type</code> 属性定义为 <code>submit</code> 值(也是默认值)的按钮会发送表单的数据到{{HTMLElement("form")}}元素的<code>action</code> 属性所定义的网页。</li> + <li>单击 <code>type</code> 属性定义为 <code>reset</code> 值的按钮 将所有表单小部件重新设置为它们的默认值。从用户体验的角度来看,这被认为是一种糟糕的做法。</li> + <li>单击 <code>type</code> 属性定义为 <code>button</code> 值的按钮……不会发生任何事!这听起来很傻,但是用JavaScript构建定制按钮非常有用。 </li> +</ul> + +<div class="note"> +<p><strong>注意:</strong>您还可以使用相应类型的 {{HTMLElement("input")}}元素来生成一个按钮,如 <code><input type="submit"></code>。{{htmlelement("button")}}元素的主要优点是, {{HTMLElement("input")}}元素只允许纯文本作为其标签,而{{htmlelement("button")}}元素允许完整的HTML内容,允许更复杂、更有创意的按钮文本。</p> +</div> + +<h2 id="基本表单样式">基本表单样式</h2> + +<p>现在您已经完成了表单的HTML代码,尝试保存它并在浏览器中查看它。<br> + 现在,你会看到它看起来很丑。</p> + +<p><img alt="" src="/files/4049/form-no-style.png" style="height: 170px; width: 534px;"></p> + +<div class="note"> +<p><strong>注意:</strong> 如果你怀疑你的HTML代码不对,试着把它和我们完成的例子进行比较 —— <a href="https://github.com/mdn/learning-area/blob/master/html/forms/your-first-HTML-form/first-form.html">first-form.html</a> (你也可以观看<a href="https://mdn.github.io/learning-area/html/forms/your-first-HTML-form/first-form.html">预览版</a>)。</p> +</div> + +<p>如何排布好表单是公认的难点。这超出了本文的讨论范围,所以现在我们只需要让您添加一些CSS来让它看起来很好。</p> + +<p>首先,在您的HTML头部中添加一个 {{htmlelement("style")}}元素。应该是这样的:</p> + +<pre class="brush:html; notranslate"><style> + +</style></pre> + +<p>在样式标签中,添加如下的CSS,如下所示:</p> + +<pre class="brush:css; notranslate">form { + /* 居中表单 */ + margin: 0 auto; + width: 400px; + /* 显示表单的轮廓 */ + padding: 1em; + border: 1px solid #CCC; + border-radius: 1em; +} + +ul { + list-style: none; + padding: 0; + margin: 0; +} + +form li + li { + margin-top: 1em; +} + +label { + /* 确保所有label大小相同并正确对齐 */ + display: inline-block; + width: 90px; + text-align: right; +} + +input, textarea { + /* 确保所有文本输入框字体相同 + textarea默认是等宽字体 */ + font: 1em sans-serif; + + /* 使所有文本输入框大小相同 */ + width: 300px; + box-sizing: border-box; + + /* 调整文本输入框的边框样式 */ + border: 1px solid #999; +} + +input:focus, textarea:focus { + /* 给激活的元素一点高亮效果 */ + border-color: #000; +} + +textarea { + /* 使多行文本输入框和它们的label正确对齐 */ + vertical-align: top; + + /* 给文本留下足够的空间 */ + height: 5em; +} + +.button { + /* 把按钮放到和文本输入框一样的位置 */ + padding-left: 90px; /* 和label的大小一样 */ +} + +button { + /* 这个外边距的大小与label和文本输入框之间的间距差不多 */ + margin-left: .5em; +}</pre> + +<p>现在,它看起来没那么丑了。</p> + +<p><img alt="" src="https://developer.mozilla.org/files/4051/form-style.png"></p> + +<div class="note"> +<p><strong>注意</strong>: 你可以在GitHub上的这里找到它 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/your-first-HTML-form/first-form-styled.html">first-form-styled.html</a> (<a href="https://mdn.github.io/learning-area/html/forms/your-first-HTML-form/first-form-styled.html">也可以在这儿看运行结果</a>).</p> +</div> + +<h2 id="向您的web服务器发送表单数据">向您的web服务器发送表单数据</h2> + +<p>最后一部分,也许是最棘手的部分,是在服务器端处理表单数据。如前所述,大多数时候HTML表单是向用户请求数据并将其发送到web服务器的一种方便的方式。</p> + +<p>{{HTMLelement("form")}} 元素将定义如何通过<code>action</code> 属性和 <code>method</code>属性来发送数据的位置和方式。</p> + +<p>但这还不够。我们还需要为我们的数据提供一个名称。这些名字对双方都很重要:在浏览器端,它告诉浏览器给数据各自哪个名称,在服务器端,它允许服务器按名称处理每个数据块。</p> + +<p>要将数据命名为表单,您需要在每个表单小部件上使用 <code>name</code> 属性来收集特定的数据块。让我们再来看看我们的表单代码:</p> + +<pre class="brush:html; notranslate"><form action="/my-handling-form-page" method="post"> + <div> + <label for="name">Name:</label> + <input type="text" id="name" name="user_name"> + </div> + <div> + <label for="mail">E-mail:</label> + <input type="email" id="mail" name="user_email"> + </div> + <div> + <label for="msg">Message:</label> + <textarea id="msg" name="user_message"></textarea> + </div> + + ...</pre> + +<p>在我们的例子中,表单会发送三个已命名的数据块 "<code>user_name</code>", "<code>user_email</code>", 和 "<code>user_message</code>"。这些数据将用使用<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST">HTTP <code>POST</code></a> 方法,把信息发送到URL为 "<code>/my-handling-form-page</code>"目录下。</p> + +<p>在服务器端,位于URL"<code>/my-handling-form-page</code>" 上的脚本将接收的数据作为HTTP请求中包含的3个键/值项的列表。这个脚本处理这些数据的方式取决于您。每个服务器端语言(PHP、Python、Ruby、Java、c等等)都有自己的机制。深入到这个主题已经超出了本指南的范围,但是如果您想了解更多,我们已经在<a href="/zh-CN/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data">发送表单数据</a>文章中提供了一些示例。 </p> + +<h2 id="总结">总结</h2> + +<p>祝贺您,您已经构建了您的第一个HTML表单。它看起来就像这样:</p> + +<p>{{ EmbedLiveSample('A_simple_form', '100%', '240', '', 'Learn/HTML/Forms/Your_first_HTML_form/Example') }}</p> + +<p>然而,这仅仅是开始,现在是时候深入研究了。HTML表单比我们在这里看到的要强大得多,本指南的其他文章将帮助您掌握其余部分。</p> + +<p>{{NextMenu("Learn/HTML/Forms/How_to_structure_an_HTML_form", "Learn/HTML/Forms")}}</p> |