【Web 表单】与用户数据打交道-1(mdn笔记)

d72944d5424f5c04a61a33c8fa9b6e77.png

bcf73747cfa55d255642f72eff504b32.png

0. Web 表单指南

我们将介绍 Web 表单的各个方面:HTML 结构、样式、验证表单数据,以及提交数据到服务器。

基本指南

你的第一个表单

第一次创建 HTML 表单的经验,包括设计一个简单表单、使用正确的 HTML 元素实现它、通过 CSS 添加一些非常简单的样式,以及如何将数据发送到服务器。

如何构造 HTML 表单

用于为表单的不同部分提供结构和意义的元素。

不同的表单控件

原生表单控件

了解原始 HTML <input> 元素的类型开始,同时学习在收集不同类型数据时可用的选择

HTML5 input 的类型

深入挖掘 <input> 元素,了解 HTML5 发布时提供的其他 input 类型,以及它们提供的各种 UI 控件和数据收集增强功能。此外,我们可以了解 <output> 元素。

其他表单控件

接下来,我们学习所有非 <input> 表单控件,以及相关的工具,如:<select>、<textarea>、<meter> 和 <progress>。

表单样式指南

HTML 表单样式

使用 CSS 为表单赋予样式,包括可能需要了解的基本样式任务的所有基础知识。

高级表单样式

一些更高级的表单样式技术,这些技术需要在处理一些更难以设置样式的元素时使用。

UI 伪类

UI 伪类的介绍,使 HTML 表单控件能够根据当前状态进行定位。

验证和提交表单数据

客户端表单验证

需要确保用户填写表单的数据格式是正确的,以在后续流程中正确处理它,而且它不会破坏我们的应用程序。
帮助用户正确填写表单,让他们在使用应用程序时不会感到困扰。表单验证可以帮助我们实现这些目标.

发送表单数据

讨论当用户提交一个表单时,会发生什么情况.

高级指南

如何构建自定义表单控件

在某些情况下,可能出于样式或功能的原因,原生表单部件无法提供你所需要的东西。在这种情况下,你可能需要使用原生 HTML 构建自己的表单小部件。

通过 JavaScript 发送表单

本文将讨论如何使用表单来构建 HTTP 请求,并通过定制的 JavaScript 发送它,而不是标准的表单提交。

表单控件的 CSS 属性兼容性表

确定 CSS 属性与表单元素的兼容性关系。

1. 创建我的第一个表单

1.1 web 表单是什么?

web 表单是用户和 web 站点或应用程序之间交互的主要内容之一。它们允许用户输入数据,大多数情况下会将数据发送到 web 服务器进行处理和存储。或者在客户端使用某种方式立刻更新界面。

web 表单是由一个或多个表单控件(有时称为小部件),以及一些有助于构建整个表单的附加元素组成——通常被称为 HTML 表单
这些控件可以是文本字段(单行或多行)、选择框、按钮、复选框或单选按钮,大部分是使用 <input> 元素创建的,尽管还有一些其他元素需要学习。

还可对表单控件进行编程,以强制指定输入的格式和值(表单验证),并与文本标签配对,向有视力障碍的用户描述其用途。

1.2 设计表单

定义你想要询问用户的正确的数据集。只要求必要的数据。

  • UXMatters 也是一个非常周到的资源,从基本的最佳实践到复杂的问题如多页表单,都有很好的建议。

ea2f1fcbf98258dab6853343a0d3fd4a.jpeg

我们将构建一个简单的联系人表单:做一个粗略的草图。表单将包含三个文本字段和一个按钮。向用户询问他们的姓名、电子邮件和他们想要发送的信息。点击这个按钮将把他们的数据发送到一个 web 服务器。

1.3 主动学习:使用 HTML 实现我们的表单

我们将使用以下 HTML 元素:<form>、<label>、<input>、<textarea> 和 <button>。

<form> 元素
所有表单都以一个 <form> 元素开始:

<form action="/my-handling-form-page" method="post"></form>

它支持一些特定的属性来配置表单的行为方式.所有属性都是可选的,但实践中最好至少要设置 action 属性和 method 属性

  • action 属性定义了在提交表单时,应该把所收集的数据送给谁(URL)去处理

  • method 属性定义了发送数据的 HTTP 方法(通常是 get 或 post)。

将上面的 <form> 元素添加到你的 HTML <body> 中。

<label>、<input> 和 <textarea> 元素
我们的联系人表单非常简单,包含三个文本字段,每个字段都有一个标签。

  • 名称的输入字段将是一个基本的单行文本字段。

  • 电子邮件的输入字段将是一个只接受电子邮件地址的单行文本字段

  • 消息的输入字段将是一个 <textarea>——基本的多行文本字段。

<form action="/my-handling-form-page" method="post">
  <ul>
    <li>
      <label for="name">Name:</label>
      <input type="text" id="name" name="user_name" />
    </li>
    <li>
      <label for="mail">E-mail:</label>
      <input type="email" id="mail" name="user_email" />
    </li>
    <li>
      <label for="msg">Message:</label>
      <textarea id="msg" name="user_message"></textarea>
    </li>
  </ul>
</form>

使用 <li> 元素可以使我们更加方便地构造我们自己的代码,并且更容易样式化.
为了可用性和无障碍,我们为每个表单控件包含一个明确的标签。
注意在所有 <label> 元素上使用 for (en-US) 属性;它是将标签链接到表单控件的一种正规方式。这个属性引用对应的表单控件的 id

这样做有一些好处。最明显的一个好处是允许用户单击标签以激活相应的表单控件,它还有助于使用屏幕阅读器的用户读取名称。

在 <input> 元素中,最重要的属性是 type 属性。这个属性非常重要,因为它定义了 <input> 属性的行为方式

  • 值 text 表示一个基本的单行文本字段,接受任何类型的文本输入。

  • 值 email 定义了一个只接受格式正确的电子邮件地址的单行文本字段。

注意 <input> 和 <textarea> 的语法:<input> 标签是一个空元素,这意味着它不需要关闭标签。相反,<textarea> 不是一个空元素,因此必须使用适当的结束标记来关闭它。

要定义 <input> 的默认值,你必须使用 value 属性

<input type="text" value="by default this element is filled with this text" />

相反,如果你想定义 <textarea> 的默认值,你只需在 <textarea> 元素的开始和结束标记之间放置默认值,就像这样:

<textarea>
by default this element is filled with this text
</textarea>

<button> 元素
添加一个按钮,让用户在填写完表单后发送他们的数据。

<li class="button">
  <button type="submit">Send your message</button>
</li>

<button> 元素也接受一个 type属性,它接受 submit、reset 或者 button 三个值中的任一个

  • 单击 type 属性定义为 submit 值(也是默认值)的按钮会发送表单的数据到 <form> 元素的 action 属性所定义的网页。

  • 单击type 属性定义为 reset 值 的按钮 将所有表单小部件重新设置为它们的默认值。从用户体验的角度来看,这被认为是一种糟糕的做法。

  • 单击 type 属性定义为 button 值的按钮,**不会发生任何事!**这听起来很傻,但是用 JavaScript 构建定制按钮非常有用。

备注:你还可以使用相应类型的 <input> 元素来生成一个按钮,如 <input type="submit">。<button> 元素的主要优点是,<input> 元素只允许纯文本作为其标签,而 <button> 元素允许完整的 HTML 内容,允许更复杂、更有创意的按钮内容。

1.4 基本表单样式

添加一些 CSS 来让它看起来很好:

2f6ac8d74b2d5e81cafb1fe34b6811c6.png

<style>
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; /* 设置表单中相邻两个列表项之间的上边距为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: 0.5em;
}
</style>

1.5 向你的 web 服务器发送表单数据

<form> 元素通过 action 属性和 method 属性来定义发送数据的位置和方式。
需要为每个表单控件提供 name 属性。这些名称对客户端和服务端都很重要:
要命名表单中的数据,你需要在每个表单小部件上使用 name 属性来收集特定的数据块

<form action="/my-handling-form-page" method="post">
  <ul>
    <li>
      <label for="name">Name:</label>
      <input type="text" id="name" name="user_name" />
    </li>
    <li>
      <label for="mail">E-mail:</label>
      <input type="email" id="mail" name="user_email" />
    </li>
    <li>
      <label for="msg">Message:</label>
      <textarea id="msg" name="user_message"></textarea>
    </li>

    …
  </ul>
</form>

表单会发送三个已命名的数据块“user_name”、“user_email”和“user_message”。这些数据将用使用 HTTP POST 方法,把信息发送到 URL 为“/my-handling-form-page”的目录下

服务器端,位于 URL“/my-handling-form-page”上的脚本将接收的数据作为 HTTP 请求中包含的 3 个键/值项的列表
每个服务器端语言(PHP、Python、Ruby、Java、c 等等)都有自己的表单数据处理机制

2. 如何构造 HTML 表单

2.1 <form> 元素

<form> 元素按照一定的格式定义了表单和确定表单行为的属性。

备注:严格禁止在一个表单内嵌套另一个表单。嵌套会使表单的行为不可预知,而这取决于正在使用的浏览器。

2.2 <fieldset> 和 <legend> 元素

<fieldset>元素是一种方便的用于创建具有相同目的的小部件组的方式,出于样式和语义目的。

可以在<fieldset>开口标签后加上一个 <legend>元素来给<fieldset> 标上标签。<legend>的文本内容正式地描述了<fieldset>里所含有部件的用途

许多辅助技术将使用<legend> 元素,就好像它是相应的 <fieldset> 元素里每个部件的标签的一部分。
例如,在说出每个小部件的标签之前,像Jaws或NVDA这样的屏幕阅读器朗读出 legend 的内容

<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>

03a481e6f89633e0e48fe9f91269687e.png

这个表单中包含了一个 fieldset 元素,用于将相关的表单控件分组legend 元素定义了 fieldset 的标题。表单中有三个 input 元素,类型都是 radio,表示它们是单选按钮。这些单选按钮的 name 属性都是 size,表示它们属于同一组,用户只能选择其中一个。每个单选按钮都有一个对应的 label 元素,用于描述该按钮的含义。for 属性的值与对应的单选按钮的 id 属性相同,表示这个标签与该单选按钮相关联。

当阅读上述表格时,屏幕阅读器将会读第一个小部件“Fruit juice size small”,“Fruit juice size medium”为第二个,“Fruit juice size large”为第三个。

每当您有一组单选按钮时,您应该将它们嵌套在<fieldset>元素中

2.3 <label> 元素

<label> 元素是为 HTML 表单小部件定义标签的正式方法。当实现的恰当时,屏幕阅读器会连同有关的说明和表单元素的标签一起朗读.

<label for="name">Name:</label> <input type="text" id="name" name="user_name" />

<label> 标签与 <input> 通过他们各自的for 属性和 id 属性正确相关联,这样,屏幕阅读器会读出诸如“Name, edit text”之类的东西。如果标签没有正确设置,屏幕阅读器只会读出“Edit text blank”之类的东西.

注意,一个小部件可以嵌套在它的元素中,就像这样:

<label for="name">
  Name: <input type="text" id="name" name="user_name" />
</label>

标签也可点击!
在所有浏览器中单击标签来激活相应的小部件.

50fd0d938fe85b09d3d697fd92cb7416.png

<!--单击标签选中复选框 用户可以同时选择多个复选框。-->
<form>
  <p>
    <input type="checkbox" id="taste_1" name="taste_cherry" value="1" /> <!-- 创建一个复选框 -->
    <label for="taste_1">I like cherry</label> <!-- 为复选框添加标签 -->
  </p>
  <p>
    <input type="checkbox" id="taste_2" name="taste_banana" value="2" /> <!-- 创建另一个复选框 -->
    <label for="taste_2">I like banana</label> <!-- 为复选框添加标签 -->
  </p>
</form>

多个标签
在多个标签的情况下,您应该将一个小部件和它的标签嵌套在一个<label>元素中。

18abd7b423cc6158fea8e5c858fef96e.png

<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>

第一种方式使用了两个 label 元素,一个用于描述输入框的含义,另一个用于表示这是一个必填字段。但是这种方式不够简洁,也不符合语义。

第二种方式在一个 label 元素内包含了文本、输入框和必填标记。这种方式更加简洁,也更符合语义。

第三种方式在一个 label 元素内包含了文本和必填标记,输入框单独放在外面。这种方式更加简洁,也更符合语义。

总的来说,第三种方式可能是最好的选择。

  • 在第一个例子中,标签根本没有和input一起被念出来——读出来的只是“edit the blank”,和单独被念出的标签。多个元素会使屏幕阅读器迷惑。

  • 在第二个例子中,事情变得清晰一点了——标签和输入一起,读出的是“name star name edit text”,但标签仍然是单独读出的。这还是有点令人困惑,但这次还是稍微好一点了,因为input和label联系起来了。

  • 第三个例子是最好的——标签是一起读出的,标签和输入读出的是“name star edit text”。

2.4 用于表单的通用 HTML 结构

用 <div>元素 包装标签和它的小部件是很常见的做法。<p>元素也经常被使用,HTML 列表也是如此.(后者在构造多个复选框或单选按钮时最为常见)。

除了<fieldset>元素之外,使用 HTML 标题(例如,<h1> (en-US)、<h2> (en-US))和分段(如<section>)来构造一个复杂的表单也是一种常见的做法。

包含了从功能上划分开并分别包含在<section>元素中的部分,以及一个<fieldset>来包含单选按钮.

自主学习:构建一个表单结构
一个支付表单:

4592456b1331179b9f78b72ef3925730.png

<!DOCTYPE html> <!-- 声明文档类型为 HTML5 -->
<html lang="en-us"> <!-- 根元素,定义页面语言为美式英语 -->
  <head> <!-- 文档头部,包含文档元数据 -->
    <meta charset="utf-8"> <!-- 定义字符编码为 utf-8 -->
    <meta name="viewport" content="width=device-width"> <!-- 定义视口宽度等于设备宽度 -->
    <title>Payment form example</title> <!-- 定义文档标题 -->
    <link href="payment-form.css" rel="stylesheet"> <!-- 链接外部样式表 -->
  </head>

<body> <!-- 文档主体 -->
    <form method="post"> <!-- 定义表单,提交方式为 post -->
        <h1>Payment form</h1> <!-- 标题一级 -->
        <p>Required fields are followed by <strong><span aria-label="required">*</span></strong>.</p> <!-- 段落,说明必填字段后面有 * 号 -->
        <section> <!-- 定义文档中的节 -->
            <h2>Contact information</h2> <!-- 标题二级,联系信息 -->
            <fieldset> <!-- 定义字段集,用于将相关表单控件分组 -->
              <legend>Title</legend> <!-- 定义字段集的标题 -->
              <ul> <!-- 无序列表 -->
                  <li> <!-- 列表项 -->
                    <label for="title_1"> <!-- 定义标签,与 id 为 title_1 的表单控件相关联 -->
                      <input type="radio" id="title_1" name="title" value="A"> <!-- 单选按钮,id 为 title_1,name 为 title,值为 A -->
                      Ace
                    </label>
                  </li>
                  <li>
                    <label for="title_2">
                      <input type="radio" id="title_2" name="title" value="K" ><!-- 单选按钮,id 为 title_2,name 为 title,值为 K-->
                      King
                    </label>
                  </li>
                  <li>
                    <label for="title_3">
                      <input type="radio" id="title_3" name="title" value="Q"><!-- 单选按钮,id 为 title_3,name 为 title,值为 Q-->
                      Queen
                    </label>
                  </li>
              </ul>
            </fieldset>
            <p>
              <label for="name">
                <span>Name: </span><!-- 名字标签-->
                <strong><span aria-label="required">*</span></strong><!-- 必填标记-->
              </label>
              <input type="text" id="name" name="username" required><!-- 文本输入框,id 为 name, name 为 username, 必填-->
            </p>
            <p>
              <label for="mail">
                <span>E-mail: </span><!-- 邮箱标签-->
              <strong><span aria-label="required">*</span></strong><!-- 必填标记-->
            </label>
            <input type="email" id="mail" name="usermail" required><!-- 邮箱输入框,id 为 mail, name 为 usermail, 必填-->
          </p>
          <p>
            <label for="pwd">
              <span>Password: </span><!-- 密码标签-->
              <strong><span aria-label="required">*</span></strong><!-- 必填标记-->
            </label>
            <input type="password" id="pwd" name="password" required><!-- 密码输入框,id 为 pwd, name 为 password, 必填-->
          </p>
      </section>
      <section> <!-- 定义文档中的节 -->
          <h2>Payment information</h2> <!-- 标题二级,支付信息 -->
          <p>
            <label for="card">
              <span>Card type:</span><!-- 卡类型标签-->
            </label>
            <select id="card" name="usercard"><!-- 下拉选择框,id 为 card, name 为 usercard -->
              <option value="visa">Visa</option><!-- 选项,值为 visa -->
              <option value="mc">Mastercard</option><!-- 选项,值为 mc -->
              <option value="amex">American Express</option><!-- 选项,值为 amex -->
            </select>
          </p>
          <p>
            <label for="number">
              <span>Card number:</span><!-- 卡号标签-->
              <strong><span aria-label="required">*</span></strong><!-- 必填标记-->
            </label>
            <input type="tel" id="number" name="cardnumber" required><!-- 电话输入框,id 为 number, name 为 cardnumber, 必填-->
          </p>
          <p>
            <label for="expiration">
              <span>Expiration date:</span><!-- 过期日期标签-->
              <strong><span aria-label="required">*</span></strong><!-- 必填标记-->
            </label>
            <input type="text" id="expiration" required placeholder="MM/YY" pattern="^(0[1-9]|1[0-2])\/([0-9]{2})$"><!-- 文本输入框,id 为 expiration, 必填, 占位符 MM/YY, 验证模式 ^(0[1-9]|1[0-2])\/([0-9]{2})$ -->
          </p>
      </section>
      <section> <!-- 定义文档中的节 -->
        <p>
          <button type=“submit”>Validate the payment</button> <!-- 提交按钮,文本为 Validate the payment --> 
        </p> 
      </section> 
    </form> 
  </body>
</html> <!-- 结束根元素 -->

payment-form.css样式表:

h1 {
    margin-top: 0; /* 设置 h1 元素的上边距为 0 */
}

ul {
    margin: 0; /* 设置 ul 元素的外边距为 0 */
    padding: 0; /* 设置 ul 元素的内边距为 0 */
    list-style: none; /* 设置 ul 元素的列表样式为无 */
}

form {
    margin: 0 auto; /* 设置 form 元素的外边距为自动居中 */
    width: 400px; /* 设置 form 元素的宽度为 400 像素 */
    padding: 1em; /* 设置 form 元素的内边距为 1 em */
    border: 1px solid #CCC; /* 设置 form 元素的边框宽度为 1 像素,样式为实线,颜色为 #CCC */
    border-radius: 1em; /* 设置 form 元素的边框圆角半径为 1 em */
}

div+div {
    margin-top: 1em; /* 设置紧邻 div 元素之后的 div 元素的上外边距为 1 em */
}

label span {
    display: inline-block; /* 设置 label 内部 span 元素的显示方式为行内块级元素 */
    width: 120px; /* 设置 label 内部 span 元素的宽度为 120 像素 */
    text-align: right; /* 设置 label 内部 span 元素的文本对齐方式为右对齐 */
}

input, textarea {
    font: 1em sans-serif; /* 设置 input 和 textarea 元素的字体大小为 1 em,字体族为无衬线字体 */
    width: 250px; /* 设置 input 和 textarea 元素的宽度为 250 像素 */
    box-sizing: border-box; /* 设置 input 和 textarea 元素的盒模型计算方式为 border-box */
    border: 1px solid #999; /* 设置 input 和 textarea 元素的边框宽度为 1 像素,样式为实线,颜色为 #999 */
}

input[type=checkbox], input[type=radio] {
    width: auto; /* 设置 input[type=checkbox] 和 input[type=radio] 的宽度自动计算 */
    border: none; /* 取消 input[type=checkbox] 和 input[type=radio] 的边框 */
}

input:focus, textarea:focus {
    border-color: #000; /* 设置获得焦点时 input 和 textarea 的边框颜色为 #000 */
}

textarea {
    vertical-align: top; /* 设置 textarea 的垂直对齐方式为顶部对齐 */
    height: 5em; /* 设置 textarea 的高度为 5 em */
    resize: vertical; /* 设置 textarea 可以垂直调整大小 */
}

fieldset {
    width: 250px; /* 设置 fieldset 元素的宽度为 250 像素 */
    box-sizing: border-box; /* 设置 fieldset 元素的盒模型计算方式为 border-box */
    margin-right: 136px; /* 设置 fieldset 元素的右外边距为 136 像素 */
    border: 1px solid #999; /* 设置 fieldset 元素的边框宽度为 1 像素,样式为实线,颜色为 #999 */
}

button {
    margin: 20px 0 0 124px; /* 设置 button 元素的外边距,上边距为 20 像素,左边距为 124 像素 */
}

label {
  position: relative; /* 设置 label 元素的定位方式为相对定位 */
}

3. 原生表单部件

我们将详细研究不同表单部件的功能,查看了哪些选项可用于收集不同类型的数据。
备注:widget 在本页面中被统一翻译为部件,但在其他地方可能也被译为组件。
你可能已经遇见过了一些表单元素,包括:<form>、<fieldset>、<legend>、<textarea>、<label>、<button> 和 <input>。这篇文章提到了:

  • 常见的输入(input)类型元素button、checkbox、file、hidden、image、password、radio、reset、submit 和 text

  • 所有表单部件共有的一些属性。

3.1 文本输入框

文本输入框是最基本的表单小部件。

备注:HTML 表单文本字段是简单的纯文本输入控件。这意味着您不能将它们用作富文本编辑(粗体、斜体等)。你遇到的所有富文本编辑器都是使用 HTML、CSS 和 JavaScript 所创建的自定义小部件。

文本框都有一些通用规范:

  • 它们可以被标记为 readonly(用户不能修改输入值)甚至是 disabled(输入值永远不会与表单数据的其余部分一起发送)。

  • 它们可以有一个 placeholder;这是文本输入框中出现的文本,用来简略描述输入框的目的

  • 它们可以 使用 size (en-US)(框的物理尺寸)和 maxlength (en-US)(可以输入的最大字符数) 进行限制。

  • 如果浏览器支持的话,它们可以从拼写检查(使用 spellcheck 属性)中获益。

备注:<input> 元素是如此特别因为它可以通过简单设置 type 属性,来接收多种类型的数据。它被用于创建大多数类型的表单小部件,包括单行文本字段、没有文本输入的控件、时间和日期控件和按钮。

单行文本框
使用 type 属性值被设置为 text 的 <input> 元素创建一个单行文本框.type默认设置为 text.在浏览器中是未知的情况下(比如你指定 type="date",但是浏览器不支持原生日期选择器),属性值也将会回落到 text。

09dc2d077151e38ce8de7ac8d98a9331.png

<!DOCTYPE html> <!-- 声明文档类型为 HTML5 -->
<html lang="en-us"> <!-- 根元素,定义页面语言为美式英语 -->
  <head> <!-- 文档头部,包含文档元数据 -->
    <meta charset="utf-8"> <!-- 定义字符编码为 utf-8 -->
    <meta name="viewport" content="width=device-width"> <!-- 定义视口宽度等于设备宽度 -->
    <title>Single line text field examples</title> <!-- 定义文档标题 -->
  </head>

<body> <!-- 文档主体 -->
    <form> <!-- 定义表单 -->
        <p> <!-- 段落 -->
          <label for="comment">Add a comment here:</label> <!-- 定义标签,与 id 为 comment 的表单控件相关联 -->
          <input type="text" id="comment" name="comment" value="I'm a text field"> <!-- 文本输入框,id 为 comment,name 为 comment,初始值为 I'm a text field -->
        </p>
        <p>
          <label for="email">Enter your email address:</label> <!-- 定义标签,与 id 为 email 的表单控件相关联 -->
          <input type="email" id="email" name="email" multiple> <!-- 邮箱输入框,id 为 email,name 为 email,允许多个值 -->
        </p>
        <p>
          <label for="pwd">Enter your password:</label> <!-- 定义标签,与 id 为 pwd 的表单控件相关联 -->
          <input type="password" id="pwd" name="pwd"> <!-- 密码输入框,id 为 pwd,name 为 pwd -->
        </p>
        <p>
          <label for="search">Search:</label> <!-- 定义标签,与 id 为 search 的表单控件相关联 -->
          <input type="search" id="search" name="search"> <!-- 搜索输入框,id 为 search,name 为 search -->
        </p>
        <p>
          <label for="tel">Enter your number:</label> <!-- 定义标签,与 id 为 tel 的表单控件相关联 -->
          <input type="tel" id="tel" name="tel"> <!-- 电话输入框,id 为 tel,name 为 tel -->
        </p>
        <p>
          <label for="url">Web address:</label> <!-- 定义标签,与 id 为 url 的表单控件相关联 -->
          <input type="url" id=“url” name=“url”> <!-- 网址输入框,id 为 url,name 为 url --> 
        </p> 
        <p> 
          <button type=“submit”>Submit me!</button> <!-- 提交按钮,文本为 Submit me! --> 
        </p> 
      </form> 
    </body>
</html> <!-- 结束根元素 -->

单行文本框只有一个真正的约束:如果您输入带有换行符的文本,浏览器会在发送数据之前删除这些换行符

密码框
通过设置 type 属性值为 password 来设置该类型框:

<input type="password" id="pwd" name="pwd" />

请记住,这只是一个用户界面特性;除非你安全地提交你的表单,否则它会以明文发送,这不利于安全——恶意的一方可能会截获你的数据,窃取你的密码、信用卡信息,或者你提交的其他任何东西。保护用户不受此影响的最佳方式是在安全连接上托管任何涉及表单的页面(例如:https://……地址),使得数据在发送之前就已加密。

隐藏内容
另一个原生的文本框控件是 hidden input 类型。创建对用户不可见的表单部件,但在发送表单时,会与其他的表单数据一起被发送到服务器.
例如,你可能希望向服务器提交一个时间戳,说明订单是何时产生的。因为它是隐藏的,所以用户看不到也不能简单地修改该值,它将永远不会获得焦点,屏幕阅读器也不会注意到它。

<input type="hidden" id="timestamp" name="timestamp" value="1286705410" />

如果您创建了这样一个元素,就需要设置它的 name 和 value 属性。
元素的值可以通过 JavaScript 动态设置。
hidden input 类型不应有关联的标签(label 元素)。

3.2 可选中项:复选框和单选按钮

两者都使用 checked 属性,以指示该部件的默认状态:“选中”或“未选中”。
对于大多数表单部件,一旦表单提交,所有具有 name 属性的小部件都会被发送,即使没有任何值被填。

7e8fcdf60b8a611be5e5d9cc6f5047e1.png

对于可选中项,只有在勾选时才发送它们的值。如果他们没有被勾选,就不会发送任何东西,甚至连他们的名字也没有。。而在它们被勾选且没有提供值(value)时,将会发送名字和缺省值 on。

<form> <!-- 定义表单 -->
    <fieldset> <!-- 定义字段集,用于将相关表单控件分组 -->
      <legend>Choose all the vegetables you like to eat</legend> <!-- 定义字段集的标题 -->
      <ul> <!-- 无序列表 -->
        <li> <!-- 列表项 -->
          <label for="carrots">Carrots</label> <!-- 定义标签,与 id 为 carrots 的表单控件相关联 -->
          <input type="checkbox" checked id="carrots" name="vegetable" value="carrots"> <!-- 多选框,id 为 carrots,name 为 vegetable,值为 carrots,初始选中 -->
        </li>
        <li>
          <label for="peas">Peas</label> <!-- 定义标签,与 id 为 peas 的表单控件相关联 -->
          <input type="checkbox" id="peas" name="vegetable" value="peas"> <!-- 多选框,id 为 peas,name 为 vegetable,值为 peas -->
        </li>
        <li>
          <label for="cabbage">Cabbage</label> <!-- 定义标签,与 id 为 cabbage 的表单控件相关联 -->
          <input type="checkbox" id="cabbage" name="vegetable" value="cabbage"> <!-- 多选框,id 为 cabbage,name 为 vegetable,值为 cabbage -->
        </li>
        <li>
          <label for="cauli">Cauliflower</label> <!-- 定义标签,与 id 为 cauli 的表单控件相关联 -->
          <input type="checkbox" id="cauli" name="vegetable" value="cauli"> <!-- 多选框,id 为 cauli,name 为 vegetable,值为 cauli -->
        </li>
        <li>
          <label for="broc">Broccoli</label> <!-- 定义标签,与 id 为 broc 的表单控件相关联 -->
          <input type="checkbox" id="broc" name="vegetable" value="broc"> <!-- 多选框,id 为 broc,name 为 vegetable,值为 broc -->
        </li>
      </ul>
    </fieldset>
    <fieldset> <!-- 定义字段集,用于将相关表单控件分组 -->
      <legend>What is your favorite meal?</legend> <!-- 定义字段集的标题 -->
      <ul> <!-- 无序列表 -->
        <li> <!-- 列表项 -->
          <label for="soup">Soup</label> <!-- 定义标签,与 id 为 soup 的表单控件相关联 -->
          <input type="radio" checked id="soup" name="meal" value="soup"> <!-- 单选按钮,id 为 soup,name 为 meal,值为 soup,初始选中 -->
        </li>
        <li>
          <label for="curry">Curry</label> <!-- 定义标签,与 id 为 curry 的表单控件相关联 -->
          <input type="radio" id="curry" name="meal" value="curry"> <!-- 单选按钮,id 为 curry,name 为 meal,值为 curry -->
        </li>
        <li>
          <label for="pizza">Pizza</label> <!-- 定义标签,与 id 为 pizza 的表单控件相关联 -->
          <input type="radio" id="pizza" name="meal" value="pizza"> <!-- 单选按钮,id 为 pizza,name 为 meal,值为 pizza -->
        </li>
        <li>
          <label for="tacos">Tacos</label> <!-- 定义标签,与 id 为 tacos 的表单控件相关联 -->
          <input type="radio" id="tacos" name="meal" value="tacos"> <!-- 单选按钮,id 为 tacos,name 为 meal,值为 tacos -->
        </li>
        <li>
          <label for="bolognaise">Bolognaise</label> <!-- 定义标签,与 id 为 bolognaise 的表单控件相关联 -->
          <input type="radio" id="bolognaise" name="meal" value="bolognaise"> <!-- 单选按钮,id 为 bolognaise,name 为 meal,值为 bolognaise -->
        </li>
      </ul>
    </fieldset>
</form>

复选框
使用 type 属性值为 checkbox 的 <input> 元素来创建一个复选框。

<input type="checkbox" id="questionOne" name="subscribe" value="yes" checked />

相关的复选框元素应该使用具有相同值的 name 属性
包含 checked 属性使复选框在页面加载时自动被选中

备注:任何带有 checked 属性的复选框和单选按钮在加载时都会匹配 :default 伪类,即使它们后面不再被选中。任何当前被选中的元素,都会匹配 :checked 伪类。

复选框-切换按钮 示例:

5e663b9c56506399d5e13740ac944d69.png

5ff1a73639be5c32ca9c232c4edf7dbf.png

<!DOCTYPE html> <!-- 声明文档类型为 HTML5 -->
<html lang="en-US"> <!-- 根元素,定义页面语言为美式英语 -->
  <head> <!-- 文档头部,包含文档元数据 -->
    <meta charset="utf-8"> <!-- 定义字符编码为 utf-8 -->
    <meta name="viewport" content="width=device-width"> <!-- 定义视口宽度等于设备宽度 -->
    <title>Toggle switch example</title> <!-- 定义文档标题 -->
    <style> <!-- 内联样式表 -->
      * {
        box-sizing: border-box; /* 设置所有元素的盒模型计算方式为 border-box */
      }

      li {
        width: 100px; /* 设置 li 元素的宽度为 100 像素 */
        display: flex; /* 设置 li 元素的显示方式为 flex */
        align-items: center; /* 设置 li 元素的子元素垂直居中对齐 */
        justify-content: space-around; /* 设置 li 元素的子元素水平两端对齐,中间留有空隙 */
        position: relative; /* 设置 li 元素的定位方式为相对定位 */
      }

      label {
        width: 20px; /* 设置 label 元素的宽度为 20 像素 */
        height: 20px; /* 设置 label 元素的高度为 20 像素 */
        line-height: 20px; /* 设置 label 元素的行高为 20 像素 */
        position: relative; /* 设置 label 元素的定位方式为相对定位 */
      }

      label span {
        position: absolute; /* 设置 label 内部 span 元素的定位方式为绝对定位 */
      }

      input[type="checkbox"] {
        -webkit-appearance: none; /* 取消 input[type="checkbox"] 的默认外观(针对 WebKit 内核浏览器) */
        appearance: none; /* 取消 input[type="checkbox"] 的默认外观 */
        width: 44px; /* 设置 input[type="checkbox"] 的宽度为 44 像素 */
        height: 24px; /* 设置 input[type="checkbox"] 的高度为 24 像素 */
        border-radius: 12px; /* 设置 input[type="checkbox"] 的边框圆角半径为 12 像素 */
        border: 2px solid black; /* 设置 input[type="checkbox"] 的边框宽度为 2 像素,样式为实线,颜色为黑色 */
        background: #eee; /* 设置 input[type="checkbox"] 的背景颜色为 #eee */
        transition: all 0.4s; /* 设置 input[type="checkbox"] 的所有属性变化过渡时间为 0.4 秒 */
      }

      input[type="checkbox"]::before {
        width: 16px; /* 设置 input[type="checkbox"] 的 ::before 内容的宽度为 16 像素 */
        height: 16px; /* 设置 input[type="checkbox"] 的 ::before 内容的高度为 16 像素 */
        border-radius: 9px; /* 设置 input[type="checkbox"] 的 ::before 内容的边框圆角半径为 9 像素 */
        background-color: black; /* 设置 input[type="checkbox"] 的 ::before 内容的背景颜色为黑色 */
        content: ''; /* 设置 input[type="checkbox"] 的 ::before 内容为空字符串 */
        position: absolute; /* 设置 input[type="checkbox"] 的 ::before 内容的定位方式为绝对定位 */
        top: 7px; /* 设置 input[type="checkbox"] 的 ::before 内容的上边距为 7 像素 */
        left: 16%; /* 设置 input[type="checkbox"] 的 ::before 内容的左边距为 16% */
        transition: all 0.4s; /* 设置 input[type="checkbox"] 的 ::before 内容的所有属性变化过渡时间为 0.4 秒 */
      }

      input[type="checkbox"]:checked {
        background-color: #ffaa00; /* 设置 input[type="checkbox"] 被选中时的背景颜色为 #ffaa00 */
        transition: all 0.4s; /* 设置 input[type="checkbox"] 被选中时的所有属性变化过渡时间为 0.4 秒 */
      }

      input[type="checkbox"]:checked::before {
        left: 35%; /* 设置 input[type="checkbox"] 被选中时的 ::before 内容的左边距为 35% */
        transition: all 0.4s; /* 设置 input[type="checkbox"] 被选中时的 ::before 内容的所有属性变化过渡时间为 0.4 秒 */
      }

      input[type="checkbox"] ~ label .on, input[type="checkbox"]:checked ~ label .off {
        opacity: 0; /* 设置 input[type="checkbox"] 后面的 label 内部 class 为 on 的 span 元素和 input[type="checkbox"] 被选中时后面的 label 内部 class 为 off 的 span 元素不可见 */
      }

      input[type="checkbox"] ~ label .off, input[type="checkbox"]:checked ~ label .on {
        opacity: 1; /* 设置 input[type="checkbox"] 后面的 label 内部 class 为 off 的 span 元素和 input[type="checkbox"] 被选中时后面的 label 内部 class 为 on 的 span 元素可见 */
      }

      input:focus {
        outline: 1px dotted black; /* 设置获得焦点时 input 元素的轮廓宽度为 1 像素,样式为点状,颜色为黑色 */
      }

    </style>
  </head>
  <body> <!-- 文档主体 -->
    <ul> <!-- 无序列表 -->
      <li> <!-- 列表项 -->
        <input type="checkbox" name="power" id="power"> <!-- 多选框,name 为 power,id 为 power -->
        <label for="power"><span class="on">On</span> <span class="off">Off</span></label> <!-- 定义标签,与 id 为 power 的表单控件相关联,包含两个 span 元素,分别表示开和关 -->
      </li>
    </ul>
  </body>
</html> <!-- 结束根元素 -->

单选按钮
使用 type 属性值为 radio 的 <input> 元素来创建一个单选按钮。
如果它们的 name 属性共享相同的值,那么它们将被认为属于同一组的按钮。同一组中只有一个按钮可以同时被选;这意味着当其中一个被选中时,所有其他的都将自动未选中。如果没有选中任何一个,那么整个单选按钮池就被认为处于未知状态,并且没有以表单的形式发送任何值。

3.3 按钮

在 HTML 表单中,有三种按钮:

  • Submit
    将表单数据发送到服务器。对于 button 元素,省略 type 属性(或是一个无效的 type 值)的结果就是一个提交按钮

  • Reset
    将所有表单小部件重新设置为它们的默认值。

  • Anonymous
    没有自动生效的按钮,但是可以使用 JavaScript 代码进行定制。

也可以使用 <button> 元素。它也带有 submit、reset 和 button 这几个 type 属性,与 <input> 的三种按钮行为一致。它们之间的主要区别在于 <button> 元素更易于设置样式。

备注:image input 类型同样被渲染为一个按钮。我们将在后面提到。

这是一段 HTML 代码,它定义了一个包含多种类型按钮的表单。你可以看到每一种与 <button> 对应类型等价的 <input> 类型的示例。

4a9f58eb395c23be86826548a07f636a.png

<form> <!-- 定义表单 -->
    <p> <!-- 段落 -->
      <button type="submit"> <!-- 提交按钮 -->
        This a <br><strong>submit button</strong> <!-- 按钮文本,包含换行和加粗 -->
      </button>
    </p>
    <p>
      <input type="submit" value="This is a submit button"> <!-- 提交按钮,值为 This is a submit button -->
    </p>
    <p>
      <button type="reset"> <!-- 重置按钮 -->
          This a <br><strong>reset button</strong> <!-- 按钮文本,包含换行和加粗 -->
      </button>
    </p>
    <p>
      <input type="reset" value="This is a reset button"> <!-- 重置按钮,值为 This is a reset button -->
    </p>
    <p>
      <button type="button"> <!-- 普通按钮 -->
          This an <br><strong>anonymous button</strong> <!-- 按钮文本,包含换行和加粗 -->
      </button>
    </p>
    <p>
      <input type="button" value="This is an anonymous button"> <!-- 普通按钮,值为 This is an anonymous button -->
</form>

不管您使用的是 <button> 元素还是 <input> 元素,按钮的行为都是一样的。
然而,有一些显著的不同之处:

  • <button> 元素允许您在它们的标签中使用 HTML 内容,这些内容被插入到 <button> 开始和结束的标签之间。

  • 另一方面,<input> 元素是空元素;它显示的内容需要插入到 value 属性中,因此只接受纯文本内容。

从技术上讲,使用<button>元素或<input>元素定义的按钮几乎没有区别。区别是按钮本身的标签。在<input>元素中,标签只能是字符数据,而在**<button>元素中,标签可以是 HTML,因此可以相应地进行样式化**。

图像按钮
图像按钮(image button)控件渲染的方式与 <img> 几乎完全相同。只是在用户点击它时,图像按钮的行为与提交(submit)按钮相同.
图像按钮是使用 type 属性值设置为 image 的 <input> 元素创建的。
这个元素支持与 <img> 元素相同的属性,和其他表单按钮支持的所有属性。

<input type="image" alt="Click me!" src="my-img.png" width="80" height="30" />

如果使用图像按钮来提交表单,这个小部件不会提交它的值;而是提交在图像上单击处的 X 和 Y 坐标. 坐标被发送为两个键/值对:

  • X 值键是 name 属性的值,后面是字符串“.x”。

  • Y 值键是 name 属性的值,后面是字符串“.y”。

例如,当您点击这个小部件图像坐标为 (123,456) 的位置时,它将会通过 get 方法提交。你可以看到类似的 URL:
http://foo.com?pos.x=123&pos.y=456
这是构建“热图”的一种非常方便的方式。

3.4 文件选择器

HTML 表单能够将文件发送到服务器;文件选择器小部件是用户如何选择一个或多个文件来发送的。
要创建一个文件选择器小部件,您可以使用 <input> 元素,将它的 type 属性设置为 file。被接受的文件类型可以使用 accept 属性来约束。如果您想让用户选择多个文件,那么可以通过添加 multiple 属性来实现。

示例
创建一个文件选择器,请求图形图像文件。允许用户选择多个文件。

<input type="file" name="file" id="file" accept="image/*" multiple />

在一些移动终端上,文件选择器可以访问由设备相机和麦克风直接获取的图片、视频、音频。我们只需要这样设置 accept 属性即可(分别对应相机捕获的图片、视频和麦克风获取的音频):

<input type="file" accept="image/*;capture=camera" />
<input type="file" accept="video/*;capture=camcorder" />
<input type="file" accept="audio/*;capture=microphone" />

3.5 通用属性

所有表单元素中都有一组通用属性:

属性名称 默认值 描述
autofocus (en-US) false 这个布尔属性允许您指定当页面加载时元素应该自动具有输入焦点,除非用户覆盖它,例如通过键入不同的控件。文档中只有一个与表单相关的元素可以指定这个属性。
disabled false 这个布尔属性表示用户不能与元素交互。如果没有指定这个属性,元素将从包含它的元素继承设置,例如 <fieldset>;如果没有包含在设定了 disabled 属性的元素里,那么这个元素就是可用的。
form
小部件与之相关联的表单元素。属性值必需是同个文档中的 <form> 元素的 id 属性。理论上,它允许您在 <form> 元素之外设置一个表单小部件。
name
元素的名称;这是跟表单数据一起提交的。
value
元素的初始值

4. HTML5 的输入(input)类型

具体看一看较新的表单控件,包含一些新添加至 HTML 5 的 input 类型,以允许收集更多特定类型的数据。

HTML 表单元素参考,特别是深入的 <input> 类型 参考。

4.1 E-mail 地址字段

将 type 属性设置为 email 就可以使用这种控件:

<input type="email" id="email" name="email" />

任何其他输入都会使得浏览器在表单提交时显示错误信息。

也可以搭配使用 multiple (en-US) 属性,以允许在同一个 email 输入框中输入多个电子邮件地址,以英文逗号分隔:

<input type="email" id="email" name="email" multiple />

备注:你可以在基本 input 例子中找到基本文本 input 类型的例子(也请看看源代码)。

4b159caaf8db776df1ca36851c0343b7.png

<head> <!-- 文档头部,包含文档元数据 -->
    <meta charset="utf-8"> <!-- 定义字符编码为 utf-8 -->
    <meta name="viewport" content="width=device-width"> <!-- 定义视口宽度等于设备宽度 -->
    <title>Basic input types</title> <!-- 定义文档标题 -->
    <style>   <!--内联样式表-->
      html, input {
        font-family: sans-serif; /* 设置 html 和 input 元素的字体族为无衬线字体 */
      }

      body {
        width: 90%; /* 设置 body 元素的宽度为 90% */
        max-width: 500px; /* 设置 body 元素的最大宽度为 500 像素 */
        margin: 0 auto; /* 设置 body 元素的外边距为自动居中 */
      }

      form {
        margin-top: 20px; /* 设置 form 元素的上外边距为 20 像素 */
      }

      div {
        margin-bottom: 20px; /* 设置 div 元素的下外边距为 20 像素 */
        display: flex; /* 设置 div 元素的显示方式为 flex */
        justify-content: space-between; /* 设置 div 元素的子元素水平两端对齐,中间留有空隙 */
        align-items: center; /* 设置 div 元素的子元素垂直居中对齐 */
      }

      label, input, button {
        font-size: 14px; /* 设置 label、input 和 button 元素的字体大小为 14 像素 */
        line-height: 1.5 /* 设置 label、input 和 button 元素的行高为 1.5 */
      }

      label {
        text-align: right; /* 设置 label 元素的文本对齐方式为右对齐 */
        width: 30%; /* 设置 label 元素的宽度为 30% */
        margin-right: 2%; /* 设置 label 元素的右外边距为 2% */
      }

      input {
        flex: auto; /* 设置 input 元素占用剩余空间 */
      }

      button {
        width: 70%; /* 设置 button 元素的宽度为 70% */
        margin: 0 auto; /* 设置 button 元素的外边距为自动居中 */
      }
    </style>
  </head>
  <body> <!-- 文档主体 -->
      <form> <!-- 定义表单 -->
        <div> <!-- 容器 -->
          <label for="text">text input type: </label> <!-- 定义标签,与 id 为 text 的表单控件相关联 -->
          <input type="text" id="text" name="text"> <!-- 文本输入框,id 为 text,name 为 text -->
        </div>
        <div>
          <label for="pwd">password input type: </label> <!-- 定义标签,与 id 为 pwd 的表单控件相关联 -->
          <input type="password" id="pwd" name="pwd"> <!-- 密码输入框,id 为 pwd,name 为 pwd -->
        </div>
        <div>
          <label for="email">email input type: </label> <!-- 定义标签,与 id 为 email 的表单控件相关联 -->
          <input type="email" id="email" name="email"> <!-- 邮箱输入框,id 为 email,name 为 email -->
        </div>
        <div>
          <label for="url">url input type: </label> <!-- 定义标签,与 id 为 url 的表单控件相关联 -->
          <input type="url" id="url" name="url"> <!-- 网址输入框,id 为 url,name 为 url -->
        </div>
        <div>
          <label for="number">number input type: </label> <!-- 定义标签,与 id 为 number 的表单控件相关联 -->
          <input type="number" id="number" name="number"> <!-- 数字输入框,id 为 number,name 为 number -->
        </div>
        <div>
          <label for="tel">tel input type: </label> <!-- 定义标签,与 id 为 tel 的表单控件相关联 -->
          <input type="tel" id="tel" name="tel"> <!-- 电话输入框,id 为 tel,name 为 tel -->
        </div>
        <div>
          <label for="search">search input type: </label> <!-- 定义标签,与 id 为 search 的表单控件相关联 -->
          <input type="search" id="search" name="search"> <!-- 搜索输入框,id 为 search,name 为 search -->
        </div>
        <div>
          <button>Submit</button> <!-- 提交按钮,文本为 Submit -->
        </div>
      </form>
      <script>

      </script>
  </body>

客户端验证
email 与其他较新的 input 类型一样,提供了内置的客户端错误验证,在数据被发送到服务器之前由浏览器执行。

你的应用程序始终应该在服务器端和客户端对任何表单提交的数据进行安全检查,因为客户端验证太容易被关闭了,所以恶意用户仍然可以很容易地将坏数据发送到你的服务器

注意,在默认限制条件下,a@b 也是一个合法的电子邮件地址,因为 email input 类型默认也允许内部网络的电子邮件地址

备注:如果输入的数据不是一个电子邮件地址,会匹配 :invalid 伪类,且 validityState.typeMismatch (en-US) 属性总会返回 true。

4.2 查询字段

查询字段(Search fields)旨在用于在页面和应用程序上创建搜索框。将** type 属性设置为 search** .

<input type="search" id="search" name="search" />

text 字段和 search 字段的主要区别是浏览器赋予它们的外观显示
通常情况下,search 字段拥有圆角边框,有时会显示“?”标志,当点击它时会清除输入框。另外,在动态键盘设备上,键盘的回车键会显示“search”,或显示为放大镜图标。
search 字段的值可以自动地保存下来,在同一网站的自动完成框中复用输入.

4.3 电话号码字段

在 type 属性中使用 tel 值,即可创建一个专门用于输入电话号码的文本域:

<input type="tel" id="tel" name="tel" />

当使用带有动态键盘的移动设备访问带有 type="tel" 的表单时,大多数设备会显示数字键盘。这意味着只要数字键盘有用,这种类型就很有用,而且不只是用于电话号码。

4.4 URL 字段

在 type 属性值中使用 url,即可创建一个用于输入网址的文本字段:

<input type="url" id="url" name="url" />

浏览器会在没有协议(例如 http:)输入或网址格式不对的情况下报告错误。
在具有动态键盘的设备上,键盘通常会显示部分或全部冒号、句号和正斜杠作为默认键。

4.5 数字字段

用于输入数字的控件可以由 type 为 number 的 <input> 元素创建。这个控件外观与文本域类似,但只允许浮点数输入,并通常以旋转器(spinner)的形式提供按钮来增加和减少控件的值。在有动态键盘的设备上,一般会显示数字键盘。
使用 number input 类型,你可以使用 min 和 max 属性控制允许输入的最小值和最大值
使用 step 属性来设定每次按下 spinner 按钮增加或减少的值
默认情况下,number input 类型只允许整数值输入,为了允许浮点数输入,要指定 step="any" (en-US)

创建 可从 1 到 10 之间选择值的数字选择器,且单击一次按钮所增长或减少的值为 2

<input type="number" name="age" id="age" min="1" max="10" step="2" />

创建可从 0 到 1 之间选择值得数字选择器,且单击一次按钮所增长或减少的值为 0.01。

<input type="number" name="change" id="pennies" min="0" max="1" step="0.01" />

当有效值的范围有限时,number 输入类型才有意义,例如一个人的年龄或身高。如果范围太大,渐进式增加没有意义(如范围为 00001 到 99999 的美国 ZIP 码)的话,使用 tel 类型可能会更好;它提供了数字键盘,而放弃了数字输入器的 spinner UI 功能。

4.6 滑块控件

另外一种选择数字的方式是使用滑块(slider)
从使用上来说,滑块的准确性不如文本字段。它们被用来挑选精确值不一定那么重要的数字。
在 \input> 元素中使用 range 作为属性 type 的值,就可以创建一个滑块.
推荐分别配置 min (en-US)、max (en-US) 和 step (en-US) 属性来设置滑块的最小值、最大值和增量值。

63a2cd9c750e38498609dbec2263e699.png

创建一个其取值为 50000 到 500000 之间的滑块,每次的增量值是 100。我们使用 value 属性设定了此滑块的默认值为 250000。

<label for="price">Choose a maximum house price: </label>
<input
  type="range"
  name="price"
  id="price"
  min="50000"
  max="500000"
  step="100"
  value="250000" />
<output class="price-output" for="price"></output>

使用滑块的一个问题是,它们不提供任何种类的视觉反馈来说明当前的值是什么。这是我们附加了一个包含当前值输出的 <output> 元素的原因。

要真正显示当前值,并在其变化时更新,你必须使用 JavaScript:

//我们将 range 输入元素和 output 元素存为了两个变量
const price = document.querySelector("#price");
const output = document.querySelector(".price-output");
//将 output 的 textContent 属性设置为 input 的 value
output.textContent = price.value;
//设置了一个事件监听器,确保每次范围滑块移动时,output 的 textContent 总是可以及时更新为新值。
price.addEventListener("input", () => {
  output.textContent = price.value;
});

4.7 日期和时间选择器

日期和时间控件可由 <input> 元素和一个合适的 type 属性值来创建,该值取决于要收集的类型(日期、时间、还是以上全部)。
这里有一个示例,在浏览器不支持的情况下会自动回退为 <select> 元素:

d9d37e9cfb525f504028fc4f4ffd0c97.png

datetime-local
<input type="datetime-local"> 创建了显示和选择一个没有特定时区信息的日期和时间的控件

<input type="datetime-local" name="datetime" id="datetime" />

month
<input type="month"> 创建了显示和选择带有年份信息的某个月的控件

time
<input type="time"> 创建了显示和选择时间的控件。时间可能会以 12 小时制显示,但一定会以 24 小时制形式返回。

<input type="time" name="time" id="time" />

week
<input type="week"> 创建了显示和选择一年中特定编号周的控件。
一周以周一开始,一直运行到周日结束。另外,每年的第一周总会包含那一年首个星期四,其中可能不包括当年的第一天,也可能包括前一年的最后几天。

<input type="week" name="week" id="week" />

限制日期/时间值
所有的日期和时间控件总可以由 min (en-US) 和 max (en-US) 属性控制,可由 step (en-US) 属性进一步做控制,具体值随着 input 类型的不同而产生变化。

<label for="myDate">When are you available this summer?</label>
<input
  type="date"
  name="myDate"
  min="2013-06-01"
  max="2013-08-31"
  step="7"
  id="myDate" />

4.8 颜色选择器控件

颜色总是有点难处理。有许多方法来表达它们,如 RGB 值(十进制或十六进制)、HSL 值、关键词等。

db9c26223e376f5c1aa35bd8dd69c79d.png

用于输入颜色的控件可以由 type 为 color 的 <input> 元素创建

<input type="color" name="color" id="color" />

返回值总是颜色的小写的 6 位十六进制数表示。

5. 其他表单控件

非 <input> 表单控件的功能,从下拉列表菜单(drop-down list)、多行文本域(multi-line text field) 到其他有用的表单功能,如我们在前一篇文章看到的 <output> 元素和进度条(progress bar) 元素。

5.1 多行文本域

多行文本域使用 <textarea> 元素指定,而不是使用 <input> 元素。

<textarea cols="30" rows="8"></textarea>

<textarea> 也需要关闭标签,其中要包含的默认文字需要放在开闭标签之间。作为对比,<input> 是不包含关闭标签的空元素,它的默认值应该在 value 属性中指定。

注意,即使可以将任何东西放入到 <textarea> 元素中,甚至可以包含其他 HTML 元素、CSS 和 JavaScript,由于该元素的特性,这些内容都将以纯文本的形式渲染。
现代浏览器会提供拖动手柄,你可以通过拖拽来放大或缩小文本区的大小。

控制多行渲染

<textarea> 接受三种属性来控制其多行渲染行为:

  • cols : 指定文本控件的可见宽度(列),单位为字符的(起始)宽度,可以通过调整 <textarea> 的大小来改变,也可以用 CSS 重写。如果没有指定,默认值是 20。

  • rows : 指定文本控件的可见行数。这实际上是起始高度,默认值是 2。

  • wrap : 指定如何控制文本换行。 soft(默认值),意味着提交的文字没有换行,而浏览器中渲染的文字有换行; hard(使用此属性必须指定 cols 的值),意味着提交的文字和浏览器中渲染的文字都有换行;和 off,停止任何换行行为。

控制文本域可缩放性

<textarea> 的缩放能力由 CSS resize 属性控制,其可能的值如下:

  • both:默认值——允许横向和纵向缩放行为。

  • horizontal:只允许横向水平缩放行为。

  • vertical:只允许纵向竖直缩放行为。

  • none:不允许缩放行为。

  • block 和 inline:实验性的值,仅允许以 block 或 inline 方向缩放,如何变化取决于文字的方向,请参阅处理不同文字方向以了解更多内容。

5.2 下拉控件

让用户从许多不同选项中进行选择的控件,不占用用户界面太多空间。
HTML 有两种下拉内容:一种是选择框、另外一种是自动补全框。这两种情况下的交互是相同的——一旦被激活,浏览器就会显示可供用户选择的值的列表。

7296b6b7f8212f382afdf91a72705352.png

<form> <!-- 创建一个表单 -->
    <p> <!-- 创建一个段落 -->
        <label for="simple">A simple select box:</label> <!-- 创建一个标签,用于描述下拉选择框 -->
        <select id="simple" name="simple"> <!-- 创建一个简单的下拉选择框 -->
            <option>Banana</option> <!-- 下拉选择框中的选项 -->
            <option>Cherry</option>
            <option>Lemon</option>
        </select>
    </p>
    <p>
        <label for="groups">Select box with option groups:</label> <!-- 创建一个标签,用于描述带有选项组的下拉选择框 -->
        <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>
    </p>
    <p>
        <label for="multi">Select box allowing multiple selections:</label> <!-- 创建一个标签,用于描述允许多选的下拉选择框 -->
        <select multiple id="multi" name="multi"> <!-- 创建一个允许多选的下拉选择框 -->
            <option>Banana</option> <!-- 下拉选择框中的选项 -->
            <option>Cherry</option>
            <option>Lemon</option>
        </select>
    </p>
    <p>
        <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>
    </p>
    <p>
        <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>
    </p>
    <p>
        <button type="submit">Submit me!</button>  <!-- 提交按钮,用于提交表单数据 -->
    </p>
</form>

选择框
一个简单的选择框是由 <select> 元素及一个或多个 <option> 子元素构成的,每个子元素指定了选择框的可能取值。
基础示例

0730f5fddcf22a8c304c8222053f2f9e.png

<select id="simple" name="simple">
  <option>Banana</option>
  <option selected>Cherry</option>
  <option>Lemon</option>
</select>

如果需要的话,选择框的默认值可以由要指定默认值的 <option> 元素中的 selected 属性设置,这样在页面加载后,该选项可以预先选中。

使用 optgroup
<option> 元素可以嵌套在 <optgroup> 元素中,以在视觉上关联一组取值:(见以上示例)

0ca57257efbf307a9e686f4adbf27c1f.png

在 <optgroup> 元素中,label 属性的值在嵌套选项之前显示。浏览器往往在视觉上将它们与选项分开(如,将其粗体并显示于不同的嵌套级别),以避免它们与实际选项混淆。

使用 value 属性
如果一个 <option> 元素明确设置了 value 属性,当表单提交时也会提交那个选项对应的值。如果像上面的例子那样省略了 value 属性,<option> 元素的内容会作为提交的值。所以 value 属性并不是必需的,然而你可能需要向服务器中发送与视觉所见相比缩短或者改变过的值。
例如:

<select id="simple" name="simple">
  <option value="banana">Big, beautiful yellow banana</option>
  <option value="cherry">Succulent, juicy cherry</option>
  <option value="lemon">Sharp, powerful lemon</option>
</select>

默认情况下,选择框的高度足以显示单个值。可选的 size (en-US) 属性控制在选择框不处于聚焦状态时,可见选项的数量。

多选选择框
通过向 <select> 元素添加 multiple 属性,你可以允许用户使用操作系统提供的机制选择多个值(如按下 Cmd/Ctrl 并先后单击多个值)。

<select id="multi" name="multi" multiple size="2">
  <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>

备注:在多选选择框的情况下,你会注意到选择框不再以下拉内容的形式显示数值——相反,所有的值都会一次性显示在一个列表中,可选的 size (en-US) 属性决定了控件的高度

备注:任何支持 <select> 元素的浏览器也支持 multiple 属性。

自动补全框
可以通过 <datalist> 元素中的一些显示的 <option> 子元素为表单项提供推荐的自动补全值。<datalist> 元素需要指定一个 id。

<input> 元素会使用 list 属性绑定至一个数据列表 (如 text 或 email 输入类型),该属性的取值就是要绑定的数据列表的 id 值

一旦数据列表与表单控件相关联,它的选项就会被用来自动补全用户输入的文本;通常,它以下拉框的形式呈现给用户,列出他们输入内容的可能匹配。
基础示例

3455f70056beb7483bb6de4b638dff6c.png

<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>

Datalist 支持和回退
需要给诸如 IE 10 及以前的旧版浏览器提供支持

8a3e6d5bd752dfa2a87d9922c2daaf14.png

<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>

支持 <datalist> 元素的浏览器会忽略任何非 <option> 元素,而 datalist 仍然会按期工作。不支持 <datalist> 元素的旧浏览器会显示标签和选择框。
不太明显的 datalist 用法
根据 HTML 规范,list 属性和 <datalist> 元素可以与任何需要用户输入的组件配合使用。这可能会导致一些不太显然的用法。
例如,在支持在 <datalist> 上使用 range 输入类型的浏览器中,在每个 datalist 的 <option> 值上会显示一个小勾。你可以在 <input type="range"> 参考页面上看到一种实现。

支持 <datalist> 和 <input type="color"> 的浏览器上应该显示一个自定义颜色调色板作为默认值,同时仍然提供完整的颜色调色板。

5.3 其他表单功能

这是一段HTML代码,它创建了一个表单,其中包含文件上传、隐藏域、图像输入、进度条和仪表元素。

4903c8c9e1553a9f2ed2214113c08c6a.png

<body> <!-- 创建一个body元素 -->
    <form> <!-- 创建一个表单 -->
        <p> <!-- 创建一个段落 -->
            <label for="file">Choose an image to upload</label> <!-- 创建一个标签,用于描述文件上传输入框 -->
            <input type="file" name="file" id="file" accept="image/*" multiple> <!-- 创建一个文件上传输入框,允许上传多个图片文件 -->
        </p>
        <div> <!-- 创建一个div元素 -->
            <input type="hidden" id="timestamp" name="timestamp" value="1286705410"> <!-- 创建一个隐藏域,用于存储时间戳 -->
        </div>
        <p>
            <input type="image" name="pos" alt="Ramsbottom" src="map.png"> <!-- 创建一个图像输入框,用于提交图像坐标 -->
        </p>
        <p>
            <progress max="100" value="75">75/100</progress> <!-- 创建一个进度条,显示当前进度为75% -->
        </p>
        <p>
            <meter min="0" max="100" value="75" low="33" high="66" optimum="50">75</meter> <!-- 创建一个仪表元素,显示当前值为75 -->
        </p>
    </form>
</body>

计量器和进度条
进度条

<progress max="100" value="75">75/100</progress>

这可以实现任何需要进度报告的事情,例如下载文件的百分比,或问卷调查中填写过问题的数量。
<progress> 元素中的内容是供不支持此元素浏览器进行回退,以及给屏幕阅读器提供发音材料的机制。

计量器
计量器代表了一个由 max 和 min 限定范围内的固定值。这个值在视觉上呈现为一个条形.

  • low 和 high 将范围分为了三个部分:

    • 下半部分范围在 min 和 low 值之间,包含端点值。

    • 中间部分范围在 low 和 high 值之间,不包含端点值。

    • 上半部分范围在 high 和 max 值之间,包含端点值。

  • optimum 值定义了 <meter> 元素的最佳值,它与 low 和 high 值一同定义了首选的范围部分:

    • 如果 optimum 在下半部分范围内,下半部分范围被认为是首选部分,中间部分范围被认为是平均部分,而上半部分范围被认为是最差的部分。

    • 如果 optimum 在中间部分范围内,下半部分范围被认为是平均部分,中间部分范围被认为是首选部分,而上半部分范围也被认为是平均部分。

    • 如果 optimum 在上半部分范围内,下半部分范围被认为是最差的部分,中间部分范围被认为是平均部分,而上半部分范围被认为是首选部分。

所有实现了 <meter> 元素的浏览器使用这些值来改变计量器的颜色:

  • 如果当前值位于首选范围,则计量器显示为绿色

  • 如果当前值位于平均范围,则计量器显示为黄色

  • 如果当前值位于最差范围,则计量器显示为红色

<meter> 元素中的内容是供不支持此元素浏览器进行回退,以及给屏幕阅读器提供发音材料的机制。

6. 样式化 HTML 表单

6.1 为什么使用 CSS 美化表单组件这么困难?

有些元素在跨平台上时很少出现问题。包括以下结构元素:<form> <fieldset> <label> <output>.
一些元素难以被美化,并且可能需要一些复杂的技巧,偶尔需要高级的 CSS3 知识。
有些元素根本不能用应用 CSS 样式。这些包括:所有高级用户界面小部件,如范围,颜色或日期控件; 和所有下拉小部件,包括<select>, <option>, <optgroup>和<datalist> 元素。文件选择器小部件也被称为不可样式化。新的<progress>和<meter> 元素也属于这个类别。

6.2 基本样式美化

Search 字段
搜索框是唯一一种应用 CSS 样式有点棘手的文本字段。在基于 WebKit 的浏览器(Chrome,Safari 等)上,您必须使用 -webkit-appearance专有属性 来调整它。
Example

<form>
  <input type="search" />
</form>
input[type="search"] {
  border: 1px dotted #999;
  border-radius: 0;

  -webkit-appearance: none;
}

字体和文本
CSS font 和 text 功能能被很容易的应用到任何组件上。默认情况下,一些组件不会从它们的父元素继承 font-family和 font-size 。

许多浏览器使用系统默认的字体和文本。为了让 form 表单的外观和其他内容保持一致,你可以在你的样式表中增加以下内容:

button,
input,
select,
textarea {
  font-family: inherit;
  font-size: 100%;
}

盒子模型
所有文本字段都完全支持与 CSS 盒模型相关的每个属性 (width, height, padding, margin, 和 border)。
。如果你既想保持小部件的原生外观和感觉,又想给他们一个一致的尺寸,那么你会遇到一些困难.这是因为每个小部件都有自己的边框,填充和边距的规则。
所以如果你想给几个不同的小部件相同的大小,你必须使用box-sizing 属性

input, /* 选择器,选择所有input元素 */
textarea, /* 选择器,选择所有textarea元素 */
select, /* 选择器,选择所有select元素 */
button { /* 选择器,选择所有button元素 */
    width: 150px; /* 定义宽度为150像素 */
    margin: 0; /* 定义外边距为0 */

    -webkit-box-sizing: border-box; /* 为旧版基于WebKit的浏览器定义盒模型 */
    -moz-box-sizing: border-box; /* 为旧版(Firefox <29)基于Gecko的浏览器定义盒模型 */
    box-sizing: border-box; /* 定义盒模型为border-box */
}

定位(Positioning)
HTML 表单部件的定位通常不是问题; 但是,您应该特别注意两点:
legend
<legend>元素易于应用 CSS,除了定位。在 HTML 流中无法改变它的绝对位置,无法让其远离顶部边框。你可以使用 position 属性将其位置设置为绝对或相对。
由于<legend>元素对无障碍非常重要,因为它能被无障碍技术作为每个 fieldset 中的表单元素的标签读出来,它通常与标题配对,并且在无障碍中被隐藏。

<fieldset>
  <legend>Hi!</legend>
  <h1>Hello</h1>
</fieldset>
legend {
  width: 1px;
  height: 1px;
  overflow: hidden;
}

textarea
默认情况下,所有浏览器都认为<textarea> 元素是 inline block,与文本底线对齐。要将内联 (inline-block) 块更改为块 (block),使用display属性非常简单。但是如果你想以 inline 方式使用它,通常改变垂直对齐方式:

textarea {
  vertical-align: top;
}

6.3 示例

我们将构建下面的"明信片" 联系人表单:postcard-start.html

a1233729724594b58082ede6e18c8d98.png

<!-- 这是一个包含所有表单字段的表单元素 -->
<form>
  <!-- 这是一个显示文本“to: Mozilla”的标题元素 -->
  <h1>to: Mozilla</h1>

  <!-- 这是一个包含“from”字段的div元素 -->
  <div id="from">
    <!-- 这是一个显示文本“from:”的标签元素 -->
    <label for="name">from:</label>
    <!-- 这是一个输入元素,类型为“text”,用户可以在其中输入他们的姓名 -->
    <input type="text" id="name" name="user_name">
  </div>

  <!-- 这是一个包含“reply”字段的div元素 -->
  <div id="reply">
    <!-- 这是一个显示文本“reply:”的标签元素 -->
    <label for="mail">reply:</label>
    <!-- 这是一个输入元素,类型为“email”,用户可以在其中输入他们的电子邮件地址 -->
    <input type="email" id="mail" name="user_email">
  </div>

  <!-- 这是一个包含“message”字段的div元素 -->
  <div id="message">
    <!-- 这是一个显示文本“Your message:”的标签元素 -->
    <label for="msg">Your message:</label>
    <!-- 这是一个textarea元素,用户可以在其中输入他们的消息 -->
    <textarea id="msg" name="user_message"></textarea>
  </div>

  <!-- 这是一个包含提交按钮的div元素 -->
  <div class="button">
    <!-- 这是一个按钮元素,类型为“submit”,当点击时将提交表单 -->
    <button type="submit">Send your message</button>
  </div>
</form>

组织你的静态文件
三个额外的静态文件:

  1. 明信片的背景——下载这幅图片,把它和你的 HTML 文件保存在相同目录下。

  2. 打字机字体:源自 fontsquirrel.com 的 "Secret Typewriter“字体——将 TTF 文件下载到和上面相同的文件夹里。

  3. 手绘字体:源自 fontsquirrel.com 的 The "Journal" 字体 —— 将 TTF 文件下载到和上面相同的文件夹里。

对字体做一些处理:

  1. 打开 fontsquirrel 网络字体生成器.

  2. 使用表单,上传你的字体文件并生成一个网络字体包,将这个包下载到你的电脑上。

  3. 解压提供的 zip 文件。

  4. 解压后的文件内容里你会找到两个 .woff 文件和两个.woff2 文件。将这四个文件拷贝到一个叫 fonts 的文件夹里,而 fonts 文件夹位于和上面相同的文件夹里。我们为每种字体使用两个不同的文件以最大限度地保证浏览器兼容性。查看我们的 Web 字体 一文获取更多信息。

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  : 1.3rem sans-serif; /* 定义 body 元素的字体大小和类型 */
  padding : 0.5em; /* 定义 body 元素的内边距 */
  margin  : 0; /* 定义 body 元素的外边距 */
  background : #222; /* 定义 body 元素的背景颜色 */
}
form {
  /* 设置表单定位为相对定位 */
  position: relative;
  /* 设置表单宽度为740px */
  width: 740px;
  /* 设置表单高度为498px */
  height: 498px;
  /* 设置外边距上下左右为0,实现水平居中 */  
  margin: 0 auto;
  /* 设置内边距为1em */
  padding: 1em;
  /* 设置盒子模型为border-box */
  box-sizing: border-box;
  /* 设置背景颜色及背景图片 */
  background: #FFF url(background.jpg);
  /* 使用CSS Grid网格布局 */  
  display: grid;
  /* 设置列间距和行间距为20px */
  gap: 20px;
  /* 定义2列,每列1个弹性单位 */
  grid-template-columns: repeat(2, 1fr); 
  /* 定义4行,设置各行高度 */
  grid-template-rows: 10em 1em 1em 1em;
}
/* 设置标题字体和对齐方式 */
h1 {
  font: 1em "typewriter", monospace;
  align-self: end;
}

/* 设置 message 区域在网格的位置 */ 
#message {
  grid-row: 1 / 5; 
}

/* 设置flex布局 */
#from, #reply {
  display: flex; 
}

/* 设置 label 的字体 */
label {
  font: .8em "typewriter", sans-serif;
}
/* 设置输入框和文本域的字体 */
input,textarea {
  font: 1.4em/1.5em "handwriting", cursive, sans-serif;
  /* 去除边框 */  
  border: none;
  /* 设置内边距 */
  padding: 0 10px;  
  /* 去除外边距 */
  margin: 0;
  /* 设置宽度为80% */
  width: 80%;
  /* 去除背景 */
  background: none;
}

/* 获得焦点时的样式 */
input:focus,textarea:focus {
  background: rgba(0,0,0,.1);
  border-radius: 5px;
  outline: none;//移除由某些浏览器添加的默认高亮效果:
}

/* 设置文本域为块级元素 */
textarea {
  display: block;
  /* 设置内边距 */  
  padding: 10px;
  /* 设置外边距 */
  margin: 10px 0 0 -10px;  
  /* 设置宽度为100% */
  width: 100%;
  /* 设置高度为90% */ 
  height: 90%;
  /* 显示右边框 */
  border-right: 1px solid; 
  resize: none;/*/*防止用户调整我们的多行文本域的大小*/
  /* 溢出隐藏 */
  overflow: auto; 
}

/* 设置按钮内边距 */
button {
  padding: 5px;
  /* 设置文字样式 */
  font: bold .6em sans-serif;  
  /* 设置边框 */
  border: 2px solid #333;
  /* 设置圆角 */
  border-radius: 5px;
  /* 去除背景 */
  background: none;
  /* 设置鼠标手势 */
  cursor: pointer;
  /* 设置旋转 */
  transform: rotate(-1.5deg); 
}

/* 设置按钮伪元素内容 */
button:after {
  content: " >>>";
}

/* 设置按钮态样式 */  
button:hover,button:focus {
  outline: none;
  background: #000;
  color: #FFF;
}

备注: 如果你的例子没有像你预期的那样工作,你想将它同我们的版本检查对比,你可以在 Github 上找到它 —— 查看在线演示.
若我们想构建只包含文本域和按钮的表单,用 CSS 美化它们非常容易。        

7. 高级设计 HTML 表单(英文)

HTML表单怎样使用CSS装饰难以定制的表单小部件。如前面章节 (en-US)所示,文本字段和按钮非常容易设置样式; 设置更难样式化的表单控件类型-“坏”和“丑陋”类别.Advanced form styling

The bad: 有些元素更难设置样式,需要更复杂的CSS或一些更具体的技巧:

  • Checkboxes and radio buttons
    复选框和单选按钮

  • <input type="search"> 搜索框

The ugly: 某些元素无法使用CSS彻底设置样式。

  • 下拉部件,包括<select> 、 <option> <optgroup> 和 <datalist> 。

  • <input type="color"> 颜色控件

  • 与日期相关的控件,例如 <input type="datetime-local">

  • <input type="range">

  • <input type="file">

  • <progress> 和 <meter>

7.1 外观:控制操作系统级样式

创建该 appearance 属性是为了控制将哪些操作系统或系统级样式应用于 Web 窗体控件。
最有用的值(也可能是唯一一个您将使用的值)是 none 会尽可能阻止应用它的任何控件使用系统级样式,并允许您使用 CSS 自行构建样式。

应用以下 CSS 会删除系统级样式。

input {
  appearance: none;
}

下面的实时示例向您展示了它们在您的系统中的外观 — 左侧默认,右侧应用了上述 CSS

10923beb4cddf9e4f3d00a3402d0eba9.png

body {
  margin: 20px auto; /* 设置顶部和底部边距为20px,并使body水平居中 */
  max-width: 800px; /* 设置body的最大宽度为800px */
  justify-content: space-around; /* 沿主轴均匀分布项目 */
}

body, form > div {
  display: flex; /* 将body和form的直接子div元素的display属性设置为flex */
}

form > div {
  margin-bottom: 20px; /* 设置form的直接子div元素的底部边距为20px */
}

.appearance input {
  appearance: none; /* 移除类名为"appearance"的元素内input元素的默认外观 */
}
<div>
    <form>
      <div>
        <label for="search1">search: </label>
        <input id="search1" name="search1" type="search">
      </div>
      <div>
        <label for="text1">text: </label>
        <input id="text1" name="text1" type="text">
      </div>
      <div>
        <label for="date1">date: </label>
        <input id="date1" name="date1" type="datetime-local">
      </div>
      <div>
        <label for="radio1">radio: </label>
        <input id="radio1" name="radio1" type="radio">
      </div>
      <div>
        <label for="checkbox1">checkbox: </label>
        <input id="checkbox1" name="checkbox1" type="checkbox">
      </div>
      <div><input type="submit" value="submit"></div>
      <div><input type="button" value="button"></div>
    </form>
  </div>
  <div class="appearance">
    <form>
      <div>
        <label for="search2">search: </label>
        <input id="search2" name="search2" type="search">
      </div>
      <div>
        <label for="text2">text: </label>
        <input id="text2" name="text2" type="text">
      </div>
      <div>
        <label for="date2">date: </label>
        <input id="date2" name="date2" type="datetime-local">
      </div>
      <div>
        <label for="radio2">radio: </label>
        <input id="radio2" name="radio2" type="radio">
      </div>
      <div>
        <label for="checkbox2">checkbox: </label>
        <input id="checkbox2" name="checkbox2" type="checkbox">
      </div>
      <div><input type="submit" value="submit"></div>
      <div><input type="button" value="button"></div>
    </form>
  </div>

在大多数情况下,效果是删除风格化的边框,这使得CSS样式更容易一些.

Taming search boxes 驯服搜索框
禁用默认外观:

7d61538629285dd205fdc08ff737341b.png

input[type="search"] {
  appearance: none;
}

设置复选框和单选按钮的样式
考虑以下简单的测试用例:

baba4a1a16b506ede339e37385f64e37.png

<label
  ><span><input type="checkbox" name="q5" value="true" /></span> True</label
>
<label
  ><span><input type="checkbox" name="q5" value="false" /></span> False</label
>
span {
  display: inline-block;
  background: red;
}

input[type="checkbox"] {
  width: 100px;
  height: 100px;
}

不同的浏览器处理复选框并跨越不同的方式,通常是丑陋的:

使用外观:none on radios/checkboxes 单选按钮和复选框none

以下示例 HTML 使用appearance :none 完全删除复选框或单选按钮 的默认外观:

<form>
  <fieldset>
    <legend>Fruit preferences</legend>

    <p>
      <label>
        <input type="checkbox" name="fruit" value="cherry" />
        I like cherry
      </label>
    </p>
    <p>
      <label>
        <input type="checkbox" name="fruit" value="banana" disabled />
        I can't like banana
      </label>
    </p>
    <p>
      <label>
        <input type="checkbox" name="fruit" value="strawberry" />
        I like strawberry
      </label>
    </p>
  </fieldset>
</form>
input[type="checkbox"] {
  appearance: none;/*取消原始复选框的样式*/
}

我们可以使用 and :checked :disabled 伪类在自定义复选框的状态更改时更改其外观

84de2adb737259e00f8e285140598714.png

input[type="checkbox"] {
  position: relative; /* 设置相对定位 */
  width: 1em; /* 设置宽度为1em */
  height: 1em; /* 设置高度为1em */
  border: 1px solid gray; /* 设置边框为1px实线灰色 */
  /* 调整复选框在文本基线上的位置 */
  vertical-align: -2px;
  /* 在此处设置,以便Windows的高对比度模式可以覆盖 */
  color: green;
}

input[type="checkbox"]::before {
  content: "?"; /* 设置内容为"?" */
  position: absolute; /* 设置绝对定位 */
  font-size: 1.2em; /* 设置字体大小为1.2em */
  right: -1px; /* 设置右边距为-1px */
  top: -0.3em; /* 设置顶部边距为-0.3em */
  visibility: hidden; /* 设置不可见 */
}

input[type="checkbox"]:checked::before {
  /* 使用`visibility`而不是`display`以避免重新计算布局 */
  visibility: visible; /* 当复选框被选中时设置可见 */
}

input[type="checkbox"]:disabled {
  border-color: black; /* 当复选框被禁用时设置边框颜色为黑色 */
  background: #ddd; /* 设置背景颜色为#ddd */
  color: gray; /* 设置颜色为灰色 */
}

:checked — 复选框(或单选按钮)处于选中状态 — 用户已单击/激活它。
:disabled — 复选框(或单选按钮)处于禁用状态 — 无法与之交互。

样式化的单选按钮:自定义单选按钮样式。

切换开关示例:样式类似于切换开关的复选框。

如果您在不支持 appearance 的浏览器中查看这些复选框,您的自定义设计将丢失,但它们仍将看起来像复选框并且可用。

7.2 对于“丑陋”"ugly"元素,我们能做些什么?

“丑陋”的控件 - 那些很难彻底设置样式的控件
简而言之,这些是下拉框、复杂的控件类型(如 和 )以及面向反馈的控件(如 color <progress> 和 <meter> datetime-local )。

以以下示例为例,该示例显示了运行中的许多“丑陋”表单功能:

19109de74a5afa44e0ed5b1f39abfc44.png

body {
  font-family: "Josefin Sans", sans-serif; /* 设置字体为"Josefin Sans" */
  margin: 20px auto; /* 设置顶部和底部边距为20px,并使body水平居中 */
  max-width: 400px; /* 设置body的最大宽度为400px */
}

form > div {
  margin-bottom: 20px; /* 设置form的直接子div元素的底部边距为20px */
}

select {
  appearance: none; /* 移除默认外观 */
  width: 100%; /* 设置宽度为100% */
  height: 100%; /* 设置高度为100% */
}

.select-wrapper {
  position: relative; /* 设置相对定位 */
}

.select-wrapper::after {
  content: "▼"; /* 设置内容为"▼" */
  font-size: 1rem; /* 设置字体大小为1rem */
  top: 3px; /* 设置顶部边距为3px */
  right: 10px; /* 设置右边距为10px */
  position: absolute; /* 设置绝对定位 */
}

button,
label,
input,
select,
progress,
meter {
  display: block; /* 设置display属性为block */
  font-family: inherit; /* 继承父元素的字体 */
  font-size: 100%; /* 设置字体大小为100% */
  margin: 0; /* 设置边距为0 */
  box-sizing: border-box; /* 设置盒模型为border-box */
  width: 100%; /* 设置宽度为100% */
  padding: 5px; /* 设置内边距为5px */
  height: 30px; /* 设置高度为30px */
}

input[type="text"],
input[type="datetime-local"],
input[type="color"],
select {
  box-shadow: inset 1px 1px 3px #ccc; /* 添加内阴影效果 */
  border-radius: 5px; /* 添加圆角效果 */
}

label {
  margin-bottom: 5px; /* 设置底部边距为5px */
}

button {
  width: 60%; /* 设置宽度为60% */
  margin: 0 auto; /* 水平居中按钮 */
}
<form>
  <div>
    <label for="select">Select box:</label>
    <div class="select-wrapper">
      <select id="select" name="select">
        <option>Banana</option> <!-- 下拉选项 -->
        <option>Cherry</option>
        <option>Lemon</option>
      </select>
    </div>
  </div>
  <div>
    <label for="myFruit">"Favorite fruit?" datalist:</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>
  </div>
  <div>
    <label for="date1">Datetime local: </label> <!-- 日期时间输入框 -->
    <input id="date1" name="date1" type="datetime-local">
  </div>
  <div>
    <label for="range">Range: </label> <!-- 范围输入框 -->
    <input id="range" name="range" type="range">
  </div>
  <div>
    <label for="color">Color: </label> <!-- 颜色选择器 -->
    <input id="color" name="color" type="color">
  </div>
  <div>
    <label for="file">File picker: </label> <!-- 文件选择器 -->
    <input id="file" name="file" type="file" multiple> 
    <ul id="file-list">

    </ul>
  </div>
  <div>
    <label for="progress">Progress: </label> <!-- 进度条 -->
    <progress max="100" value="75" id="progress">75/100</progress> 
  </div>
  <div>
    <label for="meter">Meter: </label> <!-- 计量器 -->
    <meter id="meter" min="0" max="100" value="75" low="33" high "66" optimum "50">75</meter> 
  </div>
  <div><button>Submit?</button></div> <!-- 提交按钮 -->
</form>
const fileInput = document.querySelector('#file'); // 获取文件输入元素
const fileList = document.querySelector('#file-list'); // 获取文件列表元素

fileInput.addEventListener('change', updateFileList); // 为文件输入元素添加change事件监听器

function updateFileList() {
  while(fileList.firstChild) {
    fileList.removeChild(fileList.firstChild); // 移除文件列表中的所有子元素
  }

  let curFiles = fileInput.files; // 获取当前选择的文件

  if(!(curFiles.length === 0))  { // 如果选择了文件
    for(let i = 0; i < curFiles.length; i++) { // 遍历选择的文件
      const listItem = document.createElement('li'); // 创建列表项元素
      listItem.textContent = 'File name: ' + curFiles[i].name + '; file size ' + returnFileSize(curFiles[i].size) + '.'; // 设置列表项文本内容
      fileList.appendChild(listItem); // 将列表项添加到文件列表中
    }
  }
}

function returnFileSize(number) { // 定义函数,用于返回文件大小的字符串表示
  if(number < 1024) {
    return number + 'bytes'; // 如果小于1024字节,返回字节数
  } else if(number >= 1024 && number < 1048576) {
    return (number/1024).toFixed(1) + 'KB'; // 如果大于等于1024字节且小于1048576字节,返回KB数
  } else if(number >= 1048576) {
    return (number/1048576).toFixed(1) + 'MB'; // 如果大于等于1048576字节,返回MB数
  }
}

虽然在HTML表单中使用CSS仍然存在困难,但有一些方法可以解决许多问题。没有干净、通用的解决方案,但现代浏览器提供了新的可能性。目前,最好的解决方案是详细了解不同浏览器在应用于 HTML 表单控件时支持 CSS 的方式。

The End

猜你喜欢

转载自blog.csdn.net/cxyhjl/article/details/132033711
今日推荐