挑战:构建一个反馈表单

在此挑战中,我们将测试您创建和构建表单的能力,以及在表单中添加其他 HTML 功能。

起始点

要解决此挑战,我们希望您创建一个基本的网站项目,可以在您电脑硬盘的文件夹中创建,或者使用像 CodePenJSFiddle 这样的在线编辑器。此页面上提供的代码已经包含了您所需的大部分代码。

  1. 在您电脑的合适位置创建一个名为 forms-challenge 的新文件夹(或打开一个在线编辑器并按照所需步骤创建新项目)。

  2. 将以下 HTML 代码保存在您文件夹中的一个名为 index.html 的文件中(或将其粘贴到在线编辑器的 HTML 面板中)。

    html
    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Forms challenge</title>
        <link href="style.css" rel="stylesheet" />
        <script defer src="index.js"></script>
      </head>
      <body>
        We want your feedback!
    
        We're very excited that you visited the little house in the woods,
        and we want to hear what you thought of it! Please fill in the below
        sections. You don't need to provide your name or contact details, but
        if you do, we'll enter you into a prize draw where you'll have a chance
        to win prizes.
    
        --
    
        Facilities
    
        Was the porridge
        Too hot?
        Too cold?
        Just right?
    
        Were the beds
        Too hard?
        Too soft?
        Just right?
    
        Describe the chairs (select all you agree with)
        Comfy
        Luxurious
        Hi tec
        Pretty
        Majestic
    
        --
    
        About your hosts
    
        Who's your favorite bear?
        Papa bear
        Mama bear
        Junior
        Dozer
    
        Which greeting did you prefer?
        Wave
        Friendly greeting
        Growl
        Claw marks in the door
    
        --
    
        Any other feedback?
    
        Give us your comments
    
        --
    
        Your details
    
        Name
        Email
        Phone
    
        --
    
        Submit
    
        --
      </body>
    </html>
    
  3. 将以下 CSS 代码保存在您文件夹中的一个名为 style.css 的文件中(或将其粘贴到在线编辑器的 CSS 面板中)。

    css
    /* Basic font styles */
    
    body {
      background-color: white;
      color: #333333;
      font: 1em / 1.4 system-ui;
      padding: 1em;
      width: 800px;
      margin: 0 auto;
    }
    
    h1 {
      font-size: 2rem;
    }
    
    h2 {
      font-size: 1.6rem;
    }
    
    h1,
    h2 {
      margin: 0 0 20px;
      color: purple;
    }
    
    * {
      box-sizing: border-box;
    }
    
    p {
      color: gray;
      margin: 0.5em 0;
    }
    
    /* Form structure */
    
    fieldset {
      border: 0;
      padding: 0;
    }
    
    legend {
      padding-bottom: 10px;
      font-weight: bold;
    }
    
    fieldset,
    .separator {
      margin-bottom: 20px;
    }
    
    .form-section {
      margin-bottom: 20px;
      padding: 20px;
    }
    
    img {
      max-width: 100%;
      height: 50px;
      margin: 20px 0;
    }
    
    /* Individual form items */
    
    fieldset input {
      margin: 0 10px 0 0;
    }
    
    label {
      margin-right: 40px;
    }
    
    textarea {
      margin-top: 10px;
      padding: 5px;
      width: 100%;
      height: 200px;
    }
    
    .separator {
      display: flex;
    }
    
    .separator label {
      flex: 2;
    }
    
    .separator input,
    .separator select {
      flex: 3;
      padding: 5px;
    }
    
    button {
      padding: 10px 20px;
      border-radius: 10px;
      border: 1px solid grey;
      background-color: #dddddd;
      width: 50%;
      margin: 0 auto;
      display: block;
    }
    
    button:hover,
    button:focus {
      background-color: #eeeeee;
      cursor: pointer;
    }
    

项目简介

我们希望您想象一下,您刚刚在一家名为“林中小屋”的酒店(至少您认为那是一家酒店)住过。我们希望您帮助我们为这家酒店创建一个虚构的反馈表单。除了标记所需的要素和构建表单之外,还有一些额外的 HTML 功能我们希望您实现。

实现表单控件

  1. 在“设施”部分,我们希望您将前两组线条转换为单选按钮组,每个按钮都有一个描述它们的标签,以及一个描述整个组的图例。在每种情况下,添加一个属性使第一个单选按钮默认被选中。
  2. 在“设施”部分,将第三组线条转换为复选框组,每个复选框都有一个描述它们的标签,以及一个描述整个组的图例。
  3. 在“关于您的主人”部分,将两组线条都转换为下拉选项菜单,每个选项都有一个描述它们的标签。
  4. 在“其他反馈?”部分,添加一个多行文本输入框,并将现有的一行文本转换为其描述性标签。
  5. 在“您的详细信息”部分,为每三个列出的值添加一个合适的文本输入类型来收集。将现有行转换为它们的标签。
  6. 将“提交”转换为表单的提交按钮。

构建表单

  1. 将表单包装在一个合适的包装器元素中,以指定整个内容为一个表单。
  2. 在表单内部添加重复的结构元素,以包装每个表单部分。给每个表单部分元素添加一个 class,名为 form-section。为了方便起见,每个表单部分都用两组双连字符 (--) 包围。添加结构元素后,您可以删除双连字符。
  3. 您需要为一些控件/标签对添加额外的结构元素,使它们单独占一行。现在添加它们,给每个元素添加一个 class,名为 separator
  4. 在多行文本输入框和它的标签之间添加一个换行符元素,使两者单独占一行。

附加的 HTML 功能

  1. 文本中有几个标题需要使用合适的元素进行标记。
    1. 顶级标题:“我们希望得到您的反馈!”。
    2. 二级标题:“设施”、“关于您的主人”、“其他反馈?”和“您的详细信息”。
  2. 顶级标题下的开头段落需要被适当地标记。
  3. 同样在开头段落中,将文本“林中小屋”和“抽奖”转换为链接。我们还没有要链接到的页面,所以目前,只需将目标 URL 设置为 # 作为占位符。
  4. 我们希望您在开头段落下方放置一个宽而扁平的图像作为装饰。图像路径是 https://mdn.github.io/shared-assets/images/examples/learn/woodland-strip.jpg,我们希望您为它设置一个空的替代文本,因为它仅用于装饰。
  5. 接续上一点,作为一项扩展目标,研究一种更好的方法来在页面上包含装饰性图像,并尝试这样做(这涉及到一种我们在此模块中尚未接触过的与 HTML 不同的技术)。

提示和技巧

  • 使用 W3C HTML 验证器来捕获您 HTML 中无意的错误 — 这样您就可以修复它们。
  • 如果您卡住了,并且无法设想应该在何处放置哪些元素,请画出页面布局的简单框图,并在您认为应该包含每个块的元素上写字。这非常有帮助。

示例

以下截图展示了标记后的表单可能的样子。如果您在如何实现这些功能方面遇到困难,请参阅实时示例下方的解决方案。

The finished example for the challenge; a feedback form showing two sets of radio buttons, a set of checkboxes, and two drop-down select menus

点击此处显示解决方案

您完成的 HTML 应该看起来像这样

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Forms challenge</title>
    <link href="style.css" rel="stylesheet" />
    <script defer src="index.js"></script>
  </head>
  <body>
    <h1>We want your feedback!</h1>

    <p>
      We're very excited that you visited the
      <a href="#">little house in the woods</a>, and we want to hear what you
      thought of it! Please fill in the below sections. You don't need to
      provide your name or contact details, but if you do, we'll enter you into
      a <a href="#">prize draw</a> where you'll have a chance to win prizes.
    </p>

    <img
      src="https://mdn.github.io/shared-assets/images/examples/learn/woodland-strip.jpg"
      alt="" />

    <form>
      <div class="form-section">
        <h2>Facilities</h2>

        <fieldset>
          <legend>Was the porridge</legend>
          <input
            type="radio"
            id="porridge-1"
            name="porridge"
            value="hot"
            checked /><label for="porridge-1">Too hot?</label>
          <input
            type="radio"
            id="porridge-2"
            name="porridge"
            value="cold" /><label for="porridge-2">Too cold?</label>
          <input
            type="radio"
            id="porridge-3"
            name="porridge"
            value="right" /><label for="porridge-3">Just right?</label>
        </fieldset>

        <fieldset>
          <legend>Were the beds</legend>
          <input
            type="radio"
            id="beds-1"
            name="beds"
            value="hard"
            checked /><label for="beds-1">Too hard?</label>
          <input type="radio" id="beds-2" name="beds" value="soft" /><label
            for="beds-2"
            >Too soft?</label
          >
          <input type="radio" id="beds-3" name="beds" value="right" /><label
            for="beds-3"
            >Just right?</label
          >
        </fieldset>

        <fieldset>
          <legend>Describe the chairs (select all you agree with)</legend>
          <input type="checkbox" id="comfy" name="comfy" /><label for="comfy"
            >Comfy</label
          >
          <input type="checkbox" id="luxurious" name="luxurious" /><label
            for="luxurious"
            >Luxurious</label
          >
          <input type="checkbox" id="hi-tech" name="hi-tech" /><label
            for="hi-tech"
            >Hi-tech</label
          >
          <input type="checkbox" id="pretty" name="pretty" /><label for="pretty"
            >Pretty</label
          >
          <input type="checkbox" id="majestic" name="majestic" /><label
            for="majestic"
            >Majestic</label
          >
        </fieldset>
      </div>

      <div class="form-section">
        <h2>About your hosts</h2>

        <div class="separator">
          <label for="favorite">Who's your favorite bear?</label>
          <select name="favorite" id="favorite">
            <option value="papa">Papa bear</option>
            <option value="mama">Mama bear</option>
            <option value="junior">Junior</option>
            <option value="randy">Cousin Randy</option>
          </select>
        </div>

        <div class="separator">
          <label for="greeting">Which greeting did you prefer?</label>
          <select name="greeting" id="greeting">
            <option value="papa">Wave</option>
            <option value="mama">Friendly greeting</option>
            <option value="junior">Growl</option>
            <option value="randy">Claw marks in the door</option>
          </select>
        </div>
      </div>

      <div class="form-section">
        <h2>Any other feedback?</h2>

        <label for="comments">Give us your comments</label>
        <br />
        <textarea id="comments" name="comments"></textarea>
      </div>

      <div class="form-section">
        <h2>Your details</h2>

        <div class="separator">
          <label for="name">Name</label>
          <input type="text" id="name" name="name" />
        </div>

        <div class="separator">
          <label for="email">Email</label>
          <input type="email" id="email" name="email" />
        </div>

        <div class="separator">
          <label for="phone">Phone</label>
          <input type="tel" id="phone" name="phone" />
        </div>
      </div>

      <div class="form-section">
        <button>Submit</button>
      </div>
    </form>
  </body>
</html>

对于扩展目标,在页面上添加装饰性图像的更好方法是使用 CSS 背景图像。删除 <img> 元素,而是使用 CSS 的 background 属性将图像放置在页面上。一个放置背景图像的好元素是 <form> 元素,您需要告诉浏览器不要重复该图像。您还需要提供一些 marginpadding 来分隔背景图像,以免它与文本重叠。

css
form {
  background: url("https://mdn.github.io/shared-assets/images/examples/learn/woodland-strip.jpg")
    no-repeat;
  margin-top: 20px;
  padding-top: 50px;
}